/* cardread.c */ /* Copyright (C) 1994-2002 Norbert H. Doerry 28 May 2002 Version 1.4 Syntax: CARDREAD filename.crd -d -wXX -r"XX" -f"XX" -lXX -? -pXX -oXXXX -sXXX -nXX -ni -d : Set the debug flag -r"XX" : Set the record delimiting string to "XX" -f"XX" : Set the field delimiting string to "XX" -wXX : Set the number of characters allowed in a line before wrapping -? : Print help -lXX : Maximum number of lines per page (not counting new page string) -p"XX" : Set the new page string to "XX" -oXXXX : Set the output filename -sXXXX : Prints only the cards with indexes starting with these chars. Not Case Sensitive. If the first character is *, then prints only the cards with indexes containing these characters. -nXX : Prints the first XX lines of the cards -ni : Supresses printing the index This file reads the contents of a Windows 3.1 cardfile which only has text cards within it. The format for this file is: 00 'M' 01 'G' 02 'C' 03 Number of Cards 04 00 05 00 06 00 07 05 'Not sure what this means 08 00 09 00 0A 00 0B Low offset to first data field 0C High offset to first data field 0D 00 0E 00 0F 00 10-3E First Index Entry 1F Low offset to second data field 20 High offset to second data field 21 00 22 00 23 00 24-72 Second Index Entry Data field format relative to base address +00 00 +01 00 +02 Low length? 'Not always the case +03 High length? 'Not always the case +04 Start of data 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Version History 1.0 10 May 1994 1.1 15 May 1994 1.2 19 Feb 1996 added -n -ni flags, still need to fix the calculations for when to start a new page 1.3 16 Mar 1996 Fix the calculations for when to start a new page 1.4 28 May 2002 Added GNU license. Recompiled */ #include #include #include #include typedef struct CardFile { int nbr_cards; /* number of cards */ struct Card *crd; /* array of card structures */ FILE *in; /* Input file structure */ FILE *out; /* Output file structure */ char *filename; /* Input Filename */ char *outfile; /* Output Filename */ int debug; /* debug flag */ int wrap; /* characters used before wrapping */ char field_delimit[81]; /* characters used to delimit fields */ char record_delimit[81]; /* characters used to delimit records */ char newpage[81]; /* characters used to delimit new pages not including formfeed*/ int max_lines; /* maximum number of lines per page, if <= 0, then don't print the newpage */ int nbr_lines_2print; /* number of lines of each card to print */ int print_index; /* = 1 to print index = 0 to suppress */ int lines_per_field; /* number of newlines in field_delimit */ int lines_per_record; /* number of newlines in record_delimit */ int lines_per_newpage; /* number of newlines in new page */ char search_string[81]; /* search string (should be lower case) */ } CARDFILE; #define ALL_LINES -1 typedef struct Card { long offset; /* file offset for beginning of data */ char index[48]; /* index entry for the card */ char *data; /* data for the card */ int length; /* number of non-Null characters in data */ int nbr_fields; /* number of fields (including line wraps) */ int print_flag; /* = 0 for do not print, = 1 for printing */ } CARD; void cardfile_init(CARDFILE *); void cardfile_command(CARDFILE *,char *); int read_header(CARDFILE *); int read_card(CARDFILE *,int); void process_data(CARDFILE *); int print_card(CARDFILE *,int); void syntax_error(void); void cardread_help(void); void process_string(char *,char *); int main(int argc,char **argv) { CARDFILE cf; int i; int lcnt; int ncnt; /* initialize everything */ cardfile_init(&cf); /* process the command line entries */ for (i=1; i < argc ; i++) cardfile_command(&cf,argv[i]); /* check to ensure the file streams are correct */ if (cf.in == (FILE *) NULL) syntax_error(); if (cf.out == (FILE *) NULL) cf.out = stdout; /* read in the header */ if (read_header(&cf)) exit(3); /* read in all of the cards */ for (i=0;i< cf.nbr_cards; i++) read_card(&cf,i); /* perform updated processing*/ process_data(&cf); /* print the newpage stuff for the first page if necessary */ if (cf.max_lines > 0) fprintf(cf.out,"%s",cf.newpage); lcnt = 0; /* process each card, assume card is less than one page */ for (i=0;i< cf.nbr_cards; i++) { if (cf.crd[i].print_flag == 0) continue; /* skip cards which don't need printing */ ncnt = cf.lines_per_field * cf.crd[i].nbr_fields + cf.lines_per_record; if (lcnt + ncnt > cf.max_lines && cf.max_lines > 0 && lcnt > 0) { if (cf.max_lines > 0) fprintf(cf.out,"\f%s",cf.newpage); lcnt = ncnt; /* counter for number of lines printed per page */ } else { lcnt += ncnt; } print_card(&cf,i); } if (cf.in != stdin) fclose(cf.in); if (cf.out != stdout) fclose(cf.out); return 0; } void cardfile_init(CARDFILE *cf) { /* initialize the other variables */ cf->in = (FILE *) NULL; cf->out = (FILE *) NULL; cf->outfile = (char *) NULL; cf->filename = (char *) NULL; cf->debug = 0; cf->wrap = 40; strcpy(cf->field_delimit,"\n"); strcpy(cf->record_delimit,"\n\n-----------------------------\n"); strcpy(cf->newpage,"\n\n"); cf->max_lines = 55; cf->search_string[0] = (char) NULL; cf->nbr_lines_2print = ALL_LINES; cf->print_index = 1; } /* CARDREAD filename.crd -d -wXX -r"XX" -f"XX" -lXX -? -pXX -oXXXX */ void cardfile_command(CARDFILE *cf, char *cmd) { int value; int len; int i; /* check to see if a command or an input filename */ if (cmd[0] != '-') { /* input file */ if (cf->filename == (char *) NULL) { cf->filename = (char *) calloc(strlen(cmd)+1,sizeof(char)); strcpy(cf->filename,cmd); cf->in = fopen(cf->filename,"rb"); if (cf->in == (FILE *) NULL) { fprintf(stderr,"\n ***ERROR: Unable to open file %s (%s)\n", cmd,cf->filename); exit(1); } } else syntax_error(); } else if (cmd[1] == 'd') /* set the debug flag */ { cf->debug = 1; } else if (cmd[1] == 'w') /* set the linewrap flag */ { value = atoi(cmd+2); if (value > 0) cf->wrap = value; } else if (cmd[1] == 'r') /* set the record delimiting string */ { process_string(cf->record_delimit,cmd+2); if (cf->debug) printf("(%s) (%s)\n",cmd+2, cf->record_delimit); } else if (cmd[1] == 'f') /* set the field delimiting string */ { process_string(cf->field_delimit,cmd+2); if (cf->debug) printf("(%s) (%s)\n",cmd+2, cf->field_delimit); } else if (cmd[1] == 'l') /* set the maximum number of lines per page */ { value = atoi(cmd+2); cf->max_lines = value; } else if (cmd[1] == '?') /* help */ { cardread_help(); } else if (cmd[1] == 'p') /* set the new page string */ { process_string(cf->newpage,cmd+2); } else if (cmd[1] == 'o') /* set the output filename */ { if (cf->outfile == (char *) NULL) { cf->outfile = (char *) calloc(strlen(cmd),sizeof(char)); strcpy(cf->outfile,cmd+2); cf->out = fopen(cf->outfile,"wt"); if (cf->out == (FILE *) NULL) { fprintf(stderr,"\n ***ERROR: Unable to open file %s (%s)\n", cmd+2,cf->out); exit(1); } } else syntax_error(); } else if (cmd[1] == 's') /* set the search string */ { process_string(cf->search_string,cmd+2); /* convert to lower case */ for (i=0 ; cf->search_string[i] != (char) NULL ; i++) cf->search_string[i] = (char)tolower((int)cf->search_string[i]); if (cf->debug) printf("(%s) (%s)\n",cmd+2, cf->search_string); } else if (cmd[1] == 'n' && cmd[2] == 'i') cf->print_index = 0; else if (cmd[1] == 'n') /* set the number of lines to print */ { value = atoi(cmd+2); if (value >= 0) cf->nbr_lines_2print = value; } else syntax_error(); } int read_header(CARDFILE *cf) { int cnt; int icrd; int ch[12]; /* read the first 11 bytes of the file */ for (cnt=0 ; cnt < 11 ; cnt++) { ch[cnt] = fgetc(cf->in) & 0x00FF; if (feof(cf->in)) break; } /* if there weren't 11 bytes, then not the current file */ if (cnt < 11 || ch[0] != 'M' || ch[1] != 'G' || ch[2] != 'C') { fprintf(stderr,"\n ***ERROR: File '%s' not a text only cardfile\n", cf->filename); if (cf->debug) printf("<%c%c%c> cnt=%d (MGC,11)\n",ch[0],ch[1],ch[2],cnt); return 1; } cf->nbr_cards = ch[3]; if (cf->debug) printf(" Number of Cards = %d\n",cf->nbr_cards); /* if the number of entries less than 1, then have a problem */ if (cf->nbr_cards < 1) { fprintf(stderr,"\n ***ERROR: Number of cards (%d) is less than 1\n", cf->nbr_cards); return 1; } cf->crd = (CARD *) calloc((unsigned)cf->nbr_cards,sizeof(CARD)); if (cf->crd == (CARD *) NULL) { fprintf(stderr,"\n ***ERROR: Out of memory in read_header()\n"); return 1; } /* read in the card headers */ for (icrd = 0 ; icrd < cf->nbr_cards ; icrd++) { for (cnt = 0 ; cnt < 5 ; cnt++) { ch[cnt] = fgetc(cf->in) & 0x00FF; if (feof(cf->in)) { fprintf(stderr,"\n ***ERROR: Unexpected EOF in %s\n",cf->filename); return 1; } } cf->crd[icrd].offset = ch[0] + 256 * ch[1]; /* calculate the offset */ if (cf->debug) printf("offset %02X %02X :<%04lX> <%lu>\n",ch[0], ch[1], cf->crd[icrd].offset, cf->crd[icrd].offset & 0xFFFF); for (cnt = 0 ; cnt < 47 ; cnt++) { cf->crd[icrd].index[cnt] = (char)(fgetc(cf->in) & 0x00FF); if (feof(cf->in)) { fprintf(stderr,"\n ***ERROR: Unexpected EOF in %s\n",cf->filename); return 1; } } cf->crd[icrd].index[cnt] = (char) NULL; if (cf->debug) printf("Index %d:'%s'\n",icrd,cf->crd[icrd].index); } return 0; } int read_card(CARDFILE *cf,int icrd) { int ch; int chh[4]; int icnt = 0; /* move to the proper point in the file */ if (cf->debug) printf("cf->crd[%d].offset = %04X\n",icrd, cf->crd[icrd].offset); if (fseek(cf->in,cf->crd[icrd].offset,SEEK_SET)) { fprintf(stderr,"\n*** ERROR: Offset Error for card %d (%04X)\n", icrd,cf->crd[icrd].offset); return 1; } /* read in the card header data */ for (icnt = 0 ; icnt < 4 ; icnt++) { chh[icnt] = fgetc(cf->in) & 0xFF; if (feof(cf->in)) { fprintf(stderr,"\n ***ERROR: Unexpected EOF in %s\n",cf->filename); return 1; } } if (chh[0] != 0x00 || chh[1] != 0x00) { fprintf(stderr, "\n ***ERROR: Unexpected Characters in %s Data (%02X %02X)\n", cf->crd[icrd].index,chh[0],chh[1]); return 1; } cf->crd[icrd].length = chh[2] + 256 * chh[3] + 3;/* add 3 for insurance */ if (cf->debug) printf("icnt = %d , cf->crd[%d].length = %04x\n", icrd,icrd,cf->crd[icrd].length); /* allocate memory to hold the data */ cf->crd[icrd].data = (char *) calloc((unsigned) cf->crd[icrd].length, sizeof(char)); if (cf->crd[icrd].data == (char *) NULL) { fprintf(stderr,"\n ***ERROR: Out of memory in read_card()\n"); return 1; } /* read in until hit a NULL */ cf->crd[icrd].length = 0; /* start counting the characters for real */ while (1) { ch = (fgetc(cf->in)) & 0x00FF; if (feof(cf->in) != 0) { if (cf->debug) printf("EOF\n"); break; } if (ch == 0x0000) break; cf->crd[icrd].data[cf->crd[icrd].length++] = (char) ch; } cf->crd[icrd].data[cf->crd[icrd].length] = (char) NULL; if (cf->debug) printf("%2d (%d): '%s'\n",icrd,cf->crd[icrd].length,cf->crd[icrd].data); return 0; } void process_data(CARDFILE *cf) { int i,j,lc,nl; char buffer[81]; /* count the lines per field */ cf->lines_per_field = 0; for (i=0;cf->field_delimit[i] != (char) NULL ; i++) { if (cf->field_delimit[i] == '\n') cf->lines_per_field++; } if (cf->debug) printf("cf->lines_per_field =%d\n",cf->lines_per_field); /* count the lines per record */ cf->lines_per_record = 0; for (i=0;cf->record_delimit[i] != (char) NULL ; i++) { if (cf->record_delimit[i] == '\n') cf->lines_per_record++; } if (cf->debug) printf("cf->lines_per_record =%d\n",cf->lines_per_record); /* count the lines per newpage */ cf->lines_per_newpage = 0; for (i=0;cf->newpage[i] != (char) NULL ; i++) { if (cf->newpage[i] == '\n') cf->lines_per_newpage++; } if (cf->debug) printf("cf->lines_per_newpage =%d\n",cf->lines_per_newpage); /* process the individual cards */ for (j=0 ; j < cf->nbr_cards ; j++) { /* set the print flag */ if (cf->search_string[0] == (char) NULL) cf->crd[j].print_flag = 1; /* print all the cards */ else /* search string was specified */ { /* convert the index to lower case */ for (i=0 ;cf->crd[j].index[i] != (char) NULL ; i++) buffer[i] = (char) tolower((int)cf->crd[j].index[i]); buffer[i] = (char) NULL; if (cf->search_string[0] == '*') /* search for substrings */ { cf->crd[j].print_flag = (strstr(buffer,cf->search_string + 1) == (char *) NULL) ? 0 : 1; } else { cf->crd[j].print_flag = (strncmp(buffer,cf->search_string, strlen(cf->search_string))) ? 0 : 1; } } /* count the index entry if we will print it*/ if (cf->print_index != 0) cf->crd[j].nbr_fields = 1; else cf->crd[j].nbr_fields = 0; /* count the number of fields */ for (i=0,lc=0,nl=0; cf->crd[j].data[i] != 0x00; i++) { /* see if limited by the number of lines to print */ if (cf->nbr_lines_2print != 0 && nl >= cf->nbr_lines_2print) break; if (cf->crd[j].data[i] == '\n') /* check for the end of a line */ { lc = 0; /* reset the line character counter */ nl++; /* count the number of lines (without wraps) */ cf->crd[j].nbr_fields++; /* count the number of lines (with wraps) */ } else { lc++; /* count characters in the line */ } if (lc == cf->wrap) /* check for wrap */ { lc = 0; /* reset the line character counter */ cf->crd[j].nbr_fields++; /* count the number of lines (with wraps) */ } } if (cf->debug) printf("cf->crd[%d].nbr_fields = %d\n", j,cf->crd[j].nbr_fields); } } int print_card(CARDFILE *cf,int icrd) { int i; int lc; int clc; /* card line count */ fprintf(cf->out,"%s",cf->record_delimit); /* print the index entry */ if (cf->print_index != 0) fprintf(cf->out,"%s%s",cf->crd[icrd].index,cf->field_delimit); /* print the data */ for (i=0,lc=0,clc=0 ; cf->crd[icrd].data[i] != 0x00 ; i++) { if (clc == cf->nbr_lines_2print) break; if (cf->crd[icrd].data[i] == '\n') { lc = 0; /* reset the line ctr */ fprintf(cf->out,"%s",cf->field_delimit); clc++; continue; } else if (cf->crd[icrd].data[i] == '\r') continue; else { fprintf(cf->out,"%c",cf->crd[icrd].data[i]); lc++; } if (lc == cf->wrap) /* check for wrap */ { fprintf(cf->out,"%s",cf->field_delimit); lc = 0; } } return 0; } /* CARDREAD filename.crd -d -wXX -r"XX" -f"XX" -lXX -? -p"XX" -oXXXX */ void syntax_error(void) { fprintf(stderr,"\n ***SYNTAX ERROR: "); fprintf(stderr, "CARDREAD file.crd -d -wX -r\"X\" -f\"X\" -lX -p\"X\" -oX -sX\n"); fprintf(stderr," For HELP: CARDREAD -?\n"); exit(1); } void cardread_help(void) { printf("\n CARDREAD version 1.4 of %s\n",__DATE__); printf(" Norbert H. Doerry\n"); printf("\n SYNTAX: "); printf("CARDREAD file.crd -d -wX -r\"X\" -f\"X\" -lX -P\"X\" -oX -sX -nXX -ni\n"); printf(" d Set the Debug Flag\n"); printf(" wXX Set the number of characters before line wrapping\n"); printf(" r\"X\" Specify the string to delimit records\n"); printf(" f\"X\" Specify the string to delimit fields\n"); printf(" lXX Set the maximum number of lines on a page\n"); printf(" p\"X\" Specify the string to delimit pages\n"); printf(" oXX Specify the output filename\n"); printf(" sXX Prints only cards starting with XX\n"); printf(" s*X Prints cards containing the string X\n"); printf(" nXX Prints only the first XX fields of a record\n"); printf(" ni Do not print the index\n"); printf("\n"); exit(0); } void process_string(char *s1,char *s2) { char *st1,*st2,*stn; int i; for (st2=s2,st1=s1 ; *st2 != (char) NULL ; st2++,st1++) { if (*st2 != '\\') { *st1 = *st2; } else { st2++; if (*st2 == 'n') *st1 = '\n'; else if (*st2 == 'a') *st1 = '\a'; else if (*st2 == 'b') *st1 = '\b'; else if (*st2 == 'f') *st1 = '\f'; else if (*st2 == 'r') *st1 = '\r'; else if (*st2 == 't') *st1 = '\t'; else if (*st2 == 'v') *st1 = '\v'; else if (*st2 >= '0' && *st2 <= '7') /* octal digit */ { *st1 = (char) strtol(st2,&stn,8); st2 = stn-1; } else if (*st2 == 'x') { st2++; *st1 = (char) strtol(st2,&stn,16); st2 = stn-1; } else if (*st2 == (char) NULL) { break; } else { *st1 = *st2; } } } *st1 = (char) NULL; }