/* NewZAP : main body - DJH */ #include #include #include #define FAILAT 100 /* exit code if problems */ extern struct Menu menu[3]; extern struct Gadget gadget[11]; extern struct StringInfo ginfo; extern struct Image GotoImage; extern struct TextFont ThinFont; extern struct Window *pwindow; extern struct Requester arequest,brequest; extern UWORD BusySprite[]; extern UBYTE filespec[],searchbuf[]; extern fontinit(),OpenBackDrop(),CloseBackDrop(), InitHelpRequester(),FreeRequester(), InitSearchRequester(),FreeSearchRequester(), FakeRequester(),Beep(); /* GLOBALS */ UBYTE title[] = "NewZAP 3.0 : (c) 1986 John Hodgson"; /* Allow user to modify defaults with NewZAP : simply look for PRECUE/POSTCUE strings and ZAP the bytes in the middle! */ #define PREAMBLE "PENCOLORS= " #define PRELEN (sizeof(PREAMBLE)-1) /* exclude \0 */ #define POSTAMBLE " [default=01213]" /* this works because AZTEC C supports string merging */ #define BGPEN "0" /* background color */ #define STDPEN "3" /* information rendering (ex: cursor pos) */ #define HEXPEN "2" /* hex window text */ #define MODPEN "1" /* hex modify highlight */ #define SEARCHPEN "3" /* search highlight */ /* sorry, AZTEC won't merge DEFINE'd strings. Preprocess the following string by hand as if it was : PenBlock[] = PREAMBLE BGPEN STDPEN HEXPEN MODPEN SEARCHPEN POSTABLE */ char PenBlock[] = "PENCOLORS= 03213 [default=03213]"; /* (ecch) */ struct PenCache { long BgPen,StdPen,HexPen,ModPen,SearchPen; } PenCache; long prevx=0,prevy=0,prevasc=0,Read(),Seek(); /* global hex/asc cursor pos */ short cursec,endsec,eof,idnum,searchflag, direction=1, /* search fwd by default */ caps=1, /* LC = UC for searches */ digitcount=0; /* kybd buf cnt */ char goodfile[50], /* last successful filespec */ secbuf[16][32], /* 512-byte sector buffer */ hilite[16][32]; /* corresponding hilite map */ struct StringInfo prevgoto; struct Gadget *gadgetptr; struct TextFont *topaz,*thin,*OpenFont(),*OpenDiskFont(); struct FileHandle *file,*Open(); void *IntuitionBase,*GfxBase,*DiskfontBase; /* ------- */ struct TextFont *LoadFont(name,height) UBYTE *name; short height; { struct TextAttr newfont; newfont.ta_Name=name; newfont.ta_YSize=height; newfont.ta_Style=FS_NORMAL; newfont.ta_Flags=FPB_ROMFONT|FPB_DISKFONT; /* OpenDiskFont will load in the romfonts as well, but it searches the fonts: directory first. Slow! */ if (!strcmp(name,"topaz.font")) return(OpenFont(&newfont)); else return(OpenDiskFont(&newfont)); } edit_window(inkey) short inkey; { char hexbuf[2],accumulator; short i,c; /* not char for -1 checks */ if (prevasc==0) return(0); /* back if no cursor undefined */ if ((c=fetch_input(inkey))==-1) return(0); /* back if dud */ accumulator=c; hexconv(&hexbuf[0],accumulator); /* binary to HEX */ erase_cursors(); SetFont(pwindow->RPort,thin); /* hex window font */ SetAPen(pwindow->RPort,PenCache.ModPen); /* modify hilight */ prstr(pwindow,(short)prevx,(short)prevy+7,&hexbuf[0],2); /* print digits */ prstr(pwindow,(short)prevasc,(short)prevy+7,&accumulator,1); /* print char */ SetFont(pwindow->RPort,topaz); i=roundup(&prevx,&prevy,&prevasc); /* compute x-index */ secbuf[((prevy-26)/8)][i]=accumulator; /* & update buffer */ bump_cursors(); refresh_position(0); draw_cursors(); } fetch_input(inkey) short inkey; { static unsigned char accumulator=0; if (idnum==2) { /* ASC mode? */ digitcount=0; /* reset accumulated chars */ return((int)inkey); /* and return */ } /* HEX input processing starts here */ if (!isalnum(inkey)) { /* invalid char? */ digitcount=0; /* reset digit tabulators */ return(-1); } inkey=toupper(inkey); /* fold to uppercase */ if (inkey>'F') { digitcount=0; return(-1); } if (inkey<='9') inkey-='0'; else inkey-=55; /* fold to binary */ if (digitcount==0) accumulator=0; /* 1st pass? zero accumulator */ accumulator=(accumulator<<4)+inkey; /* shift & add */ if (++digitcount==1) return(-1); /* back if only 1 digit stored */ digitcount=0; /* prepare for fresh pass */ return((int)accumulator); /* return accumulated hex digit */ } bump_cursors() { short i; long hexx,hexy,asc; hexx=prevx+18; /* largest skip used by any HEX pair */ hexy=prevy; asc=prevasc; if (hexx>422+11) { hexx=0; hexy+=8; } /* line wrap */ if (hexy>146) hexy=0; /* page wrap */ i=roundup(&hexx,&hexy,&asc); /* remap & compute x-index */ /* don't bump past EOF */ if ((cursec==endsec) && ((hexy-26)/8)*32+i >= eof) { Beep(); return(0); } prevx=hexx; prevy=hexy; prevasc=asc; /* ok? update! */ } refresh_position(mode) short mode; /* mode==1 FORCES refresh of hex/asc window ONLY */ { short i,curpos; char charbuf[3]; if (!(prevasc|mode)) { /* cursor undefined? */ prstr(pwindow,605,18," ",-1); /* erase "cursor pos : " argument */ prstr(pwindow,605,174," ",-1); /* erase "Edit mode : " argument */ return(0); } SetAPen(pwindow->RPort,PenCache.StdPen); if (mode==0) { i=roundup(&prevx,&prevy,&prevasc); /* compute x-index */ curpos=((prevy-26)/8)*32+i; /* update cursor pos */ if (curpos & 0x100) charbuf[0]='1'; else charbuf[0]='0'; hexconv(&charbuf[1],curpos); prstr(pwindow,605,18,&charbuf[0],3); } if (idnum==1) prstr(pwindow,605,174,"HEX",-1); else prstr(pwindow,605,174,"ASC",-1); /* see below */ } display_record() { short ctr,x,y,flag=0; register short i; char linebuf[80],hibuf[80]; SetFont(pwindow->RPort,thin); /* fill last record w/dummy chars past EOF */ if (cursec==endsec) for (ctr=512;ctr>eof;ctr--) secbuf[0][ctr-1]='#'; searchflag=0; /* assume no hilighting displayed */ for (y=0;y<16;y++) { ctr=flag=0; setmem(&hibuf[0],80,0); /* clear working line hilite buffer */ for (x=0;x<32;x++) { hexconv(&linebuf[ctr],secbuf[y][x]); if (hilite[y][x]) searchflag=flag=hibuf[ctr]=hibuf[ctr+1]=1; ctr+=2; if ((x+1)%4==0) linebuf[ctr++]=' '; /* don't hilite HEX gaps */ } if (flag) { /* take highlighting into account */ Move(pwindow->RPort,8L,y*8+33L); for (i=0;i<71;i++) { /* HEX side w/hilite */ if (hibuf[i]) SetAPen(pwindow->RPort,PenCache.SearchPen); else SetAPen(pwindow->RPort,PenCache.HexPen); Text(pwindow->RPort,&linebuf[i],1L); } Move(pwindow->RPort,441L,y*8+33L); for (i=0;i<32;i++) { /* ASCii side w/hilite */ if (hilite[y][i]) SetAPen(pwindow->RPort,PenCache.SearchPen); else SetAPen(pwindow->RPort,PenCache.HexPen); Text(pwindow->RPort,&secbuf[y][i],1L); } } else { /* no hilighting? fast display! */ SetAPen(pwindow->RPort,PenCache.HexPen); prstr(pwindow,8,y*8+33,&linebuf[0],71); prstr(pwindow,441,y*8+33,&secbuf[y][0],32); } } /* line loop */ setmem(&hilite[0][0],512,0); /* erase hilite buffer */ SetFont(pwindow->RPort,topaz); /* back to normal */ prevx=prevy=prevasc=0; /* undefine cursors; written over! */ } BorderInfo() { char charbuf[20]; SetAPen(pwindow->RPort,PenCache.StdPen); refresh_position(0); sprintf(&charbuf[0],"%d ",cursec); /* "Current Sector : " */ prstr(pwindow,141,166,&charbuf[0],-1); /* "End of File : " (can't shrink - no trailing spcs req'd) */ sprintf(&charbuf[0],"%d",eof); prstr(pwindow,605,166,&charbuf[0],-1); sprintf(&charbuf[0],"%d ",endsec); /* "Ending Sector : " */ prstr(pwindow,141,174,&charbuf[0],-1); } prstr(window,x,y,string,len) /* print-at routine; len=-1 for autosizing */ struct Window *window; short x,y,len; char *string; { Move(window->RPort,(long)x,(long)y); Text(window->RPort,string,(len==-1) ? (long)strlen(string) : (long)len); } hexconv(result,byte) /* byte to 2 ASCII hex digits */ unsigned char result[2],byte; { result[0]=byte>>4; result[1]=byte & 0xf; if (result[0]<10) result[0]|=0x30; else result[0]+=55; if (result[1]<10) result[1]|=0x30; else result[1]+=55; } hex2bin(source,dest) /* ASCII HEX digit to binary */ unsigned char source[2],*dest; { char msb,lsb; /* check for correctness & fold to UC */ if (!isalnum(source[0]) || !isalnum(source[1])) return(1); source[0]=toupper(source[0]); source[1]=toupper(source[1]); if (source[0]>'F' || source[1]>'F') return(1); if (source[0]<='9') msb=source[0]-'0'; else msb=source[0]-55; if (source[1]<='9') lsb=source[1]-'0'; else lsb=source[1]-55; *dest=(msb<<4)+lsb; return(0); } Setup() { IntuitionBase=OpenLibrary("intuition.library",0L); GfxBase=OpenLibrary("graphics.library",0L); DiskfontBase=OpenLibrary("diskfont.library",0L); /* cache user-definable pen colors */ PenCache.BgPen = PenBlock[PRELEN+0]-'0'; /* strip off ASCII bit */ PenCache.StdPen = PenBlock[PRELEN+1]-'0'; PenCache.HexPen = PenBlock[PRELEN+2]-'0'; PenCache.ModPen = PenBlock[PRELEN+3]-'0'; PenCache.SearchPen = PenBlock[PRELEN+4]-'0'; fontinit(); NoFile(); /* initialize empty environment */ if (strlen(&filespec[0])>30) filespec[30-1]='\0'; /* truncate long fspecs */ if (filespec[0]!='\0') OpenFile(); /* allocation-oriented subs can fail, so ... */ if (InitHelpRequester()) exit(FAILAT); if (InitSearchRequester()) exit(FAILAT); if (OpenBackDrop()) exit(FAILAT); SetMenuStrip(pwindow,&menu[0]); /* attach menus */ EnableMenu(); /* handle Search enable/disable */ /* Prior to 1.2, string gadgets may not erase correctly. So, we'll save the initial state of the GOTO stringinfo so we can force it to redraw itself completely later. */ prevgoto=ginfo; /* Cover string gadget w/"GOTO" box until selected */ DrawImage(pwindow->RPort,&GotoImage,291L,172L); thin=&ThinFont; topaz=LoadFont("topaz.font",8); read_sector(); /* read & display */ } OpenFile() { long i; NoFile(); /* assume open won't work */ if (!(file=Open(&filespec[0],MODE_OLDFILE))) { Beep(); return(-1); } /* dud flag */ Seek(file,0L,OFFSET_END); i=Seek(file,0L,OFFSET_BEGINNING); /* get file len */ endsec=i/512; eof=i-(endsec*512); if (eof) endsec++; /* round up odd-length files */ else eof=512; /* adjust pseudo-EOF for full-sectored files */ /* backup successful fspec in case of later unsuccessful files */ strcpy(&goodfile[0],&filespec[0]); return(0); /* good read */ } NoFile() { cursec=endsec=1; /* current/ending sectors = lowest possible */ eof=0; /* sector size = 0 (empty) */ } ShutDown() { if (eof) Close(file); CloseFont(topaz); /* don't expunge romfonts! */ ClearMenuStrip(pwindow); /* delete menus before closing windows */ FreeRequester(); FreeSearchRequester(); CloseBackDrop(); CloseLibrary(IntuitionBase); CloseLibrary(GfxBase); CloseLibrary(DiskfontBase); } ScanGadgets() /* IDCMP asynchronous scan routine */ { struct IntuiMessage *message; long class; short code,qual; static short remap[4]={ 6-1,9-1,7-1,8-1 }; for(;;) { /* FOREVER 'til CLOSEWINDOW */ WaitPort(pwindow->UserPort); while (message=(struct IntuiMessage *)GetMsg(pwindow->UserPort)) { class=message->Class; code=message->Code; qual=message->Qualifier; gadgetptr=((struct Gadget *)message->IAddress); ReplyMsg(message); if (class==MENUPICK) { switch(code) { case 0xf800: /* menu=0, menuitem=0, menusub=NOSUB */ if (ITEMNUM(code)==0) Request(&arequest,pwindow); /* help menu */ break; case 0xf820: /* Quit */ return(0); break; case 0xf801: /* menu 1, menuitems0-3, subitem 0 */ case 0xf821: case 0xf841: case 0xf861: class=GADGETUP; /* fake gadget input for F,S,E & B */ gadgetptr=&gadget[remap[ITEMNUM(code)]]; break; case 0xf802: /* menu 2 */ FakeRequest(); /* search pseudo-requester */ break; case 0x22: /* case dependency ON */ caps=0; break; case 0x822: /* case dependency OFF */ caps=1; break; case 0x42: /* direction=FORWARD */ direction=1; break; case 0x842: /* direction=REVERSE */ direction=-1; break; case 0xf862: /* continue search */ Search(); break; } } switch(class) { case RAWKEY: if (code=arrow_filter(code,qual)) edit_window(code); break; case CLOSEWINDOW: return(0); /* up to caller to shutdown */ break; case MOUSEMOVE: movecur(); /* mouse events only in edit */ break; case GADGETDOWN: gdown(); break; case GADGETUP: (* (int (*)()) gadgetptr->UserData ) (); break; } /* switch (CLASS) */ } /* while (getmsg) */ } /* FOREVER */ } Dummy() { } /* used by dummy gadget # 11 */ Fgadget() { if (cursec1) { cursec--; read_sector(); } } gdown() /* GADGETDOWN */ { short id=gadgetptr->GadgetID; /* Redraw GOTO lid in case of premature deselection */ if (id!=5) DrawImage(pwindow->RPort,&GotoImage,291L,172L); /* redraw filespec in case of premature deselection */ if (id!=10) update_fspec(); if (id<3 && eof) { /* select appropriate edit-window */ idnum=id; /* update edit mode */ refresh_position(1); /* just update "HEX/ASC" msgs */ movecur(); /* display cursor */ } else { /* deselect edit-window */ erase_cursors(); prevx=prevy=prevasc=0; /* undefine cursors */ refresh_position(0); } } gotogad() /* GOTO */ { long i; DrawImage(pwindow->RPort,&GotoImage,291L,172L); /* draw lid */ i=((struct StringInfo *)gadgetptr->SpecialInfo)->LongInt; if (i>0 && i<=endsec) { cursec=i; read_sector(); } else Beep(); /* beep if error! */ ginfo=prevgoto; /* see message in Setup() */ } fspecgad() { struct FileLock *lock; /* AmigaDOS-recommended way to check for file existence : Note that Lock() actually returns a nonzero lock when passed a null string! Bug?! */ if (filespec[0]=='\0') lock=0; else lock=Lock(&filespec[0],ACCESS_READ); if (lock==0) { /* no file? */ Beep(); update_fspec(); return(0); /* redraw & return */ } UnLock(lock); if (eof) Close(file); /* close previous file */ OpenFile(); EnableMenu(); read_sector(); /* new file all ready! */ } EnableMenu() /* reflect presence of file in Search menu */ { if (eof) { OnMenu(pwindow,NOITEM<<5L | 1); /* Move Menu */ OnMenu(pwindow,0<<5L|2); /* Search : search */ OnMenu(pwindow,3<<5L|2); /* Search : Continue Search */ } else { OffMenu(pwindow,NOITEM<<5L | 1); OffMenu(pwindow,0<<5L|2); OffMenu(pwindow,3<<5L|2); } } update_fspec() { strcpy(&filespec[0],&goodfile[0]); /* restore good filespec */ /* Note : Before 1.2, string gadgets did not redraw their entire display when refreshed. So, to make sure all bits and pieces are removed, we have to erase by hand. */ SetAPen(pwindow->RPort,PenCache.BgPen); /* background color */ RectFill(pwindow->RPort,97L,12L,98L+250,12L+7); /* erase string */ RefreshGadgets(&gadget[10-1],pwindow,0L); /* and redraw */ } Search1() { /* FakeRequest() forces this routine to perform inclusive searches when the search string is changed; prevents skipping the current sector when a previous (different string) search highlighted it. */ searchflag=0; Search(); } Search() /* sector string search : current to last records */ { int c; short start,teof,i,n,dest,tcaps,flag=0; char convbuf[50],*srcbuf; /* flag "zz" busy ptr for search */ SetPointer(pwindow,&BusySprite[0],25L,16L,0L,0L); c=strlen(&searchbuf[0]); srcbuf=(char *)&searchbuf[0]; tcaps=caps; /* cache uc/lc match flag */ /* treat '$' search as literal if no args! */ if (searchbuf[0]=='$' && c>1) { for (n=0,i=1;iRPort,COMPLEMENT); RectFill(pwindow->RPort,prevx,prevy,prevx+10,prevy+6); RectFill(pwindow->RPort,prevasc,prevy,prevasc+4,prevy+7); SetDrMd(pwindow->RPort,JAM2); } draw_cursors() { if (prevasc==0) return(0); /* don't draw undefined cursors! */ SetDrMd(pwindow->RPort,COMPLEMENT); RectFill(pwindow->RPort,prevx,prevy,prevx+10,prevy+6); /* draw HEX cursor */ RectFill(pwindow->RPort,prevasc,prevy,prevasc+4,prevy+7); /* ASC cursor */ SetDrMd(pwindow->RPort,JAM2); } movecur() { long hexx,hexy,ascx; short i; hexx=pwindow->MouseX; hexy=pwindow->MouseY; i=roundup(&hexx,&hexy,&ascx); /* compute relative cursor positions */ /* truncate max-y pos if exceeding EOF boundaries */ if ((cursec==endsec) && ((hexy-26)/8)*32+i >= eof) hexy=((eof/32)-(i>=(eof&31)))*8+26; /* takes odd eof's into acct */ /* return if not enough movement to actually move cursor */ if ((hexx==prevx) && (hexy==prevy) || (hexy<26)) return(0); erase_cursors(); /* erase old cursors */ prevx=hexx; prevy=hexy; prevasc=ascx; /* & update */ refresh_position(0); draw_cursors(); } roundup(hexx,hexy,ascx) /* map cursor to HEX or ASCII window */ long *hexx,*hexy,*ascx; { static short tilehex[32] = { /* allowed HEX cursor positions */ 8, 20, 32, 44, 62, 74, 86, 98, 116,128,140,152, 170,182,194,206, 224,236,248,260, 278,290,302,314, 332,344,356,368, 386,398,410,422 }; static short tileasc[32] = { 441,447,453,459, 465,471,477,483, /* allowed ASC cursor positions */ 489,495,501,507, 513,519,525,531, 537,543,549,555, 561,567,573,579, 585,591,597,603, 609,615,621,627 }; short i; if (*hexx<440) { /* cursor in HEX window? */ for (i=0;*hexx>=tilehex[i] && i<32;i++); /* round x to nearest HEX pair */ if (i) --i; *hexx=tilehex[i]; *ascx=tileasc[i]; /* compute ASCII, given HEX */ } else { /* cursor in ASCII window? */ for (i=0,*ascx=*hexx;*ascx>=tileasc[i] && i<32;i++); /* as above */ if (i) --i; *ascx=tileasc[i]; *hexx=tilehex[i]; /* compute HEX, given ASCII */ } if (*hexy<26) *hexy=26; else if (*hexy>146) *hexy=146; *hexy=((*hexy-26)/8)*8+26; /* round y to nearest text line */ return((int)i); /* return x-index for array */ } arrow_filter(code,qual) /* arrow & help-key processor */ short code,qual; { short dx=0,dy=0; if (code==0x5f) { /* "HELP" requester */ Request(&arequest,pwindow); return(0); } /* Sure, modifying shared resources without the proper exclusion is poor style, but in this case it's fast and effective. */ if (prevasc) { /* quick-edit */ switch(code) { case 0x4c: dy=-8; break; /* up-arrow */ case 0x4f: dx=-12; break; /* left-arrow */ case 0x4e: dx=18; break; /* right-arrow */ case 0x4d: dy=8; break; /* down-arrow */ default: return(key_conv(code,qual)); /* normal keys? just convert */ break; } pwindow->MouseX=prevx+dx; pwindow->MouseY=prevy+dy; if (pwindow->MouseX > 422+11) { pwindow->MouseX=8; pwindow->MouseY+=8; } else if (pwindow->MouseX<8) { pwindow->MouseX=422; pwindow->MouseY-=8; } if (pwindow->MouseY > 146) pwindow->MouseY=26; else if (pwindow->MouseY < 26) pwindow->MouseY=146; movecur(); return(0); } } /* key_conv - Optimized Rawkeys to ASCII converter */ key_conv(code,qualifier) unsigned char code; unsigned short qualifier; { char result; /* Note : Some pgms may prefer CR's to be returned as LF's, */ /* which the Amiga compiler defines as '\n'. */ static char convtable[] = { '`','1','2','3','4','5','6','7','8','9','0','-','=','\\','\0', '0','q','w','e','r','t','y','u','i','o','p','[',']','\0','1', '2','3','a','s','d','f','g','h','j','k','l',';','\'','\0', '\0','4','5','6','\0','z','x','c','v','b','n','m',',','.', '/','\0','.','7','8','9',' ','\b','\t',13,13,0x1b,0x7f }; static char shiftable[] = { '~','!','@','#','$','%','^','&','*','(',')','_','+','|','\0', '0','Q','W','E','R','T','Y','U','I','O','P','{','}','\0','1', '2','3','A','S','D','F','G','H','J','K','L',':','\'','\0', '\0','4','5','6','\0','Z','X','C','V','B','N','M','<','>', '?','\0','.','7','8','9',' ','\b','\t',13,13,0x1b,0x7f }; if (code >0x46) return(0); /* filter upstrokes, CSI keys, etc */ if (qualifier & 0x3) result=shiftable[code]; /* SHIFT */ else result=convtable[code]; /* Caps Lock, unlike SHIFT, does not affect non-alphas */ if ((qualifier & 0x4)&&(isalpha(result))) result=shiftable[code]; /* CTRL */ if ((qualifier & 0x8)&&(isalpha(result))) result=(result & 0x1f); if (qualifier & 0x30) result|=0x80; /* ALT */ return((int)result); } main(argc,argv) int argc; char *argv[]; { if (argc>1) strcpy(&filespec[0],argv[1]); /* else null fspec */ Setup(); ScanGadgets(); ShutDown(); }