/* hex2bin.c reverse hexdump Copyright (c) 1996 by Andreas Leitgeb (AvL) Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. */ #include #include #include #include #define MAX 10240 #define E_ManyInputArgs "%s: More than one inputfile given.\n" #define E_ManyOutputArgs "%s: More than one outputfile given.\n" #define E_ParamRequired "%s: Argument -%c requires a filename given.\n" #define E_Usage \ "Usage: %s [[-i] inputfile] [-o outfile] [-q|-f|-v|-I] \n" \ " if in/outfile are omitted, stdin/stdout are used instead\n" \ " -q (quiet): hush up warnings.\n" \ " -f (flush): flush output after each chunk.\n" \ " -v (verbose): print more infos\n" \ " -I (interactive): prompt current offset and imply -f \n" #define E_OpenRead "%s: Cannot open %s for reading.\n" #define E_OpenWrite "%s: Cannot open %s for writing.\n" #define E_ValueTooLarge "%s: Value too large. (line %ld)\n" #define E_InvalidChar "%s: Invalid character. (line %ld)\n" #define E_LineTooLong "%s: Line too long. (line %ld)\n" #define E_InvalidStar "%s: A '*'-line must be preceded by a line with data. (line %ld)\n" #define E_AddrAfterStar "%s: Address must be given after '*'-line. (line %ld)\n" #define E_InvalAddrStar "%s: Invalid address after '*'-line. (line %ld)\n" #define W_UnknownEscape "%s: Warning: unknown escape-sequence. (line %ld)\n" #define W_UnexpectedEOF "%s: Warning: unexpected end of input. (line %ld)\n" #define I_FurtherAddr "%s: Further Addresses adjusted by 0x%lx. (line %ld)\n" #define I_LinesForStar "%s: chunk repeated %ld more times. (line %ld)\n" #define I_Repeating "%s: repeating previous chunk %ld more times.\n" #define I_Success "%s: Translation successful. (%ld Bytes)\n" const char *cmd; /* command name */ int warning=1,flush=0; /* warning level */ long linnr; /* line number in input */ void output(char *bptr,long len) { long i; for (i=0; i='0' && ch<'8' ) { long val=0; /* `quoted' is misused as digit counter here */ do { val<<=3; val+=(ch-'0'); cptr++; ch=*cptr; quoted++; } while (ch>='0' && ch<'8' && val<=040 && quoted<3); pchar(bptr,pn,val); quoted=0; cptr--; } else { pchar(bptr,pn,ch); } } /* end default */ } /* end switch */ } else { if (ch=='\\') { quoted=1; } else if (ch!='\n') pchar(bptr,pn,ch); } cptr++; ch=*cptr; } /* if we stopped on close quote, advance pointer */ if ( ch=='"' ) { cptr++; } *pcptr=cptr; *pbptr=bptr; } #undef pchar } long doline(char *str, long *offs, char *buf) { char *cptr=str, *bptr=buf, ch; long n=0; /* Input: str: hexstring * Output: offs: address offs==-1 --> no addr specified * buf: binary data * Return: length ==-1 --> EOF */ /* find first nonspace maybe after the address */ while ((ch=*cptr) && isspace(ch)) { cptr++; } *offs=readhex(&cptr,0x7fffffff); while ((ch=*cptr) && isspace(ch)) { cptr++; } /* if first character after first number is a colon or * a semicolon, then the number was an address */ if (ch==';') { /* logical end of input (ignore the rest) */ return -1; } else if (ch==':') { /* first number was an address */ cptr++; ch=*cptr; } else { /* restart at linestart (offset was data, not address) */ *offs=-1; cptr=str; ch=*cptr; } while ( ch!=0 && ch!='|' ) { if ( ch=='-' || isspace(ch) ) { cptr++; } else if ( ch=='"' ) { readstr(&cptr,&bptr,&n); } else if ( isxdigit(ch) ) { *bptr=readhex(&cptr,0xff); bptr++; n++; } else { fprintf(stderr,E_InvalidChar,cmd,linnr); exit(3); } ch=*cptr; } return n; } char *getline(long actcount,char *buf,size_t bufsize) { if (warning>=3) { fprintf(stderr,"%8.8lx: ",actcount); fflush(stderr); } return fgets(buf,bufsize,stdin); } long mainloop() { char str[MAX], buf[MAX], buf1[MAX]; long buflen=0, buflen1=0, rep=0, newlen; long actcount=0, shift=0, offset; int finished=0; linnr=0; while (getline(actcount-shift,str, sizeof(str)) != NULL) { linnr++; if ( strlen(str)+1==MAX && str[MAX-2]!='\n') { fprintf(stderr,E_LineTooLong,cmd,linnr); exit(3); } if ( str[0]=='\n' ) { continue; } if ( str[0]=='*' ) { char *cptr; long num; if (buflen == 0) { fprintf(stderr,E_InvalidStar,cmd,linnr); exit(3); } /* see for a number to be used as multiplikator */ num=strtoul(str+1,&cptr,0); if (str+1 != cptr) { /* yes. number found: immediately repeat previous line */ if (warning>=2) fprintf(stderr,I_Repeating,cmd,num); while (num>0) { output(buf, buflen); actcount+=buflen; num--; } rep=0; continue; } else { /* no number found: prepare for next line's offset */ memcpy(buf1,buf,buflen); buflen1=buflen; rep=1; continue; } } newlen=doline(str,&offset,buf); if (offset != -1) { offset += shift; } if (rep) { if (offset==-1) { fprintf(stderr,E_AddrAfterStar,cmd,linnr); exit(3); } rep=0; while ( (actcount+buflen1) <= offset) { output(buf1,buflen1); actcount+=buflen1; rep++; } if (warning>=2) fprintf(stderr,I_LinesForStar,cmd,rep,linnr); rep=0; if (actcount != offset) { fprintf(stderr,E_InvalAddrStar,cmd,linnr); exit(3); } } if (newlen == -1) { finished=1; break; } if ( offset != -1 && offset != actcount ) { shift += actcount-offset; if (warning>=2) fprintf(stderr,I_FurtherAddr,cmd,shift,linnr); } if (newlen) { buflen=newlen; output(buf,buflen); actcount+=buflen; } } if (!finished) { if (warning>=1) fprintf(stderr,W_UnexpectedEOF,cmd,linnr); } return actcount; } int main(int argc,char *argv[]) { int i; char *infname=NULL,*outfname=NULL; long total; cmd=argv[0]; for (i=1 ; i=2) fprintf(stderr,I_Success,cmd,total); return(0); }