/* Utility for reading DBF files. Under MS DOS, compile with Turbo C++ or like, e.g. tcc -P extract.C Under UNIX, use option -D_UNIX, e.g. gcc -D_UNIX extract.C */ #include #include #include #include #include #ifdef _UNIX_ #include #include #define stricmp strcasecmp #define BIGENDIAN #else #include #endif /* standard definitons */ typedef char * str; typedef int logical; #define cy(i,n) for((i)=0; (i)<(n); (i)++) #define cy2(i) for((i)=0; (i)<2; (i)++) void oops(char *s) { fprintf(stderr, "%s\n", s); exit(1); } static int line_No = 1; static logical all_fields = 0; #define NF 64 /* Maximum number of fields */ inline void get( int & x, int f) { #ifdef BIGENDIAN /* this is what you do if you need to read, on a mainframe, data written on a PC! */ unsigned char c[2]; read( f, c, 2); x = (unsigned int)(c[0]) + (((unsigned int) c[1]) << 8); #else x = 0; read( f, &(x), 2); #endif } #define set(n) lseek(f, n, SEEK_SET) /* Field description */ class dbfield { public: int offset, size; str name; /* sets offset and size */ void setos( int o, int s) { offset = o; size = s;} /* prints the name; good for header */ void printname(FILE *f) {fprintf(f, "%-*s ", size, name);} void underline(FILE *f) { int i; cy(i,size) putc('-', f); putc(' ', f); } }; /* Removes trailing blanks (substitutes 0s instead of them) & returns * new length */ int minlen(str s) { int i; for(i = strlen(s)-1; i>=0 && strchr(" \n\r\t\032",s[i]); i--) s[i] = 0; return i+1; } static int abuflen; static int nf; /* How many fields we are to operate with */ static dbfield afield [NF]; void extract( dbfield field[], int nf, str buffer) { FILE * out =stdout; int k; cy(k,nf) { str body = (str)buffer + field[k].offset; if (k>0) fprintf(out, " "); // separator fwrite(body, field[k].size, 1, out); } fprintf(out, "\n"); } void single_file( int f) { int hsize, rsize, nrec; str abuf, buffer; long curoff; unsigned long first_line=1, last_line=0xFFFF; int i, k, fldoff0, j, dest; set(4); get( nrec,f); set(8); get(hsize,f); set(0x0A); get(rsize,f); // printf("nrec=%d; hsize=%d; rsize=%d\n", nrec, hsize, rsize); cy(i,nf) afield[i].size = afield[i].offset = 0; fldoff0 = 1; abuflen = 1; if (all_fields) nf = 0; /* Reading the header */ for( curoff= 0x20; curoff+0x20<=hsize; curoff += 0x20) { char s[32]; int doff; set( curoff ); read( f, s, 16); set( curoff + 0x10 ); get(doff,f); // printf("s=%s\n", s); if (all_fields) { char * q = strdup(s); if (q == NULL) oops("Out of memory"); // printf("name = `%s', size = %d\n", s, doff); afield[nf].name = q; afield[nf].setos( fldoff0, doff); nf ++; abuflen += doff; } else { for(k=0; k nrec) last_line = nrec; /* Printing the header */ cy(k,nf) afield[k].printname(stdout); printf("\n"); cy(k,nf) afield[k].underline(stdout); printf("\n"); /* Reading the body */ for(curoff = hsize + (first_line-1)*rsize, line_No = first_line; line_No <= last_line; curoff += rsize, line_No ++) { /* printf("\nLine %d; offset %ld",line_No,curoff); */ if ( set( curoff ) == -1 ) { fprintf(stderr,"Unexpected end of DBF file, record #%d",line_No); exit(1); } read( f, buffer, rsize); extract( afield, nf, buffer); } } /* Makes the list of the names of the fields we want printed */ void learn_field_names(int argc, str argv[], int &ia, int &nf, dbfield field[]) { str v,u; nf = 0; v = (ia= NF) { fprintf(stderr,"Too many fields specified in command line"); exit(1); } field[nf++].name = v; u = strchr(v,'+'); v = NULL; if (u) { *u = 0; v = u+1; if (!*v) { ia++; v = (ia < argc) ? argv[ia] : NULL; } } else { ia++; if (ia < argc && argv[ia][0] == '+') v = argv[ia]+1; } } } void usage(int argc, char * argv[]) { fprintf(stderr,"\nUsage: "); fprintf(stderr,"\n%s [...]", argv[0]); fprintf(stderr,"\n is a list [+...] "); fprintf(stderr,"\n or a single dot (.). "); fprintf(stderr,"\n 's are DBF file names"); fprintf(stderr,"\nExamples:"); fprintf(stderr,"\n %s firstname +lastname +id foo.dbf", argv[0]); fprintf(stderr,"\nCopies the fields firstname, lastname, and id of foo.dbf to std. output."); fprintf(stderr,"\n %s firstname . foo.dbf", argv[0]); fprintf(stderr,"\nCopies all fields of foo.dbf to std. output."); fprintf(stderr,"\nYou can use redirection (>) to write output to a file."); fprintf(stderr,"\n"); exit(1); } int main(int argc, char * argv[]) { int ia = 1; learn_field_names(argc, argv,ia, nf, afield); if (ia >= argc) usage(argc, argv); for(;ia