/* db_dump.c - Routines for reading dBase III files Copyright (c) 1995 Martin Schulze This file is part of the dbview package, a viewer for dBase II files. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Most of the code in this file comes from Greg Twaites anno 87. I only took the file and wrote a program around it. I enclude the whole header. I have obtained this file from a free software archive, namely nic.funet.fi. ftp://nic.funet.fi/pub/msdos/languages/c/dbase.c */ /* * These functions are used to read dbase files. * * These functions are provided by Valour Software as a gift. * * The program is for test purposes only. No warranty is expressed nor * implied. USE AT YOUR OWN RISK! * * Fri Jun 21 19:30:44 1996: Martin Schulze * Fixed a bug which causes dbview to eat a character at the end * of beginning of a line. Thanks to Chris Childs * for submitting a patch. * * Thu Sep 26 21:38:33 1996: Martin Schulze * Modified on some places based on corrections from Vladimir * Michl * */ #include "db_dump.h" #include #include #include #include #include #include #include #include DBASE_HEAD dbhead={0}; FLD_LIST *db_fld_root=0; char *Buffer; char buf_work[255]; int dbfile; /*------------------------------------------------------------code-------*/ void db3_process(dbfn, flags, delim) char *dbfn; int flags; char delim; { dbfile=open(dbfn,O_RDONLY); if (dbfile == -1) { printf("Unable to open file `%s'\n", dbfn); return; } db3_read_dic(flags); if ( ! (flags & DB_FL_OMIT)) db3_print_recs(dbhead.count, flags, delim); close(dbfile); } /****************************************************** db3_rm_ld_spc() This function removes leading space characters and returns a new string; ******************************************************/ char * db3_rm_ld_spc (var) char *var; { static char rvar[257]; /* dBase fields can only * be 256 byts long, max. */ char *c; bzero (rvar, sizeof(rvar)); for (c=var; isspace (*c); c++); strcpy(rvar, c); return rvar; } /****************************************************** db3_rm_tr_spc() This function removes trailing space characters and returns a new string; ******************************************************/ char * db3_rm_tr_spc (var) char *var; { char *c=var; for (c+=strlen(var)-1; isspace (*c); c--); *(++c) = '\0'; return var; } /****************************************************** db3_cvt_fld() This function is called with a valid db3 field specifier. It will convert the fieldname into a more friendly look. This is done by tr '_' ' ' and tr [:upper:] [:lower:]. ******************************************************/ void db3_cvt_fld (fld) DBASE_FIELD *fld; { char *c; char first=1; for (c=fld->name; *c; c++) if (!first) { if (isupper(*c)) *c = tolower(*c); else if (*c == '_') { *c = ' '; first = 1; } first = 0; } else first = 0; } /****************************************************** db3_read_dic() This function is called with a file name to read to create a record type to support the dbase file ******************************************************/ void db3_read_dic(flags) int flags; { int fields; char *info; char *lang; char *cdx; DBASE_FIELD *fld; if(dbfile==-1) { printf("open failed"); return; } read(dbfile,&dbhead,sizeof(DBASE_HEAD)); if ( ! ( dbhead.version==0x03 || dbhead.version==0x83 || dbhead.version==0x04 || dbhead.version==0x05 || dbhead.version==0x8b || dbhead.version==0xf5 ) ) { printf ("Version %d not supported\n",dbhead.version); if (dbhead.version==0x8e ) { printf ("dBase IV or dBase V with SQL table - partially known...\n"); } if (dbhead.version==0x43 || dbhead.version==0xb3){ printf ("FlagShip - partially known...\n"); } return; } if (dbhead.version==0x03){ info="Plain dbf, dBaseIII+"; } if (dbhead.version==0x04){ info="Plain dbf, dBaseIV+"; } if (dbhead.version==0x05){ info="Plain dbf, dBaseV or FoxPro"; } if (dbhead.version==0x83){ info="dBaseIII+ w/memo"; } if (dbhead.version==0x8b){ info="dBaseIV+ w/memo"; } if (dbhead.version==0xf5){ info="FoxPro w/memo"; } fields=(dbhead.header-1)/32-1; if (dbhead.excdx){ cdx="Yes"; } else{ cdx="No"; } if (dbhead.language==101){ lang="DOS 866"; } else if (dbhead.language==2){ lang="WIN 1251"; } else if (dbhead.language==2){ lang="DOS 850 Multi ling"; } else if (dbhead.language==1){ lang="DOS 437 USA"; } else{ lang="Unknown"; } if (flags & DB_FL_INFO) { printf("File version : %d, %s\n",dbhead.version,info); printf("Last update : %02d/%02d/%2d\n", dbhead.l_update[1],dbhead.l_update[2],dbhead.l_update[0]+1900); printf("Number of recs : %ld\n",dbhead.count); printf("Header length : %d\n",dbhead.header); printf("Record length : %d\n",dbhead.lrecl); printf("Exist index cdx : %s\n",cdx); printf("Language ID : %s\n",lang); printf("Count fields : %d\n\n",fields); } Buffer=malloc(dbhead.lrecl); if (flags & DB_FL_DESCR) { printf("Field Name\tType\tLength\tDecimal Pos\n"); } while(fields--) { fld=(DBASE_FIELD *)malloc(sizeof(DBASE_FIELD)); if (!fld) { printf ("Not enough memory\n"); return; } read(dbfile,fld,sizeof(DBASE_FIELD)); if (! (flags & DB_FL_RESERVE)) db3_cvt_fld (fld); if (flags & DB_FL_DESCR) { printf("%-10s\t %c\t %3d\t %3d\n", fld->name, fld->type, fld->length,fld->dec_point); } stack_field(fld); } read(dbfile,Buffer,1); /* read the silly little \r 0x0d character */ #ifdef I_USE_A_LAME_OS_LIKE_DOS read(dbfile,Buffer,1); /* strange, it only works if we read another byte */ #endif return; } /****************************************************** db3_print_recs() Read records and print the data ******************************************************/ void db3_print_recs(cnt, flags, delim) int cnt; int flags; char delim; { int bytes; lseek(dbfile,dbhead.header,SEEK_SET); while(cnt) { bytes=read(dbfile,Buffer,dbhead.lrecl); if(bytes!=dbhead.lrecl) break; /* Check if deleted == '*' */ if(Buffer[0]==' ') { db3_print(flags, delim); cnt--; } } return; } /****************************************************** db3_print() Print a single record ******************************************************/ void db3_print(flags, delim) int flags; char delim; { FLD_LIST *temp; temp=db_fld_root; while (temp) { memcpy(buf_work,temp->data,temp->fld->length); buf_work[temp->fld->length] = '\0'; if (flags & DB_FL_BROWSE) if (flags & DB_FL_TRIM) printf("%s%c",db3_rm_tr_spc(db3_rm_ld_spc(buf_work)), delim); else printf("%s%c",buf_work, delim); else printf("%-11s: %s\n",temp->fld->name,db3_rm_tr_spc(db3_rm_ld_spc(buf_work))); temp=temp->next; } printf("\n"); return; } /****************************************************** stack_field() Add a field to the linked list of fields ******************************************************/ void stack_field(fld) DBASE_FIELD *fld; { FLD_LIST *list, *temp; list=(FLD_LIST *)calloc(1,sizeof(FLD_LIST)); if (!list) { printf ("Not enough memory\n"); return; } list->fld=fld; if(!db_fld_root) { list->data=Buffer+1; /*skip delete byte*/ db_fld_root=list; return; } temp=db_fld_root; while(temp->next) temp=temp->next; temp->next=list; list->data=temp->data + temp->fld->length; return; }