home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 328_02 / wfscanfm.c < prev    next >
C/C++ Source or Header  |  1991-03-17  |  7KB  |  334 lines

  1. /* wfscanfm.c
  2.  *         procedure: wfscanform(FILE *infile, WFORM *form, char *stopcode)
  3.  *
  4.  *    This procedure is a file-header parser.
  5.  *    Text files are read and each line is checked to see if
  6.  *    it matches an item in the WFORM table. If so, the data is
  7.  *    formatted and placed in the calling program's storage area
  8.  *    ...as indicated by the table.
  9.  *
  10.  *    The input file may be in the format:
  11.  *        KEYWORDdata\r\n
  12.  *        KEYWORDdata\r\n
  13.  *        STOPCODE\r\n
  14.  *    The KEYWORD may have a punctuation mark or whitespace at the end,
  15.  *        these are ignored for the purposes of comparison.
  16.  *        So the file may be in any of the following forms:
  17.  *        KEYWORD: filedata\r\n
  18.  *        KEYWORD:filedata\r\n
  19.  *        KEYWORD filedata\r\n
  20.  *        KEYWORD-filedata\r\n
  21.  *        KEYWORD$  filedata\r\n
  22.  *
  23.  *
  24.  *        ONLY 1 punctuation mark may be used as a delimiter,
  25.  *            but it doesn't have to be the same one each time.
  26.  *
  27.  *
  28.  *        in each of these cases, the data that will be returned
  29.  *              will be 'filedata' without the punctuation or leading space.
  30.  *
  31.  *    However, if no delimiter or space is indicated in the WFORM label,
  32.  *        then any delimiter found will be included in the data.
  33.  *
  34.  *    Data may continue to the next line if the last line is a + - or \
  35.  *        ex: col 0123456789....
  36.  *              KEYWORD: This is dat+\r\n
  37.  *              a for the program\r\n
  38.  *        will be read as This is data for the program.
  39.  *
  40.  *
  41.  *    Open the input file in either text or binary mode,
  42.  *        This routine actively ignores \n\r
  43.  *        and does not depend on fgets() to remove these codes.
  44.  *
  45.  *
  46.  *    If a KEYWORD is not found in the file, no values are moved to the
  47.  *        calling program's data area.
  48.  *
  49.  *    Input stops on FEOF or on an input line entirely contained in STOPCODE
  50.  *
  51.  *        OK if you specify STOPCODE as DATA: and the input line is DATA\r\n
  52.  *               or if the input line is DATA:\r\n and stopcode is just DATA
  53.  *            
  54.  *            ie: ok for a single punct. mark at end of stopcode or input line
  55.  *                for a header record, STOPCODE might be DATA: or DATA- or DATA
  56.  *
  57.  *    to display the KEYWORDdata information onscreen, use the same WFORM[]
  58.  *        and call WPRINTFORM ()
  59.  *    to create compatible file headers, use the same WFORM[]
  60.  *        and call WFPRINTFORM[]
  61.  *
  62.  *
  63.  *
  64.  *
  65.  */
  66.  
  67.  
  68. #include  "wsys.h"
  69.  
  70.  
  71. #define wftype wfspecial
  72.  
  73.  
  74.  
  75.  
  76. /* static function:
  77.  *    read input from infile,
  78.  *    piece together continuation lines,
  79.  *    check for stopcode.    RETURNS: zero if no more data to check.
  80.  */
  81. static int do_another(    FILE *infile, char *buffer,
  82.             int buffsize, char *stopcode );
  83.  
  84.  
  85.  
  86.  
  87.  
  88. void wfscanform ( FILE *infile, WFORM *form, char *stopcode )
  89.     {
  90.     char     *buffer;
  91.     WFORM     *item, *firstentry;
  92.     int      n, buffsize, lbl_len;
  93.     char     *data_ptr,
  94.         *userend;
  95.  
  96.  
  97.  
  98.     _NORMALIZE (form);
  99.  
  100.  
  101.  
  102.     firstentry = form;
  103.  
  104.     item = firstentry;
  105.  
  106.     /* scan form, fill in data types, figure out longest data element
  107.      */
  108.  
  109.  
  110.     for (     item = firstentry, buffsize = 0;
  111.         item->wflabel != NULL;
  112.         ++item
  113.         )
  114.         {
  115.         _NORMALIZE (item->wfuser);
  116.         _NORMALIZE (item->wflabel);
  117.         _NORMALIZE (item->wformat);
  118.  
  119.         /* find the longest piece of data (plus size of it's label
  120.          */
  121.  
  122.         n= strlen (item->wflabel) + item->wflen;
  123.         if ( buffsize < n )
  124.             {
  125.             buffsize = n;
  126.             }
  127.  
  128.  
  129.         /* check data type against supported types,
  130.          * move single char type into form table
  131.          */
  132.         item->wftype = *(item->wformat +
  133.                 strcspn ( item->wformat, "csidfegEGouxX") );
  134.  
  135.         } /* end for... scanning table ... */
  136.  
  137.  
  138.  
  139.  
  140.     buffsize += 256;    /* add enough to cover longest line */
  141.     buffer = wmalloc ( buffsize, "WFSCANFORM" );
  142.  
  143.  
  144.  
  145.     while ( do_another ( infile, buffer, buffsize, stopcode ) )
  146.         {
  147.         for ( item = firstentry; item-> wflabel != NULL; ++item )
  148.             {
  149.             lbl_len = strlen (item->wflabel);
  150.  
  151.             /* ignore punctuation marks and whitespace
  152.              * at the end of the label
  153.              */
  154.             while( --lbl_len &&
  155.                   ( ispunct( item->wflabel[ lbl_len ] )
  156.                   || isspace (item->wflabel[ lbl_len ] )
  157.                   )
  158.                  )
  159.                  { /* empty */
  160.                  }
  161.             ++lbl_len;
  162.  
  163.  
  164.  
  165.  
  166.             if (memicmp ( item->wflabel, buffer, lbl_len ) ==0 )
  167.                 {
  168.                 /* line in file matches line in form 
  169.                  */
  170.                 data_ptr = buffer + lbl_len;        /* pt past label */
  171.  
  172.                 /* skip whitespace and punctuation between label and data.
  173.                  */
  174.                 while ( ispunct( *data_ptr )  || isspace ( *data_ptr ) )
  175.                     {
  176.                     ++data_ptr;
  177.                     }
  178.  
  179.                 if ( *data_ptr == 0 )
  180.                     {
  181.                     /* skip NULL entry */
  182.                     }
  183.                 else
  184.                 if (item ->wfuser)            /* not a pure label, so get data */
  185.                     {
  186.                     /* update user data from buffer
  187.                      */
  188.                     switch ( item ->wftype )
  189.                         {
  190.                     case ( 'c' ):
  191.                         *((char*)item->wfuser)
  192.                             = *data_ptr;
  193.                         break;
  194.                     case ( 's' ):
  195.  
  196.                         memcpy(
  197.                         (char*)(item->wfuser),
  198.                            data_ptr,
  199.                            item->wflen  );
  200.  
  201.                         /* make sure string has a
  202.                          * terminal NULL
  203.                          */
  204.                         userend =((char*)item->wfuser)
  205.                               + (item->wflen)-1;
  206.  
  207.                         *userend = 0;
  208.  
  209.  
  210.                         break;
  211.                     default:
  212.                     sscanf (data_ptr,
  213.                             item->wformat,
  214.                                item->wfuser);
  215.                         }/* end switch */
  216.  
  217.                 /* end of updating */
  218.                     }    /* end non-NULL data */
  219.  
  220.                 }    /* end if... data matches from line */
  221.  
  222.             }    /* end for... item */
  223.         }    /* end while... infile */
  224.  
  225.     free (buffer);
  226.  
  227.     return;     /* wfscanform */
  228.     }
  229.  
  230.  
  231. /* do_another()
  232.  *    static routine that reads one line,
  233.  *    strips any DOS end-line characters,
  234.  *
  235.  *    concateneates next line if last line ended with a continuation mark.
  236.  *
  237.  *     RETURNS   0 if end of file or stopcode
  238.  *          1 if need to read more.
  239.  */
  240. static int do_another(    FILE *infile, char *buffer,
  241.             int buffsize, char *stopcode )
  242.     {
  243.  
  244.     int retcode;
  245.     int inlen;
  246.     int remaining;
  247.     int keep_going;
  248.     register int actual_inlen;
  249.     
  250.  
  251.  
  252.     inlen =0;
  253.     retcode = 1;
  254.  
  255.     do    {
  256.  
  257.         remaining = buffsize - inlen;
  258.  
  259.         fgets ( buffer + inlen, remaining, infile );
  260.  
  261.         if ( feof (infile) )
  262.             {
  263.             keep_going = retcode = 0;    /* don't do any more */
  264.             }
  265.         else
  266.             {
  267.  
  268.             /* strip any \n or \r or terminal spaces from end of string
  269.              *    (there may be two of these (\n and \r)
  270.              *    in either order
  271.              */
  272.             inlen = strlen (buffer) -1;
  273.             while ( inlen >0 && isspace(buffer[inlen]) )
  274.                 {
  275.                 --inlen;
  276.                 }
  277.  
  278.             /* is this a continuation line ?
  279.              */
  280.             switch ( buffer[inlen] )
  281.                 {
  282.                 case ('+'):
  283.                 case ('-'):
  284.                 case ('\\'):
  285.                     keep_going = 1;
  286.                     /* NOTE: by not advancing inlen, 
  287.                      * terminal NULL will be placed on the continuation mark.
  288.                      */
  289.                 default:
  290.                     keep_going = 0;
  291.  
  292.                     /* inlen now points to last letter,
  293.                      * move forward to terminal NULL
  294.                      */
  295.                     ++inlen;
  296.                 }
  297.  
  298.             /*  ensure that terminal NULL is in correct place.
  299.              */
  300.             buffer[inlen] = 0;
  301.  
  302.             }
  303.  
  304.  
  305.         }
  306.     while ( keep_going );        /* read continuation lines */
  307.     
  308.     /* now look for 'stopcode'.
  309.      * allow a punct. mark after stopcode, so check for actual length to compare
  310.      */
  311.     actual_inlen = inlen-1;        
  312.     if ( ispunct ( buffer[actual_inlen] ) )
  313.         {
  314.         inlen = actual_inlen;        
  315.         }
  316.  
  317.  
  318.     /* NOTE: must be memicmp, not stricmp, because of possibly shortened inlen
  319.      *     (see check for ispunct() above)
  320.      */
  321.     if ( memicmp( buffer, stopcode, inlen ) == 0 )
  322.         {
  323.         retcode =0;
  324.         }
  325.  
  326.  
  327.  
  328.  
  329.     return (retcode);    /* do_another */
  330.     }
  331.  
  332.  
  333. /*-------------------- end of wfscanform.c ----------------------*/
  334.