Return-Path: <@yonge.csri.toronto.edu:ian@sq.sq.com> Received: from sq.sq.com ([192.31.6.1]) by yonge.csri.toronto.edu with SMTP id <172>; Fri, 24 Jan 1992 13:26:14 -0500 Received: by sq.sq.com (/\=-/\ Smail3.1.18.1 #18.1) id ; Fri, 24 Jan 92 13:25 EST Message-Id: To: saw@hallc1.cebaf.gov (Stephen A. Wood) Cc: ian@sq.com, paddyw@lbs.lon.ac.uk Subject: dbase3 file reader in C source Date: Fri, 24 Jan 1992 13:24:47 -0500 From: ian@sq.com This will interest anyone who has data in a binary program that was written using dbase3 to do the file storage. It dumps out the header, a seperator line, and then the data. It is copyright by the author, but freely copyable. The author is Henry Spencer, henry@zoo.toronto.edu, whom you can contact for confirmation if you wish. Ian Darwin ian@sq.com : To unbundle, sh this file directory dbase3 mkdir dbase3 2>/dev/null echo x - dbase3/ORIGIN 1>&2 sed 's/^X//' >dbase3/ORIGIN <<'@@@End of dbase3/ORIGIN' XReturn-Path: XReceived: by sq.sq.com (/\=-/\ Smail3.1.18.1 #18.1) X id ; Thu, 2 Jan 92 16:28 EST XMessage-Id: XFrom: henry@zoo.toronto.edu XDate: Thu, 2 Jan 92 16:27:25 EST XTo: ian@sq.com (Ian Darwin) XSubject: Re: db3 to ascii? X Xdbase3.1: Xdbase3.c: Xdone @@@End of dbase3/ORIGIN echo x - dbase3/dbase3.1 1>&2 sed 's/^X//' >dbase3/dbase3.1 <<'@@@End of dbase3/dbase3.1' X.TH DBASE3 1 "15 Jan 1991" X.BY Zoology X.SH NAME Xdbase3 \- convert dBASE III database to ASCII file X.SH SYNOPSIS X.B dbase3 X[ X.B \-a X] [ X.B \-b X] [ file ] ... X.SH DESCRIPTION X.I Dbase3 Xtakes each of the X.IR file (s) X(standard input if none) Xas a X.I dBASE III Xdatabase, and produces an ASCII version on standard output. X.PP XThe ASCII form of a database starts with a short header Xprinting out the miscellaneous information in the X.I dBASE III Xheader: Xthe last-update date, the header length, record length, and number of records. XThen comes one line per field, giving field name, type, and length. XThen comes a line consisting entirely of X.RL ` --- ', Xfollowed by the data. XThe data is printed one line per record, with fields separated by tabs. XNo alterations are done to the data except deletion of trailing blanks Xin each field. X.PP XThe X.L -b Xoption preserves trailing blanks. X.PP XNormally, records marked as ``deleted'' do not appear in the output. XThe X.L \-a Xoption causes output of X.I all Xrecords, with an extra field prepended to each one containing its Xdeletion-flag character (nominally space for `present' and asterisk (*) for X`deleted'). X.SH SEE ALSO X.IR "File Formats for Popular PC Software: A Programmer's Reference" , Xby Jeff Walden; XJohn Wiley & Sons, Inc. 1986. X.SH HISTORY XWritten at U of T by Henry Spencer. X.SH BUGS XIgnores the ``field data address'' and ``field decimal count'' aspects Xof the fields, as it is not clear what these mean. @@@End of dbase3/dbase3.1 echo x - dbase3/dbase3.c 1>&2 sed 's/^X//' >dbase3/dbase3.c <<'@@@End of dbase3/dbase3.c' X/* X * dbase3 - pick apart dbase3 files X * X * $Log$ X */ X X#include X#include X#include X#include X X#define MAXSTR 500 /* For sizing strings -- DON'T use BUFSIZ! */ X#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) X X#ifndef lint Xstatic char RCSid[] = "$Header$"; X#endif X Xint debug = 0; Xchar *progname; X Xchar *inname; /* filename for messages etc. */ Xlong lineno; /* line number for messages etc. */ X Xint allrecs = 0; /* even deleted records? */ Xint trim = 1; /* trim trailing blanks? */ Xstruct field { X char name[12]; X char type; X int length; X} fields[128]; Xint nfields = 0; X Xextern void error(), exit(); X#ifdef UTZOOERR Xextern char *mkprogname(); X#else X#define mkprogname(a) (((a) == NULL) ? "?noname?" : (a)) X#endif Xvoid fail(); X X/* X - main - parse arguments and handle options X */ Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X int c; X int errflg = 0; X FILE *in; X struct stat statbuf; X extern int optind; X extern char *optarg; X extern FILE *efopen(); X void process(); X X progname = mkprogname(argv[0]); X X while ((c = getopt(argc, argv, "abx")) != EOF) X switch (c) { X case 'a': /* All records. */ X allrecs = 1; X break; X case 'b': /* Leave trailing blanks alone. */ X trim = 0; X break; X case 'x': /* Debugging. */ X debug++; X break; X case '?': X default: X errflg++; X break; X } X if (errflg) { X fprintf(stderr, "usage: %s ", progname); X fprintf(stderr, "[-a] [-b] [file] ...\n"); X exit(2); X } X X if (optind >= argc) X process(stdin, "stdin"); X else X for (; optind < argc; optind++) X if (STREQ(argv[optind], "-")) X process(stdin, "-"); X else { X in = efopen(argv[optind], "r"); X if (fstat(fileno(in), &statbuf) < 0) X error("can't fstat `%s'", argv[optind]); X if ((statbuf.st_mode & S_IFMT) == S_IFDIR) X error("`%s' is directory!", argv[optind]); X process(in, argv[optind]); X (void) fclose(in); X } X exit(0); X} X X/* X - process - process input file X */ Xvoid Xprocess(in, name) XFILE *in; Xchar *name; X{ X char line[MAXSTR]; X register int c; X register int hlen; X register int rlen; X register long nrecs; X register int i; X register int nf; X X inname = name; X lineno = 0; X X c = getc(in); X if (c != 3 && c != 0x83) X fail("does not appear to be a dBASE III file", ""); X printf("last updated (yy mm dd) %d ", getc(in)); X printf("%d ", getc(in)); X printf("%d\n", getc(in)); X nrecs = getc(in); X nrecs |= getc(in) << 8; X nrecs |= getc(in) << 16; X nrecs |= getc(in) << 24; X c = getc(in); X hlen = c | (getc(in) << 8); X c = getc(in); X rlen = c | (getc(in) << 8); X printf("header length %d, record length %d, %ld records\n", hlen, X rlen, nrecs); X for (i = 12; i <= 31; i++) X (void) getc(in); X if (feof(in) || ferror(in)) X fail("EOF or error while reading start of header", ""); X X nfields = 0; X while ((c = getc(in)) != '\r') { X ungetc(c, in); X nf = nfields; X nfields++; X fread(fields[nf].name, sizeof(char), 11, in); X fields[nf].name[11] = '\0'; X fields[nf].type = getc(in); X (void) getc(in); X (void) getc(in); X (void) getc(in); X (void) getc(in); X fields[nf].length = getc(in); X if (fields[nf].length > sizeof(line)) { X /* "can't happen", since length is a byte */ X fprintf(stderr, "field %d too long: %d bytes\n", X nfields, fields[nf].length); X exit(1); X } X for (i = 17; i <= 31; i++) X (void) getc(in); X printf("field %d: name `%s', type %c, length %d\n", nfields, X fields[nf].name, fields[nf].type, fields[nf].length); X } X if (feof(in) || ferror(in)) X fail("EOF or error while reading field descriptions", ""); X printf("---\n"); X X for (; nrecs > 0; nrecs--) { X lineno++; X c = getc(in); X if (allrecs) X printf("%c\t", getc(in)); X if (allrecs || c == ' ') X for (nf = 0; nf < nfields; nf++) { X i = fields[nf].length; X fread(line, sizeof(char), i, in); X if (trim) X while (i > 0 && line[i-1] == ' ') X i--; X fwrite(line, sizeof(char), i, stdout); X if (nf == nfields-1) X putchar('\n'); X else X putchar('\t'); X } X if (feof(in) || ferror(in)) X fail("EOF or error while reading data", ""); X } X X c = getc(in); X if (c != 032 && c != EOF) X fprintf(stderr, "warning: junk on end of `%s'\n", inname); X} X X/* X - fail - complain and die X */ Xvoid Xfail(s1, s2) Xchar *s1; Xchar *s2; X{ X fprintf(stderr, "%s: (file `%s', record %ld) ", progname, inname, lineno); X fprintf(stderr, s1, s2); X fprintf(stderr, "\n"); X exit(1); X} @@@End of dbase3/dbase3.c