📄 dbf2ascii.c
字号:
/* * A simple DBF-To-Ascii converter * * A DBF file is read. On output, the first line contains the field * headers, the second line contains the data format for each field, * and the following lines contain a record each. * * For the DBF format, see http://www.wotsit.demon.co.uk/ * * Frank Pilhofer <fp@fpx.de> */#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>/* * macros to extract short/long integers from character arrays. In * the DBF structure, multi-byte integers are not always aligned. * We assume LSB first (Little Endian, used on the i386). */#define GETSHORT(c) (((short)((unsigned char *)c)[0])|(((short)((unsigned char *)c)[1])<<8))#define GETLONG(c) ((int)GETSHORT(c)|(int)(GETSHORT(c+2)<<16))char delimiter[256] = "\t";char copyfields[256];/* * field description */typedef struct _dbf_field { char name[12]; int type; int length; int dcount; union { int deleted; char *string; char date[9]; int logical; long integer; } data; struct _dbf_field *next;} dbf_field;/* * Database description */typedef struct { unsigned char type; struct { unsigned char yy; unsigned char mm; unsigned char dd; } lastmod; unsigned long numrecs; unsigned short hsize; unsigned short rsize; dbf_field *fields;} dbf;/* * trucate a character field - remove whitespace */char *truncfield (char *data){ char *x=data, *y=data, *z; while (*y && isspace(*y)) y++; while (*y) { while (*y && !isspace(*y)) *x++ = *y++; z=x; while (*y && isspace(*y)) *x++ = *y++; if (!*y) x=z; } *x = *y; return data;}/* * kill a linked list of fields */voidkillfields (dbf_field *fields){ dbf_field *next; while (fields) { switch (fields->type) { case 'C': case 'F': case 'N': free (fields->data.string); break; } next = fields->next; free (fields); fields = next; }}voidkilldbf (dbf * db){ if (db) { killfields (db->fields); free (db); }}/* * read fields from dbf file */dbf_field *getfields (FILE *input){ dbf_field *head=NULL, *tail=NULL, *item; char desc[32]; int c; while (42) { if ((desc[0] = fgetc (input)) == 0x0d) break; if (feof (input)) { fprintf (stderr, "error: unexpected EOF while reading header\n"); killfields (head); return NULL; } if (fread (desc+1, 1, 31, input) < 31) { fprintf (stderr, "error: unexpected EOF while reading header\n"); killfields (head); return NULL; } if ((item = (dbf_field *) malloc (sizeof (dbf_field))) == NULL) { fprintf (stderr, "error: could not allocate field data\n"); killfields (head); return NULL; } strncpy (item->name, desc, 11); item->name[11] = '\0'; item->type = desc[11]; item->length = (int) desc[16]; item->dcount = (int) desc[17]; item->next = NULL; truncfield (item->name); switch (item->type) { case 'C': case 'F': case 'N': if ((item->data.string = (char *) malloc (item->length+1)) == NULL) { fprintf (stderr, "error: could not allocate field data\n"); killfields (head); free (item); return NULL; } break; case 'D': case 'L': case 'I': /* Visual FoxPro: 32bit Integer, LSB First */ break; default: /* going to be ignored */ break; } if (head == NULL) { head = tail = item; } else { tail->next = item; tail = tail->next; } } /* * should be terminated by a null byte */ if ((c = fgetc (input)) != 0) { ungetc (c, input); } return head;}dbf *getdbf (FILE *input){ unsigned char dbfheader[32]; dbf * db; if ((db = (dbf *) malloc (sizeof (dbf))) == NULL) { fprintf (stderr, "error: could not allocate database info structure\n"); return NULL; } if (fread (dbfheader, 1, 32, input) < 32) { fprintf (stderr, "error: could not read DBF header\n"); free (db); return NULL; } db->type = dbfheader[0]; db->lastmod.yy = dbfheader[1]; db->lastmod.mm = dbfheader[2]; db->lastmod.dd = dbfheader[3]; db->numrecs = GETLONG(dbfheader+4); db->hsize = GETSHORT(dbfheader+8); db->rsize = GETSHORT(dbfheader+10); /* * sensibility check: test day and month */ if (db->lastmod.mm < 1 || db->lastmod.mm > 12 || db->lastmod.dd < 1 || db->lastmod.dd > 31) { fprintf (stderr, "error: this does not look like a DBF file\n"); free (db); return NULL; } /* * encrypted flag */ if (dbfheader[15] != 0) { fprintf (stderr, "error: encrypted DBF file\n"); free (db); return NULL; } if ((db->fields = getfields (input)) == NULL) { free (db); return NULL; } fseek (input, db->hsize, SEEK_SET); return db;}/* * check that all requested fields are printable */voidcheckfields (FILE *output, dbf_field *iter){ int count=1; while (iter) { if (copyfields[count]) { switch (iter->type) { case 'C': case 'D': case 'F': case 'N': case 'L': case 'I': break; default: fprintf (stderr, "warning: can't handle field `%s' type `%c' (ignored)\n", iter->name, iter->type); copyfields[count] = 0; break; } } iter = iter->next; count++; }}/* * show titles of fields */voidshowtitle (FILE *output, dbf_field *iter, int deleted){ int count=1, flag=0; if (deleted) { fprintf (output, "del"); flag++; } while (iter) { if (copyfields[count++]) { fprintf (output, "%s%s", (flag++)?delimiter:"", iter->name); } iter = iter->next; } fprintf (output, "\n");}voidshowtypes (FILE *output, dbf_field *iter, int deleted){ int count=1, flag=0; if (deleted) { fprintf (output, "C1"); flag++; } while (iter) { if (copyfields[count++]) { fprintf (output, "%s", (flag++)?delimiter:""); switch (iter->type) { case 'C': fprintf (output, "C%d", iter->length); break; case 'D': fprintf (output, "D"); break; case 'F': fprintf (output, "F%d", iter->length); break; case 'N': fprintf (output, "N%d.%d", iter->length, iter->dcount); break; case 'L': fprintf (output, "L"); break; case 'I': fprintf (output, "I"); break; default: fprintf (output, "%c", iter->type); break; } } iter = iter->next; } fprintf (output, "\n");}/* * read a record */intreadrecord (FILE *input, dbf_field *iter, int dotrunc){ int deleted=0; char temp[4]; int c, i; if ((c = fgetc (input)) == 0x1a) return -1; if (feof (input)) return -1; if (c == '*') deleted = 1; while (iter) { switch (iter->type) { case 'C': case 'F': case 'N': if ((fread (iter->data.string, 1, iter->length, input)) < iter->length) return -2; iter->data.string[iter->length] = '\0'; if (dotrunc) truncfield (iter->data.string); break; case 'D': if ((fread (iter->data.date, 1, 8, input)) < 8) return -2; iter->data.date[8] = '\0'; if (dotrunc) truncfield (iter->data.date); break; case 'L': c = fgetc (input); if (feof (input)) return -2; switch (c) { case 'Y': case 'y': case 'T': case 't': iter->data.logical = 'T'; break; case 'N': case 'n': case 'F': case 'f': iter->data.logical = 'F'; break; default: iter->data.logical = '?'; break; } break; case 'I': if ((fread (temp, 1, 4, input)) < 4) return -2; if (GETLONG(temp) < 0) { iter->data.integer = GETLONG(temp); } iter->data.integer = GETLONG(temp); break; default: /* just flush */ for (i=0; i<iter->length && !feof (input); i++) c = fgetc (input); if (feof (input)) return -2; break; } iter = iter->next; } return deleted;}voiddumprecord (FILE *output, dbf_field *iter, int deleted, int isdel, int dotrunc){ int count=1, flag=0; if (deleted) { fprintf (output, "%s", (isdel) ? "*" : ((dotrunc) ? "" : " ")); flag++; } while (iter) { if (copyfields[count++]) { fprintf (output, "%s", (flag++)?delimiter:""); switch (iter->type) { case 'C': case 'F': case 'N': fprintf (output, "%s", iter->data.string); break; case 'D': fprintf (output, "%s", iter->data.date); break; case 'L': fprintf (output, "%c", iter->data.logical); break; case 'I': fprintf (output, "%ld", iter->data.integer); break; default: break; } } iter = iter->next; } fprintf (output, "\n");}intmain (int argc, char *argv[]){ int c, dotrunc=0, deleted=0, title=0, types=0, count, left, right; FILE *infile=stdin; char *blah; dbf *db; optarg = NULL; memset (copyfields, 1, 256); while ((c = getopt (argc, argv, "s:tdnf:ph")) != -1) { switch (c) { case 's': strcpy (delimiter, optarg); break; case 'f': memset (copyfields, 0, 256); blah = optarg; if (*blah == '-') { right = atoi (++blah); for (count=1; count<=right; count++) copyfields[count] = 1; while (isdigit(*blah)) blah++; while (*blah == ',') blah++; } while (isdigit(*blah)) { left = atoi (blah); while (isdigit(*blah)) blah++; if (*blah=='-') { right = atoi(++blah); for (count=left; count<=right; count++) copyfields[count] = 1; while (isdigit(*blah)) blah++; } else { copyfields[left] = 1; } while (*blah == ',') blah++; } break; case 't': dotrunc=1; break; case 'd': deleted=1; break; case 'n': title=1; break; case 'p': types=1; break; case 'h': default: fprintf (stderr, "usage: dbf2ascii [-s separator] [-t] [-p] [-d] [-n] [-flist] file\n"); return 1; } } if (optind < argc && argv[optind][0] != '-') { if ((infile = fopen (argv[optind], "r")) == NULL) { fprintf (stderr, "error: cannot open `%s'\n", argv[optind]); return 6; } } if ((db = getdbf (infile)) == NULL) { return 2; } checkfields (stdout, db->fields); if (title) { showtitle (stdout, db->fields, deleted); } if (types) { showtypes (stdout, db->fields, deleted); } for (count=1; ; count++) { if ((c = readrecord (infile, db->fields, dotrunc)) == -1) break; if (c == -2) { fprintf (stderr, "error: unexpected EOF while reading record %d\n", count); return 5; } if (c == 0 || deleted) { dumprecord (stdout, db->fields, deleted, c, dotrunc); } } /* * done */ if (optind < argc && argv[optind][0] != '-') { fclose (infile); } killdbf (db); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -