home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 12 / CD_ASCQ_12_0294.iso / vrac / csp0194b.zip / CSPLIT.C next >
C/C++ Source or Header  |  1994-01-17  |  24KB  |  830 lines

  1. /*
  2.  * CSplit.C
  3.  * This program is used to process source files for the purpose
  4.  * of transmission through a FidoNet (tm) echo in such a manner
  5.  * as to circumvent over-size message problems.
  6.  *
  7.  * This process is specified as follows:
  8.  *
  9.  * 1) a. Combine multiple source files
  10.  *    b. Split into 50-60 line sections
  11.  *    c. Add header and trailer markers
  12.  *       delimiting each section and file
  13.  * 2) a. Delete trailing whitespace
  14.  *    b. Replace tabs with spaces
  15.  *    c. Default to 4 spaces per tab
  16.  *    d. Allow user to specify alternate
  17.  *       number of spaces per tab
  18.  * 3) a. Wrap lines longer than 75 characters
  19.  *       long using the C "\ at the end of a
  20.  *       line" notation (using space break).
  21.  *    b. Wrapped lines will be followed by a
  22.  *       line with a single "\" character then
  23.  *       followed by the remainder of the line.
  24.  * 4) a. Calculate a CRC for each section and
  25.  *       include in the section trailer line
  26.  * 5) a. Provide a help display for program usage when
  27.  *       the program is executed without parameters
  28.  *
  29.  * Syntax:
  30.  *
  31.  * Extract:   CSPLIT  /x  infile
  32.  *
  33.  * Split:     CSPLIT  [/tn]  outfile  src.ext  [ ... ]
  34.  *
  35.  * Where:         n - For TAB expansion, the number of spaces to
  36.  *                    replace each TAB character (the default is 4)
  37.  *           infile - Name of file that contains the parts properly
  38.  *                    placed in consecutive order for extraction
  39.  *          outfile - Name of the output file(s).  The extension will
  40.  *                    be ignored if specified and each output file will
  41.  *                    be named such that the section number will be the
  42.  *                    extension (e.g., outfile.001, outfile.002, etc..)
  43.  *          src.ext - The first source file..etc  Wildcard filespecs are
  44.  *                    supported under non-ANSI compiling conditions.
  45.  *                    Filenames are limited to "8.3" string lengths to
  46.  *                    avoid separator line length problems.
  47.  *
  48.  * 08/31/93  Fred Cole  Original draft
  49.  * 09/05/93  FC         Added CRC calculation, fixed line wrap problem,
  50.  *                      added extraction ability, fixed a couple of bugs
  51.  * 09/14/93  FC         Added conditional compilation directives to
  52.  *                      allow non-ANSI, multi-compiler, filespec support
  53.  *                      Squashed extract() bug
  54.  * 11/21/93  Thad Smith Test for incomplete input file on extraction.
  55.  *                      Remove spaces added in message transmission.
  56.  *                      Default to 90 lines /section.
  57.  *                      Fix tab expansion.
  58.  * 12/03/93  FC         Fix file cleanup() bug.
  59.  * 12/09/93  Keith Campbell / TS
  60.  *                      Fix bug with options preceded by '-', fix
  61.  *                      tempfile opening bug, eliminate unused variables.
  62.  *                      Make sepcrc same type as crc.
  63.  * 01/02/94  david nugent / FC
  64.  *                      Additions for findfirst/findnext support for
  65.  *                      MSC6 (& 7) for OS/2 in initlist() routine
  66.  * 01/02/94  Auke Reitsma / FC
  67.  *                      Increased number of characters read in to prevent
  68.  *                      line numbers from becoming out-of-sync with input
  69.  * 01/12/94  Chad Wagner / FC
  70.  *                      Correction to initlist() function to eliminate
  71.  *                      the redundant line increment
  72.  *
  73.  * Donated to public domain
  74.  */
  75.  
  76. #include "csplit.h"
  77.  
  78. FILE *Fin  = NULL,  /* necessary evils - global variables */
  79.      *Fout = NULL,
  80.      *Ftmp = NULL;
  81. char tempfile[FNAME+1];
  82. SLST *head = NULL,
  83.      *cur  = NULL;
  84.  
  85. int main(int argc, char **argv)
  86. {
  87.   char *ext, line[81], outfile[FNAME+1], *s;
  88.   int  argndx = 1,
  89.        tab2spac = TABDEF,
  90.        lines_per_sect = LINES,
  91.        j, key, lines, curpart, maxpart, rc;
  92.   unsigned short crc;
  93.  
  94.   printf("\nCSplit - (pd) 1993 Revision %s by Fred Cole\n", VERSION);
  95.   puts("This executable program is in public domain.\n");
  96.  
  97.   if (('/' == argv[1][0]) || ('-' == argv[1][0]))
  98.   {
  99.     if ('x' == tolower(argv[1][1]))    /* if extract option */
  100.     {
  101.       if (argc < 3)
  102.       {
  103.         disp_help();
  104.         return(HELP);
  105.       }
  106.  
  107.       rc = extract(argv[2]);
  108.       cleanup();
  109.       return(rc);
  110.     }
  111.     else if ('t' == tolower(argv[1][1]))   /* if tab option */
  112.     {
  113.       tab2spac = atoi(&argv[1][2]);
  114.       if ((tab2spac < TABMIN) || (tab2spac > TABMAX))
  115.         tab2spac = TABDEF;
  116.       argndx++;
  117.     }
  118.   }
  119.  
  120.   if ((argc - argndx) < 2)
  121.   {
  122.     disp_help();
  123.     return(HELP);
  124.   }
  125.  
  126.   if (strlen(argv[argndx]) > FNAME)
  127.   {
  128.     printf("Output filename too long:  %s\n", argv[argndx]);
  129.     cleanup();
  130.     return(OUTFILE);
  131.   }
  132.  
  133.   strcpy(outfile, argv[argndx]);
  134.   if (NULL == (ext = strstr(outfile, ".")))  /* ignore any ext */
  135.     ext = &outfile[strlen(outfile)];
  136.  
  137.   *ext = 0;                         /* make temp file name */
  138.   strcpy(tempfile, outfile);
  139.   strcat(tempfile, ".$$$");
  140.  
  141.   if (NULL == (Ftmp = fopen(tempfile, "w+t")))
  142.   {
  143.     printf("Error creating temp file:  %s\n", tempfile);
  144.     cleanup();
  145.     return(PROCESS);
  146.   }
  147.  
  148.   if (NOERR != initlist(argc, argv, argndx+1))
  149.   {
  150.     cleanup();
  151.     return(MEMORY);
  152.   }
  153.  
  154.   for (cur = head, lines = 0; NULL != cur; cur = cur->next)
  155.   {
  156.     if (NULL == Fin)
  157.     {
  158.       if (NULL == (Fin = fopen(cur->srcfile, "rt")))
  159.       {
  160.         printf("Error opening source file:  %s\n", cur->srcfile);
  161.         cleanup();
  162.         return(INFILE);
  163.       }
  164.  
  165.       rc = fprintf(Ftmp, "%s%s%s%s\n",
  166.                    SEP_ID, SEP_BF, cur->srcfile, SEP_AR);
  167.  
  168.       if (0 == rc)
  169.       {
  170.         puts("Error writing output\n");
  171.         cleanup();
  172.         return(WRITE);
  173.       }
  174.       lines++;
  175.     }
  176.  
  177.     while (NULL != Fin)
  178.     {
  179.       /*
  180.        * The function my_fgets() is equivalent to fgets() in that it
  181.        * too reads n-1 characters or up to a newline character.  This
  182.        * function additionally expands TAB characters, deletes trailing
  183.        * whitespace and will wrap lines exceeding the specified length.
  184.        */
  185.       s = my_fgets(line, LENGTH, Fin, tab2spac);
  186.       if (NULL == s)
  187.       {
  188.         if (feof(Fin))
  189.         {
  190.           fclose(Fin);
  191.           Fin = NULL;
  192.           rc = fprintf(Ftmp, "%s%s%s%s\n",
  193.                        SEP_ID, SEP_EF, cur->srcfile, SEP_AR);
  194.           if (0 == rc)
  195.           {
  196.             puts("Error writing output\n");
  197.             cleanup();
  198.             return(WRITE);
  199.           }
  200.           lines++;   /* adjust line count */
  201.         }
  202.         else
  203.         {
  204.           puts("Error reading input\n");
  205.           cleanup();
  206.           return(READ);
  207.         }
  208.       } /* endif NULL string */
  209.       else
  210.       {
  211.         if (EOF == fputs(line, Ftmp))
  212.         {
  213.           puts("Error writing output\n");
  214.           cleanup();
  215.           return(WRITE);
  216.         }
  217.  
  218.         lines++; /* increment line count */
  219.       } /* endif non-NULL string */
  220.     } /*endwhile*/
  221.   } /*endfor*/
  222.  
  223.   if (lines < lines_per_sect)     /* if only one section */
  224.     maxpart = 1;
  225.   else
  226.   {
  227.     maxpart = lines / lines_per_sect;
  228.  
  229.     if (lines % lines_per_sect < 5)/* if < 5 lines in last section */
  230.     {
  231.       lines_per_sect--;           /* decrement lines per section */
  232.       maxpart = lines / lines_per_sect;
  233.     }
  234.  
  235.     if ((maxpart > 0) &&          /* why can't those go on one line? */
  236.         (lines % lines_per_sect > 0))
  237.       maxpart++;                  /* perform ceil function */
  238.   }
  239.  
  240.   curpart = 1;
  241.  
  242.   /* warn user if 1st output filename already in use */
  243.   sprintf(ext, ".%03.3d", curpart); /* make 1st output file name */
  244.   if (NULL != (Fout = fopen(outfile, "rt")))
  245.   {
  246.     key = 0;
  247.     printf("Output file already exists:  %s\n", outfile);
  248.     do
  249.     {
  250.       printf("Overwrite? (y/n) ");
  251.       key = getchar();
  252.       puts("");
  253.       j = key;
  254.       while (j != '\n')
  255.         j = getchar();  /* eat all extra keystrokes */
  256.       if (('n' == key) || ('N' == key))
  257.       {
  258.         cleanup();
  259.         return(OUTFILE);
  260.       }
  261.     } while (('y' != key) && ('Y' != key));
  262.     fclose(Fout);
  263.     Fout = NULL;
  264.   }
  265.  
  266.   if (NULL == freopen(tempfile, "rt", Ftmp))
  267.   {
  268.     printf("Error reopening temp file:  %s\n", tempfile);
  269.     cleanup();
  270.     return(PROCESS);
  271.   }
  272.  
  273.   initcrctab();
  274.  
  275.   while (NULL != Ftmp)
  276.   {
  277.     if (NULL == Fout)
  278.     {
  279.       sprintf(ext, ".%03.3d", curpart); /* make output file name */
  280.       if (NULL == (Fout = fopen(outfile, "w+t")))
  281.       {
  282.         printf("Error opening output file:  %s\n", outfile);
  283.         cleanup();
  284.         return(OUTFILE);
  285.       }
  286.       rc = fprintf(Fout, "%s%s%d/%d%s\n",
  287.                    SEP_ID, SEP_BP, curpart, maxpart, SEP_AR);
  288.       if (0 == rc)
  289.       {
  290.         puts("Error writing output\n");
  291.         cleanup();
  292.         return(WRITE);
  293.       }
  294.     }
  295.  
  296.     crc = 0;
  297.     lines = 0;
  298.  
  299.     while ((lines < lines_per_sect) && (NULL != Ftmp))
  300.     {
  301.       s = fgets(line, 80, Ftmp);
  302.       if (NULL == s)
  303.       {
  304.         if (feof(Ftmp))
  305.         {
  306.           fclose(Ftmp);
  307.           Ftmp = NULL;
  308.         }
  309.         else
  310.         {
  311.           puts("Error reading input\n");
  312.           cleanup();
  313.           return(READ);
  314.         }
  315.       } /*endif NULL string*/
  316.       else
  317.       {
  318.         crc = updcrc(crc, (unsigned char *)line, strlen(line));
  319.         if (EOF == fputs(line, Fout))
  320.         {
  321.           puts("Error writing output\n");
  322.           cleanup();
  323.           return(WRITE);
  324.         }
  325.  
  326.         lines++; /* increment line count */
  327.  
  328.       } /*endif non-NULL string*/
  329.     } /*endwhile*/
  330.  
  331.  
  332.     if (0 == fprintf(Fout, "%s%s%d/%d  crc: %04x %s\n",
  333.                      SEP_ID, SEP_EP, curpart, maxpart, crc, SEP_AR))
  334.     {
  335.       puts("Error writing output\n");
  336.       cleanup();
  337.       return(WRITE);
  338.     }
  339.  
  340.     fclose(Fout);
  341.     Fout = NULL;
  342.     curpart++;
  343.  
  344.   } /*endwhile*/
  345.  
  346.   cleanup();
  347.   return(NOERR);
  348. }
  349.  
  350. /*
  351.  * cleanup() - Just a convenient way to provide housekeeping
  352.  *             for all the places the code returns from main.
  353.  */
  354. void cleanup(void)
  355. {
  356.   freelist();
  357.   if (NULL != Fin)  fclose(Fin);
  358.   if (NULL != Fout) fclose(Fout);
  359.   if (NULL != Ftmp) fclose(Ftmp);
  360.   if (NULL != (Ftmp = fopen(tempfile, "rt")))
  361.   {
  362.     fclose(Ftmp);
  363.     remove(tempfile);
  364.   }
  365. }
  366.  
  367. void disp_help(void)
  368. {
  369.   puts("This utility is used to process source files for the purpose");
  370.   puts("of transmission through a FidoNet (tm) echo in such a manner");
  371.   puts("as to circumvent over-size message problems.\n");
  372.   puts("Syntax:\n");
  373.   puts("Extract:  CSPLIT  /x  infile\n");
  374.   puts("Split:    CSPLIT  [/tn]  outfile  src.ext  [ ... ]\n");
  375.   puts("Where:         n - For TAB expansion, the number of spaces to");
  376.   puts("                   replace each TAB character (defaults to 4)");
  377.   puts("          infile - File name that contains the parts properly");
  378.   puts("                   placed in consecutive order for extraction");
  379.   puts("         outfile - Name of the output file(s).  The extension");
  380.   puts("                   will be the sequential section/part number");
  381.   puts("                   (e.g., outfile.001, outfile.002, etc. ...)");
  382. #if !defined(__STDC__)
  383.   puts("         src.ext - Source file(s)..etc.  (w/wildcard support)");
  384. #else
  385.   puts("         src.ext - Source file(s)..etc. (no wildcard support)");
  386. #endif
  387. }
  388.  
  389. int extract(char *ifn)
  390. {
  391.   static char line[(LENGTH+1)*2], line2[(LENGTH+1)*2];
  392.   char outfile[FNAME+1], *s;
  393.   int  i, in_section, key, lines,
  394.        curpart, maxpart, pos_wrap,
  395.        sepmax, seppart,
  396.        sep_id_len = strlen(SEP_ID);
  397.   unsigned short crc, sepcrc;
  398.  
  399.   if (NULL == (Fin = fopen(ifn, "rt")))
  400.   {
  401.     printf("Error opening input file:  %s\n", ifn);
  402.     return(INFILE);
  403.   }
  404.  
  405.   crc = curpart = maxpart = lines = 0;
  406.   in_section = pos_wrap = FALSE;
  407.   Fout = NULL;
  408.   initcrctab();
  409.   *line2 = 0;
  410.  
  411.   while (NULL != Fin)
  412.   {
  413.     s = fgets(line, LENGTH*2, Fin);   /* increase input size */
  414.                                       /* Auke Reitsma */
  415.  
  416.     /* TS: eliminate any added trailing spaces */
  417.     for (i=strlen(s)-1; i && line[i-1] == ' '; i--) continue;
  418.     line[i]   = '\n';
  419.     line[i+1] = '\0';
  420.  
  421.     lines++;
  422.  
  423.     if (NULL == s)
  424.     {
  425.       if (feof(Fin))              /* end of file */
  426.       {
  427.         fclose(Fin);
  428.         Fin = NULL;
  429.       }
  430.       else
  431.       {
  432.         if (lines)  printf("(line %d) ", lines);
  433.         printf("Error reading from input file:  %s\n", ifn);
  434.         return(READ);
  435.       }
  436.     } /*endif NULL string*/
  437.     else                          /* process line */
  438.     {
  439.       if (line == (strstr(line , SEP_ID)))  /* if separator line */
  440.       {
  441.         s = line + sep_id_len;
  442.  
  443.         if (s == strstr(s, SEP_BF))    /* if begin file */
  444.         {
  445.           if (NULL != Fout)
  446.           {
  447.             printf("(line %d) ", lines);
  448.             puts("Error: encountered 2nd \"Begin file\" separator");
  449.             puts("before \"End file\" separator\n");
  450.             return(PROCESS);
  451.           }
  452.  
  453.           s += strlen(SEP_BF);
  454.           if (1 != sscanf(s, "%s", outfile))
  455.           {
  456.             printf("(line %d) ", lines);
  457.             puts("Error reading separator line\n");
  458.             return(PROCESS);
  459.           }
  460.  
  461.           if (NULL != (Fout = fopen(outfile, "rt")))
  462.           {
  463.             key = 0;
  464.             printf("Output file already exists:  %s\n", outfile);
  465.             do
  466.             {
  467.               printf("Overwrite? (y/n) ");
  468.               key = getchar();
  469.               puts("");
  470.               i = key;
  471.               while (i != '\n')
  472.                 i = getchar();  /* eat all extra keystrokes */
  473.  
  474.               if (('n' == key) || ('N' == key))
  475.                 return(OUTFILE);
  476.  
  477.             } while (('y' != key) && ('Y' != key));
  478.             if (NULL == freopen(outfile, "wt", Fout))
  479.             {
  480.               printf("Error opening file for output:  %s\n", outfile);
  481.               return(OUTFILE);
  482.             }
  483.           }
  484.           else
  485.           {
  486.             if (NULL == (Fout = fopen(outfile, "wt")))
  487.             {
  488.               printf("Error opening file for output:  %s\n", outfile);
  489.               return(OUTFILE);
  490.             }
  491.           }
  492.  
  493.           crc = updcrc(crc, (unsigned char *)line, strlen(line));
  494.         }
  495.         else if (s == strstr(s, SEP_EF))    /* if end file */
  496.         {
  497.           if (NULL == Fout)
  498.           {
  499.             printf("(line %d) ", lines);
  500.             puts("Error: encountered \"End file\" separator");
  501.             puts("before \"Begin file\" separator\n");
  502.             return(PROCESS);
  503.           }
  504.  
  505.           if (fclose(Fout))
  506.           {
  507.             printf("Error closing output file:  %s\n", outfile);
  508.             return(OUTFILE);
  509.           }
  510.  
  511.           Fout = NULL;
  512.           crc = updcrc(crc, (unsigned char *)line, strlen(line));
  513.         }
  514.         else if (s == strstr(s, SEP_BP))    /* if begin part */
  515.         {
  516.           if (in_section)
  517.           {
  518.             printf("(line %d) ", lines);
  519.             puts("Error: encountered 2nd \"Begin part\" separator");
  520.             puts("before \"End part\" separator\n");
  521.             return(PROCESS);
  522.           }
  523.  
  524.           s += strlen(SEP_BP);
  525.           if (2 != sscanf(s, "%d/%d", &seppart, &sepmax))
  526.           {
  527.             printf("(line %d) ", lines);
  528.             puts("Error reading separator line\n");
  529.             return(PROCESS);
  530.           }
  531.           if (0 == maxpart)  maxpart = sepmax;
  532.           if (maxpart != sepmax)
  533.           {
  534.             printf("(line %d) ", lines);
  535.             puts("Error reading separator line\n");
  536.             return(PROCESS);
  537.           }
  538.           if (curpart+1 != seppart)
  539.           {
  540.             printf("(line %d) ", lines);
  541.             puts("Error: section(s) missing or out-of-order\n");
  542.             return(PROCESS);
  543.           }
  544.           in_section = TRUE;
  545.           curpart++;
  546.         }
  547.         else if (s == strstr(s, SEP_EP))    /* if end part */
  548.         {
  549.           if (!in_section)
  550.           {
  551.             printf("(line %d) ", lines);
  552.             puts("Error: encountered 2nd \"End part\" separator");
  553.             puts("before \"Begin part\" separator\n");
  554.             return(PROCESS);
  555.           }
  556.           s += strlen(SEP_EP);
  557.           s = strstr(s, ": ");
  558.           if (1 != sscanf(s+2, "%x", &sepcrc))
  559.           {
  560.             printf("(line %d) ", lines);
  561.             puts("Error reading separator line\n");
  562.             return(PROCESS);
  563.           }
  564.           if (crc != sepcrc)
  565.           {
  566.             printf("(line %d) ", lines);
  567.             puts("CRC error\n");
  568.             return(PROCESS);
  569.           }
  570.           crc = 0;
  571.           in_section = FALSE;
  572.         }
  573.         else
  574.         {
  575.           printf("(line %d) ", lines);
  576.           puts("Error reading separator line\n");
  577.           return(PROCESS);
  578.         }
  579.       }
  580.       else                        /* else process data line */
  581.       {
  582.         if (in_section)           /* save only file data */
  583.         {
  584.           crc = updcrc(crc, (unsigned char *)line, (i = strlen(line)));
  585.  
  586.           if (pos_wrap)           /* if possible line wrap in progress */
  587.           {
  588.             if (0 == strcmp(line, "\\\n"))  /* if wrapped line */
  589.             {
  590.               strcpy(line, line2);
  591.               line[strlen(line)-2] = 0;     /* remove wrap EOL */
  592.             }
  593.             else
  594.             {
  595.               strcat(line2, line);
  596.               strcpy(line, line2);
  597.             }
  598.             pos_wrap = FALSE;
  599.           }
  600.           else  if ('\\' == line[i-2]) /* if possible wrapped line */
  601.           {
  602.             strcpy(line2, line);
  603.             pos_wrap = TRUE;
  604.           }
  605.  
  606.           if ((FALSE == pos_wrap) &&
  607.               ((NULL == Fout) || (EOF == fputs(line, Fout))))
  608.           {
  609.             puts("Error writing output\n");
  610.             return( NULL == Fout ? PROCESS : WRITE );
  611.           }
  612.         }
  613.       }
  614.     } /*endif non-NULL string*/
  615.   } /*endwhile*/
  616.  
  617.   /* TS: Test for incompete processing. */
  618.   if (in_section) {
  619.     printf ("Error on end of input when processing section %d of %d\n",
  620.              seppart, sepmax);
  621.     return (PROCESS);
  622.   }
  623.   if (seppart != sepmax) {
  624.     printf ("Error on end of input after processing section %d of %d\n",
  625.              seppart, sepmax);
  626.     return (PROCESS);
  627.   }
  628.  
  629.   return(NOERR);
  630. }
  631.  
  632. /*
  633.  * my_fgets() - A custom fgets() function that additionally
  634.  *              expands tabs and deletes trailing whitespace.
  635.  */
  636. char *my_fgets(char *s, int len, FILE * fp, int tabsiz)
  637. {
  638.   static char sbuf[2048] = "",    /* big enough for many TAB chars */
  639.               *beg = sbuf;
  640.   static int  wrap = FALSE;
  641.  
  642.   char *e, *w, *p = s, *q;
  643.   int ch = 0, cnt = 0, i, spaces;
  644.  
  645.   if (TRUE == wrap)               /* if line wrap */
  646.   {
  647.     strcpy(s, "\\\n");
  648.     wrap = FALSE;
  649.     return(s);
  650.   }
  651.  
  652.   while ((cnt < len-1) && ('\n' != ch))
  653.   {                                    /* get next char from buffer */
  654.     if (0 == (ch = *beg++))            /* if buffer empty */
  655.     {
  656.       beg = fgets(sbuf, 1024, fp);     /* grab another string */
  657.       if (NULL == beg)                 /* if end of file */
  658.       {
  659.         beg = sbuf;
  660.         *beg = 0;
  661.         if (0 == cnt)  return(NULL);   /* and buffer empty */
  662.       }
  663.       else
  664.       {
  665.         w = e = &sbuf[i = strlen(sbuf)]; /* find 1st trailing ws char */
  666.         while ((w > sbuf) && (isspace(*(w-1))))
  667.           w--;
  668.  
  669.         if (('\n' == *(e-1)) ||   /* if terminated w/newline char */
  670.             (i < (len-1)))        /* or unterminated short line */
  671.           *w++ = '\n';            /* terminate with newline char */
  672.  
  673.         *w = 0;
  674.         ch = *beg++;
  675.       }
  676.     } /*endif buffer empty*/
  677.  
  678.     if (ch == '\t')               /* if TAB character */
  679.     {                             /* space to next tab stop */
  680.       /* TS: The following code has been changed to pad to the next
  681.       ** tab stop, rather than insert a fixed number of spaces.     */
  682.       spaces = tabsiz - ((int)(beg - sbuf) - 1) % tabsiz;
  683.       memmove(beg + spaces -1, beg, strlen(beg)+1);
  684.       for (q = beg-1; spaces > 0; spaces--)
  685.         *q++ = ' ';
  686.       ch = ' ';                   /* change character to space */
  687.     }
  688.  
  689.     *p++ = (char) ch;             /* update output string */
  690.     cnt++;
  691.  
  692.     if ((cnt == len-1) && ('\n' != ch))     /* if need to wrap line */
  693.     {
  694.       beg -= 2;                   /* make room for "\\\n" characters */
  695.       e = beg;
  696.       p -= 2;
  697.       q = p;
  698.  
  699.       /* unget characters to 1st previous space */
  700.       while ((e > sbuf) && (' ' != *(e-1)))
  701.       {
  702.         q--;
  703.         e--;
  704.       }
  705.  
  706.       if (e != sbuf)              /* if wrap on space char */
  707.       {                           /* ( else wrap asis ) */
  708.         p = q;
  709.         beg = e;
  710.       }
  711.  
  712.       *p++ = '\\';                /* terminate current line */
  713.       *p++ = '\n';
  714.       wrap = TRUE;                /* flag wrap line pending */
  715.     } /*endif line wrap*/
  716.   } /*endwhile*/
  717.  
  718.   *p = 0;
  719.   return(s);
  720. }
  721.  
  722. /*
  723.  * CRC-16f.c, from Snippets.  Calculate, intelligently, the CRC
  724.  * of a dataset incrementally given a buffer full at a time.
  725.  * Initialize crc to 0 for XMODEM, -1 for CCITT.
  726.  */
  727.  
  728. /* P, the CRC polynomial, is used by XMODEM (almost CCITT).
  729.  * If you change P, you must change crctab[]'s initial value
  730.  * to what is printed by initcrctab().
  731.  */
  732. #define  P 0x1021
  733. #define  W 16       /* number of bits in CRC: don't change it */
  734. #define  B 8        /* number of bits per char: don't change it */
  735.  
  736. unsigned short crctab[1<<B];
  737.  
  738. unsigned short updcrc( unsigned short icrc,
  739.                        unsigned char *icp,
  740.                        unsigned int   icnt )
  741. {
  742.   register unsigned short crc = icrc;
  743.   register unsigned char *cp = icp;
  744.   register unsigned int cnt = icnt;
  745.  
  746.   while( cnt-- )
  747.     crc = (crc<<B) ^ crctab[(crc>>(W-B)) ^ *cp++];
  748.  
  749.   return( crc );
  750. }
  751.  
  752. void initcrctab()
  753. {
  754.   register b, v, i;
  755.  
  756.   for( b = 0; b <= (1<<B)-1; ++b )
  757.   {
  758.     for( v = b<<(W-B), i = B; --i >= 0; )
  759.       v = v&0x8000 ? (v<<1)^P : v<<1;
  760.  
  761.     crctab[b] = v;
  762.   }
  763. }
  764.  
  765. SLST *addlist(char *fname)
  766. {
  767.   SLST *new = NULL;
  768.  
  769.   if (strlen(fname) > FNAME)
  770.     printf("Input file argument too long:  %s\n", fname);
  771.   else  if (NULL == (new = (SLST *)malloc(sizeof(SLST))))
  772.     puts("Error allocating memory.\n");
  773.   else
  774.   {
  775.     strcpy(new->srcfile, fname);
  776.     new->next = NULL;
  777.  
  778.     if (NULL == cur)  head = new;
  779.     else  cur->next = new;
  780.   }
  781.   cur = new;
  782.   return(cur);
  783. }
  784.  
  785. void freelist(void)
  786. {
  787.   while (NULL != head)
  788.   {
  789.     cur = head->next;
  790.     free(head);
  791.     head = cur;
  792.   }
  793. }
  794.  
  795. /*
  796.  * This function creates a linked list of input source files.
  797.  * Wildcard specifications are accommodated when ANSI mode is
  798.  * not in effect.
  799.  */
  800. int initlist(int argc, char **argv, int argo)
  801. {
  802.   int i;
  803.  
  804.   for (i = argo; i < argc; i++)            /* process CL arguments */
  805.   {
  806. #if !defined(__STDC__)
  807.     int done;
  808.     DOSFileData fd;
  809.     done = FIND_FIRST(argv[i], 0x20, &fd);
  810.     if (done)
  811.     {
  812.       printf("Error with filespec: %s\n", argv[i]);
  813.       return(PROCESS);
  814.     }
  815.     while (!done)
  816.     {
  817.       if (NULL == addlist(ff_name(&fd)))   /* david nugent */
  818.         return(MEMORY);
  819.       done = FIND_NEXT(&fd);
  820.     }
  821.     FIND_END(&fd);                         /* david nugent */
  822. #else
  823.     if (NULL == addlist(argv[i]))
  824.       return(MEMORY);
  825. #endif
  826.   }
  827.   return(NOERR);
  828. }
  829.  
  830.