/* fscanbin.c -- scan binary fields via format string ** ** public domain by Ray Gardner Englewood, Colorado 11/29/89 ** ** Usage: fscanbin(FILE *fp, char *format, ...) ** ** where format string contains specifiers: ** -ddd means skip ddd bytes ** i means read a 16-bit int ** l means read a 32-bit int ** sddd means read a character string of up to ddd bytes ** reads up to a nul byte if ddd is zero or missing ** cnnn means read a character field of nnn bytes (not nul-terminated) ** reads one byte if nnn is zero or missing */ #include #include #include #include typedef unsigned short int16; typedef unsigned long int32; #define int16swap(n) (*n = (*n << 8) | (*n >> 8)) #define int32swap(n) (\ int16swap(&((int16 *)n)[0]),\ int16swap(&((int16 *)n)[1]),\ *n = (*n << 16) | (*n >> 16)\ ) #define maxk 32767 int fscanbin (FILE *fp, char *format, ...) { va_list argp; unsigned char *p; unsigned k; int c; char *charp; int16 *int16p; int32 *int32p; int bytes_read; bytes_read = 0; va_start(argp, format); for ( p = (unsigned char *)format; *p; ) { switch( *p & 0xFF ) { case '-': for ( k = 0, c = *++p; isdigit(c); c = *++p ) k = 10 * k + c - '0'; if ( k == 0 ) k = 1; if ( fseek(fp, (long)k, SEEK_CUR) ) return -2; /* i/o error */ bytes_read += k; break; case 'i': int16p = va_arg(argp, int16 *); if ( fread((void *)int16p, sizeof(int16), 1, fp) != 1 ) return -2; /* i/o error */ #if SWAP16 int16swap(int16p); #endif p++; bytes_read += sizeof(int16); break; case 'l': int32p = va_arg(argp, int32 *); if ( fread((void *)int32p, sizeof(int32), 1, fp) != 1 ) return -2; /* i/o error */ #if SWAP32 int32swap(int32p); #endif p++; bytes_read += sizeof(int32); break; case 's': charp = va_arg(argp, char *); for ( k = 0, c = *++p; isdigit(c); c = *++p ) k = 10 * k + c - '0'; do { c = getc(fp); if ( c == EOF ) return -2; *charp++ = (char)c; bytes_read++; } while ( c && (k == 0 || --k) ); break; case 'c': charp = va_arg(argp, char *); for ( k = 0, c = *++p; isdigit(c); c = *++p ) k = 10 * k + c - '0'; if ( k == 0 ) k = 1; if ( fread((void *)charp, sizeof(char), k, fp) != k ) return -2; /* i/o error */ bytes_read += k; break; default: return -1; /* bad format */ } } va_end(argp); return bytes_read; }