home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / tools / formatte / cpr / cpr.c next >
C/C++ Source or Header  |  1986-07-08  |  20KB  |  859 lines

  1. /*
  2.  *    This program prints the files named in its argument list, preceding
  3.  *    the output with a table of contents. Each file is assumed to be C
  4.  *    source code (but doesn't have to be) in that the program searches
  5.  *    for the beginning and end of functions. Function names are added to
  6.  *    the table of contents, provided the name starts at the beginning of
  7.  *    a line. The function name in the output is double striken. White space
  8.  *    is inserted after every terminating '}' character. Thus functions
  9.  *    and structure declarations are nicely isolated in the output. The only
  10.  *    drawback to this is that structure initialization tables sometimes
  11.  *    produce large quantities of white space.
  12.  *
  13.  *    Try it! You'll like it. (I call it cpr.c)
  14.  *
  15.  *    written by: Paul Breslin
  16.  *            Human Computing Resources Corp.
  17.  *            10 St. Mary St.
  18.  *            Toronto, Ontario
  19.  *            Canada, M4Y 1P9
  20.  *
  21.  *            decvax!utcsrgv!hcr!phb
  22.  */
  23.  
  24. /*
  25.  *    The following options have been added.  The `-n' option is used
  26.  *    to number source lines.  Numbering starts at 1 (one) and is reset
  27.  *    to this number for each file.  The `-o' option is used to put 1
  28.  *    (one) function on each page instead of multiple functions per page.
  29.  *    Line folding has been added.
  30.  *
  31.  *    The `-l' option has been changed so that the blank space between
  32.  *    it and the following number has been eliminated. ("-l60" instead
  33.  *    of "-l 60")
  34.  *
  35.  *    modified by:  Lance E. Shepard
  36.  *              CCI & RIT        (a lowly co-op)
  37.  *              Rochester, NY
  38.  *
  39.  *        ...!rochester!ritcv!ritvp!les8070
  40.  *
  41.  *    NOTE:
  42.  *        These modifications have been TESTED only ONCE. (And this
  43.  *        one time was under IDEAL CONDITIONS.)  NO GUARANTEES!!
  44.  *
  45.  */
  46.  
  47. /*      This might be the last crack at this.  I added the ability to read
  48.  *      standard input, removed dup2() calls to improve transportability,
  49.  *      and made sorting the table of contents an option (this was suggested
  50.  *      by the original author, Paul Breslin, who pointed out that people
  51.  *      (and VAXEN) will use the sorted or unsorted but probably not both).
  52.  *      So now there's only one table of contents (at the beginning), which
  53.  *      is sorted if the -s option is used.  I wanted to make sorting the
  54.  *      default, but that would be inconsistant with the other options, so
  55.  *      if you're like me, alias it to cpr -s.  I also robustized the command
  56.  *      line decoding, and set it up so that -l expects the length as the next
  57.  *      argument, but will accept it without an intervening space, so -l30
  58.  *      means the same as -l 30.  The same is true of a new option, -w.
  59.  *      -w allows the user to specify the line width.
  60.  *
  61.  *      The program should also grab fewer non-function constructs.  It now
  62.  *      compares potential function names with the 'C' reserved words (from
  63.  *      "The C Programming Language", Kernighan and Ritchie, 1978) and
  64.  *      discards those that match.  No, this doesn't take forever.  Look
  65.  *      at the code.
  66.  *
  67.  *      I agree with people  who dislike 3 million options for one little
  68.  *      program, but plead that when reasonable defaults are provided it
  69.  *      needn't make a program cumbersome.  Line width defaults to 132,
  70.  *      since we print mostly on our line printer, but the default is a
  71.  *      #define called WIDTH, so it's easy to change.  Likewise for page
  72.  *      length (called LENGTH).
  73.  *
  74.  *      I added a feature similar to that suggested by Rich Johnson at
  75.  *      Bell Labs, Whippany.  Rather than substituting eight spaces for
  76.  *      every tab, it looks for the next tab stop in a string defining
  77.  *      tabs.
  78.  *
  79.  *      I tested this rather thoroughly, but I also won't guarantee anything.
  80.  *
  81.  *      Rick Wise
  82.  *      CALCULON Corp.
  83.  *      Rockville MD, 20850
  84.  *
  85.  *      decvax!harpo!seismo!rlgvax!cal-unix!wise
  86.  *
  87.  */
  88.  
  89.  
  90. /*    I fixed the lack of a page title on the table of contents page.
  91. *    I made the table of contents only in sorted mode.
  92. *    I made the function that deturmines weather a string is a function
  93. *    or not much more intellegent.  It now nolonger has to start at the
  94. *    beginning of a line!!!
  95. *    Overstrike now uses \r instead of \b for my printer's sake.
  96. *
  97. *
  98. *    Blake McBride
  99. *    3900 SW 52 AVE  #803
  100. *    Pembroke Park, FL  33023
  101. */
  102. #include <stdio.h>
  103. #include <fcntl.h>
  104. /*  #include <signal.h>  */
  105.  
  106. #define  rindex        strrchr
  107. #define  mktemp(x)    "cpr$.tmp"
  108.  
  109. #define BP        0xC        /* Form feed            */
  110. #define    MAX_S        256        /* Maximum string length    */
  111. #define LENGTH          66              /* Default Page Length          */
  112. #define WIDTH           132             /* Default page width           */
  113. #define N_FILES         20              /* Maximum number of files      */
  114. #define TOC_LEN         1024            /* Max no of T of C entries     */
  115.  
  116.  
  117. /*  The following string is the definition of tab stops.  Every 'T' is a
  118. **  tab, any other character is not.  It is currently defined as a tab
  119. **  every 8 spaces.  The comment below helps if you want to modify this,
  120. **  each row being 0+n, 50+n, 100+n, and 150+n, where n is the number
  121. **  above the declaration.  Don't try to number each row with a comment,
  122. **  because you'll notice that the '\'s make it one big string.
  123. */
  124.  
  125. char    *Rs(), *Datetime();
  126.  
  127. /*       1         2         3         4         5
  128. 12345678901234567890123456789012345678901234567890      */
  129. char   *TabDef = "\
  130. -------T-------T-------T-------T-------T-------T--\
  131. -----T-------T-------T-------T-------T-------T----\
  132. ---T-------T-------T-------T-------T-------T------\
  133. -T-------T-------T-------T-------T-------T-------T";
  134.  
  135.  
  136. FILE    *File;
  137. int    Braces;                /* Keeps track of brace depth    */
  138. int    LineNumber;            /* Count output lines        */
  139. int    PageNumber = 1;            /* You figure this one out    */
  140. int     PageLength = LENGTH;            /* Normal paper length          */
  141. int     PageWidth = WIDTH;              /* normal page width            */
  142. int    PageEnd;            /* Accounts for space at bottom    */
  143. int    InComment;
  144. int    InString;
  145. int    OnePerPage = 0;
  146. int    NumLines = 0;
  147. int    Number = 1;
  148. int     WantSorted = 1;                 /* Sort the table of contents   */
  149. char    *Name;                /* Current file name        */
  150. char    FunctionName[40];
  151. char    *ProgName;
  152. char    Todayv[45];
  153. char    *STDIN = "\n";                  /* special string pointer value to */
  154.                     /* flag a file as being stdin      */
  155.  
  156. main(argc, argv)
  157.  
  158. int argc;
  159. char    **argv;
  160.   {
  161.     register int    i,
  162.             nextf = 0;      /* index into fname[]   */
  163.     char   *fname[N_FILES];         /* file names to be worked on */
  164. /*    char        *ctime();
  165.     long        thetime, time();
  166. */
  167.     ProgName = argv[0];
  168. /*    thetime     = time(0);
  169.     Todayv     = ctime(&thetime);
  170. */
  171.     Datetime(Todayv);
  172.  
  173.     for (i = 1; i < argc; i++) {
  174.         if (argv[i][0] == '-')  {
  175.         switch (argv[i][1])  {
  176.             case 'l':
  177.                 if ( ! argv[i][2]) {
  178.                     if (++i >= argc)
  179.                         Usage();
  180.                     if ( ! ISdigit (argv[i][0]))
  181.                         Usage();
  182.                     PageLength = atoi (argv[i]);
  183.                 }
  184.                 else {
  185.                     if (!ISdigit(argv[i][2]))
  186.                         Usage();
  187.                     PageLength = atoi(&argv[i][2]);
  188.                 }
  189.                 break;
  190.             case 'w':
  191.                 if ( ! argv[i][2]) {
  192.                     if (++i >= argc)
  193.                         Usage();
  194.                     if ( ! ISdigit (argv[i][0]))
  195.                         Usage();
  196.                     PageWidth = atoi (argv[i]);
  197.                 }
  198.                 else {
  199.                     if (!ISdigit(argv[i][2]))
  200.                         Usage();
  201.                     PageWidth = atoi(&argv[i][2]);
  202.                 }
  203.                 break;
  204.             case 'n':
  205.                 NumLines = 1;
  206.                 break;
  207.             case 'o':
  208.                 OnePerPage = 1;
  209.                 break;
  210.             case 's':
  211.                 WantSorted = 1;
  212.                 break;
  213.             case '\0':
  214.                 if (nextf >= N_FILES) {
  215.                     fprintf (stderr, "%s: too many files\n", argv[0]);
  216.                     exit (1);
  217.                 }
  218.                 fname[nextf++] = STDIN;
  219.                 break;
  220.             default:
  221.                 Usage();
  222.                 break;
  223.         }
  224.         }
  225.         else {
  226.         if (nextf >= N_FILES) {
  227.             fprintf (stderr, "%s: too many files\n", argv[0]);
  228.             exit (1);
  229.         }
  230.         fname[nextf++] = argv[i];
  231.         }
  232.     }
  233.  
  234.     if ( ! nextf)
  235.         fname[nextf++] = STDIN; /* if no files specified, use stdin */
  236.  
  237.     PageEnd = PageLength - (1 + PageLength / 20);
  238.  
  239.     StartTempFile();
  240.  
  241.     for (i = 0; i < nextf; i++) {
  242.         if (fname[i] == STDIN) {
  243.             File = stdin;
  244.             Name = "standard input";
  245.         }
  246.         else  {
  247.             if( (File = fopen( Name = fname[i], "r" )) == NULL )  {
  248.                 fprintf (stderr, "%s: Can't open file \"%s\"\n",
  249.                     ProgName, Name );
  250.                 continue;
  251.             }
  252.         }
  253.  
  254.         List();
  255.         if (File != stdin)
  256.             fclose(File);
  257.     }
  258.  
  259.     if( PageNumber > 1 || LineNumber > 0 )
  260.         BreakPage();
  261.  
  262.     EndTempFile();
  263.  
  264.     DumpTableOfContents();
  265.     DumpTempFile();
  266.     Done();
  267.   }
  268.  
  269. Usage()
  270.   {
  271.     fprintf (stderr, "Usage: %s [-lpagelength] [-wpagewidth] [-n] [-o] [-s] file ...\n", ProgName);
  272.     exit(1);
  273.   }
  274.  
  275. char    *TempName;
  276. FILE    *TempFile;
  277.  
  278. StartTempFile()
  279.   {
  280. /*    extern char    *mktemp();  */
  281.  
  282.     CatchSignalsPlease();
  283.     TempName = mktemp("cprXXXXXX");
  284.     if( (TempFile = fopen(TempName, "w")) == NULL )
  285.       {
  286.         fprintf (stderr, "%s: Can't open temp file!\n", ProgName);
  287.         exit(1);
  288.       }
  289.   }
  290.  
  291. EndTempFile()
  292.   {
  293.  
  294.     fclose (TempFile);
  295.   }
  296.  
  297. DumpTempFile()
  298.   {
  299.     int     fd,
  300.         n;
  301.     char    buff[1024];
  302.  
  303.     if ((fd = open (TempName, O_RDONLY | O_RAW)) == -1) {
  304.         fprintf (stderr, "%s: can't open temp file\n", ProgName);
  305.         exit (1);
  306.     }
  307.     while (n = read (fd, buff, 1024)) {
  308.         if (write (1, buff, n) == -1) {
  309.             fprintf (stderr, "%s: write error (1)\n", ProgName);
  310.             exit (1);
  311.         }
  312.     }
  313.   }
  314.  
  315. Done()
  316.   {
  317. /*
  318.     signal(SIGQUIT, SIG_IGN);
  319.     signal(SIGHUP, SIG_IGN);
  320.     signal(SIGINT, SIG_IGN);
  321. */
  322.     if( TempName )  unlink( TempName );
  323.     exit(0);
  324.   }
  325.  
  326. CatchSignalsPlease()
  327.   {
  328. /*
  329.     signal(SIGQUIT, Done);
  330.     signal(SIGHUP, Done);
  331.     signal(SIGINT, Done);
  332. */
  333.   }
  334.  
  335. List()
  336.   {
  337.     register int    bp;
  338.     char        buffer[256];
  339.  
  340.     NewPage();
  341.     NewFile();
  342.     bp = Braces = 0;
  343.     while( fgets(buffer, 256, File) != NULL )
  344.       {
  345.         Rs(buffer);
  346.         if( bp )
  347.             NewFunction();
  348.         if( 1+LineNumber > PageEnd ) NewPage();
  349.         if(!Braces && LooksLikeFunction(buffer))   
  350.             AddToTableOfContents();
  351.         bp = PutLine(buffer);
  352.         LineNumber++;
  353.       }
  354.   }
  355.  
  356. PutLine(l)
  357. register char    *l;
  358.   {
  359.     extern   char    *EndComment();
  360.     extern   char    *EndString();
  361.     char        *expand(), *rindex();
  362.     char        *substr1();
  363.     register char    c;
  364.     int        bp;
  365.     char        *save;
  366.     char        *section, *p;
  367.     int        offset;
  368.     char        Digits[15];
  369.     int        Size;
  370.     int         pos;
  371.  
  372.     bp = 0;
  373.     for( save = expand(l); c = *l; ++l )
  374.         if( InComment ) 
  375.             l = EndComment(l);
  376.         else if( InString )
  377.             l = EndString(l);
  378.         else
  379.             switch(c)
  380.               {
  381.                 case '{':
  382.                 ++Braces;
  383.                 break;
  384.     
  385.                 case '}':
  386.                 if( --Braces == 0)
  387.                     bp = 1;
  388. /*                    if (*(l+1) == ';')  ++l;
  389.                     else  bp = 1;
  390. *  this is so no blank lines after structers             */
  391.                 break;
  392.  
  393.                 case '\'':
  394.                 ++l;
  395.                 break;
  396.             
  397.                 case '"':
  398.                 InString = 1;
  399.                 break;
  400.  
  401.                 case '/':
  402.                 if( *(l+1) == '*' )
  403.                   {
  404.                     InComment = 1;
  405.                     ++l;
  406.                   }
  407.                 break;
  408.               }
  409.  
  410.     if (NumLines)  {
  411.         sprintf (Digits,"[%d]  ", Number);
  412.         Size = strlen(Digits);
  413.     }
  414.     else
  415.         Size = 0;
  416.  
  417.     if (strlen(save) + Size > PageWidth)  {
  418.         section = substr1(save, 0, PageWidth - Size);
  419.         if (section[strlen(section) - 1] != ' ') 
  420.             if (NULL == (p = rindex(section, ' ')))
  421.                 offset = strlen(section);
  422.             else
  423.                 offset = p - section;
  424.         else
  425.             offset = strlen(section) - 1;
  426.         section[offset] = NULL;
  427.  
  428.         if (NumLines)  {
  429.             fprintf (TempFile, "[%d]  %s\n", Number++, section);
  430.         }
  431.         else  {
  432.             fprintf (TempFile, "%s\n", section);
  433.         }
  434.  
  435.         pos = offset + 1;
  436.         do  {
  437.             section = substr1(save, pos, pos + PageWidth - 8);
  438.             if (strlen(save) - pos + 8 > PageWidth)
  439.                 if (section[strlen(section) - 1] != ' ') 
  440.                     if (NULL == (p = rindex(section, ' ')))
  441.                         offset = strlen(section);
  442.                     else
  443.                         offset = p - section;
  444.                 else
  445.                     offset = strlen (section) - 1;
  446.             else    offset = strlen(section);
  447.             section[offset] = NULL;
  448.     /*        if (section[strlen(section) - 1] == '\n')
  449.                 section[strlen(section) - 1] = NULL; */
  450.             fprintf (TempFile, "C       %s\n", section);
  451.             if (++LineNumber > PageEnd)
  452.                 NewPage();
  453.         }  while ((pos += offset + 1) < strlen(save));
  454.     }
  455.     else  {
  456.         if (NumLines)
  457.             fprintf (TempFile, "[%d]  %s\n", Number++, save);
  458.         else
  459.             fprintf (TempFile, "%s\n", save);
  460.     }
  461.  
  462.     return(bp);
  463.   }
  464.  
  465. char *
  466. EndComment(p)
  467. register char    *p;
  468.   {
  469.     register char    c;
  470.  
  471.     while( c = *p++ )
  472.         if( c == '*' && *p == '/' )
  473.           {
  474.             InComment = 0;
  475.             break;
  476.           }
  477.     return(p-1);
  478.   }
  479.  
  480. char *
  481. EndString(p)
  482. register char    *p;
  483.   {
  484.     register char    c;
  485.  
  486.     while( c = *p++ )
  487.         if( c == '\\' ) 
  488.           {
  489.             ++p;
  490.             continue;
  491.           }
  492.         else if( c == '"' )
  493.           {
  494.             InString = 0;
  495.             break;
  496.           }
  497.     return(p-1);
  498.   }
  499.  
  500. NewFunction()
  501.   {
  502.     register int    i;
  503.  
  504.     if( LineNumber > (PageLength * 3 / 4) )
  505.         NewPage();
  506.     else
  507.       {
  508.         if (!OnePerPage)  {
  509.             for( i=0; i < (PageLength/7); ++i ) putc ('\n', TempFile);
  510.             LineNumber += PageLength/7;
  511.         }
  512.         else
  513.             NewPage();
  514.       }
  515.   }
  516.  
  517. #define HEADER_SIZE 3
  518.  
  519. NewPage()
  520.   {
  521.     if( LineNumber > HEADER_SIZE )
  522.       {
  523.         if( PageNumber >= 0 ) ++PageNumber;
  524.         BreakPage();
  525.         LineNumber = 0;
  526.       }
  527.     if( LineNumber == 0 )
  528.         PutHeader();
  529.   }
  530.  
  531. BreakPage()
  532.   {
  533.     putc (BP, TempFile);
  534.   }
  535.  
  536. PutHeader()
  537.   {
  538.     register int    i, l, j;
  539.  
  540.     putc ('\n', TempFile);
  541.     l = strlen(Name);
  542.     for( j=0; j < 3; ++j )
  543.       {
  544.         fprintf (TempFile, "%s", Name);
  545.         if( j < 2 )
  546.     /*        for( i=0; i < l; ++i ) putc ('\b', TempFile);  */
  547.             putc('\r', TempFile);
  548.       }
  549.     if( PageNumber > 0 )
  550.       {
  551.         for( i = (l+7)/8; i < 9; ++i ) putc ('\t', TempFile);
  552.         fprintf (TempFile, "Page: %d\n\n", PageNumber);
  553.       }
  554.     else
  555.       {
  556.         for( i = (l+7)/8; i < 6; ++i ) putc ('\t', TempFile);
  557.         fprintf (TempFile, "%s\n\n", Todayv);
  558.       }
  559.  
  560.     LineNumber += HEADER_SIZE;
  561.   }
  562.  
  563. #define isidchr(c)    (isalnum(c) || (c == '_'))
  564. #define isiechr(c)      (isidchr(c) || c==' ' || c=='*' || c=='\t' || c=='\n')
  565.  
  566. LooksLikeFunction(s)
  567. register char    *s;
  568.   {
  569.     register char    *p;
  570.     char        *save;
  571.     int             Cnt, nosl,nolp,norp,flg;
  572.     char        Digits[15];
  573.     int        AddOne = 0;
  574.  
  575.     if( InComment || InString ) return(0);
  576.  
  577.     p = FunctionName;
  578.     save = s;
  579.     nosl = nolp = norp = 0;
  580.     flg = 1;
  581.     for  (; *s && flg  ; s++)  {
  582.         switch  (*s)  {
  583.             case  '(':
  584.                 if (!nolp)  nolp = 1;
  585.                 else  return(0);
  586.                 break;
  587.             case  ')':
  588.                 if (nolp && !norp)  norp = 1;
  589.                 else return(0);
  590.                 break;
  591.             default:
  592.                 if (!nolp)  {
  593.                   if (isiechr(*s))  {
  594.                     if (isidchr(*s))   *p++ = *s;
  595.                     else  p = FunctionName;
  596.                     break;
  597.                   }
  598.                   else  return(0);
  599.                 }
  600.                 if (!norp)  {
  601.                   if (isiechr(*s) || *s == ',')  break;
  602.                   else  return(0);
  603.                 }
  604.                 if (Cmemb(*s," \t\n\r") && !nosl)  break;
  605.                 if (*s == '/' && !nosl)  {
  606.                     nosl = 1;
  607.                     break;
  608.                 }
  609.                 if (*s == '*' && nosl)  {
  610.                     flg = 0;
  611.                     break;
  612.                 }
  613.                 return(0);
  614.         }
  615.     }
  616.     if (nolp != 1)  return(0);
  617.     *p = '\0';
  618.     /*
  619.      * This will cause the function name part of the line to
  620.      * be double striken.
  621.      */
  622.     
  623.     if (NumLines)  {
  624.         sprintf (Digits,"[%d]  ", Number);
  625.         Cnt = strlen(Digits) + AddOne;
  626.         while (Cnt-- > 0)  putc (' ', TempFile);
  627.         AddOne = 0;
  628.     }
  629.  
  630.     while (*save && *save != '(')  putc (*save++, TempFile);
  631.     putc ('\r', TempFile);
  632.  
  633.     return(1);
  634.   }
  635.  
  636. char    *Toc[TOC_LEN];
  637. int     TocPages[TOC_LEN];
  638. int    TocCount;
  639.  
  640. AddToTableOfContents()
  641.   {
  642.     register int    l;
  643.     register char    *p;
  644.     char    *malloc();
  645.  
  646.     if (TocCount >= TOC_LEN) {
  647.         fprintf (stderr, "%s: too many table of contents entries\n", ProgName);
  648.         exit (1);
  649.     }
  650.     l = strlen(FunctionName);
  651.     p = Toc[TocCount] = malloc(l+1);
  652.     strcpy(p, FunctionName);
  653.     TocPages[TocCount] = PageNumber;
  654.     ++TocCount;
  655.   }
  656.  
  657. NewFile()
  658.   {
  659.     register int    i, l;
  660.     char        temp[20];
  661.  
  662.     if (TocCount >= TOC_LEN) {
  663.         fprintf (stderr, "%s: too many table of contents entries\n", ProgName);
  664.         exit (1);
  665.     }
  666.     Toc[TocCount] = (char *)malloc(130);
  667.     sprintf (Toc[TocCount], "\n\tFile: %s ", Name);
  668.     l = strlen(Toc[TocCount]) - 1;
  669.     if( l < 64 )
  670.       {
  671.         i = (64 - l) / 8;
  672.         for( l=0; l < i; ++l ) strcat(Toc[TocCount], "\t");
  673.       }
  674.     sprintf (temp, "  Page %d\n", PageNumber);
  675.     strcat(Toc[TocCount], temp);
  676.     ++TocCount;
  677.  
  678.     if (NumLines)
  679.         Number  = 1;
  680.   }
  681.  
  682. DumpTableOfContents()
  683.   {
  684.     register int    i, j, l;
  685.  
  686.     if( TocCount == 0 ) return;
  687.  
  688.     if (WantSorted)
  689.         SortTableOfContents();
  690.  
  691.     Name = "Table of Contents";
  692.  
  693.     PageNumber = -1;
  694.     LineNumber = 0;
  695.     TempFile = stdout;
  696.     NewPage();
  697.  
  698.     for( i=0; i < TocCount; ++i )
  699.       {
  700.         if( Toc[i][0] == '\n' )
  701.           {
  702.             if( (LineNumber + 5) > PageEnd )
  703.                 NewPage();
  704.             printf("%s", Toc[i]);
  705.             LineNumber += 2;
  706.             continue;
  707.           }
  708.         if( ++LineNumber > PageEnd )
  709.             NewPage();
  710.         printf("\t\t%s ", Toc[i]);
  711.         l = strlen(Toc[i]);
  712.         for( j=l; j < 48; ++j ) putchar('.');
  713.         printf(" %d\n", TocPages[i]);
  714.       }
  715.     putchar(BP);
  716.     fflush (stdout);
  717.   }
  718.  
  719. SortTableOfContents()
  720. {
  721.     register int    i,
  722.             tempint;
  723.     char   *tempchar;
  724.     int     flag;
  725.  
  726.     do {
  727.         flag = 0;
  728.         for (i = 0; i < TocCount - 1; i++) {
  729.             if (Toc[i][0] == '\n' || Toc[i+1][0] == '\n')
  730.                 continue;       /* don't sort across file names */
  731.             if (strcmp (Toc[i], Toc[i+1]) > 0) {
  732.                 tempchar = Toc[i];
  733.                 Toc[i] = Toc[i+1];
  734.                 Toc[i+1] = tempchar;
  735.                 tempint = TocPages[i];
  736.                 TocPages[i] = TocPages[i+1];
  737.                 TocPages[i+1] = tempint;
  738.                 flag = 1;
  739.             }
  740.         }
  741.     } while (flag);
  742. }
  743.  
  744. /*
  745.  *    This is the function substr1().  The calling sequence is:
  746.  *
  747.  *            substr1(string, startpos, endpos).
  748.  *
  749.  *    The function returns a pointer to a static string (written over -
  750.  *    on subsequent calls) which is a substring of the string `string'
  751.  *    starting at `startpos' (the first position is 0 (zero)) and ending
  752.  *    at `endpos' (non-inclusive).  All arguments must be present or
  753.  *    strange things happen with the system stack.
  754.  *
  755.  *    An example of the use is:
  756.  *
  757.  *        x = substr1(string, 2, 5);
  758.  *        (where string == "This is a test.")
  759.  *
  760.  *    This call returns a pointer to:
  761.  *
  762.  *        "is "
  763.  *
  764.  *    An error code of -1 is returned is the `endpos' is greater than
  765.  *    `startpos'
  766.  *
  767.  *
  768.  *                        Lance E. Shepard
  769.  */
  770.  
  771. char *
  772. substr1(string, start, end)
  773.  
  774. char    *string;
  775. int    start;
  776. int    end;
  777.  
  778. {
  779.  
  780.     static char  retstr[MAX_S];
  781.     int loop1;
  782.     int loop2;
  783.  
  784.     if (end < start)  {
  785.         exit(-1);
  786.     }
  787.  
  788.     for (loop2 = 0; loop2 < MAX_S; loop2++)
  789.         retstr[loop2] = NULL;
  790.  
  791.     for (loop1 = start, loop2 = 0; string[loop1] != NULL &&
  792.         loop1 < end && loop2 <= MAX_S; loop1++, loop2++)
  793.  
  794.         retstr[loop2] = string[loop1];
  795.  
  796.     retstr[++loop2] = NULL;
  797.  
  798.     return(retstr);
  799.  
  800. }
  801.  
  802. /*
  803.  *    This is the function `char *expand().'  This function takes as
  804.  *    an argument a NULL terminated string and replaces all occurances
  805.  *    of the tab character with 8 (eight) spaces.  The function returns
  806.  *    a pointer to a static string which is overwritten on subsequent
  807.  *    calls.
  808.  */
  809.  
  810. char *
  811. expand(string)
  812.  
  813. char *string;
  814.  
  815. {
  816.  
  817.     int count;
  818.     static char retstr[MAX_S];
  819.  
  820.     for (count = 0; count < MAX_S; retstr[count++] = NULL)  ;
  821.  
  822.     for (count = 0; *string != NULL; count++, string++)  {
  823.  
  824.         if (*string == '\t')  {
  825.             retstr[count] = ' ';
  826. /*            while (((count + 1) % 8) != 0)     */
  827.             while (TabDef[count] != 'T')
  828.                 retstr[++count] = ' ';
  829.         }
  830.         else
  831.             retstr[count] = *string;
  832.     }
  833.  
  834.     retstr[count] = NULL;
  835.  
  836.     return(retstr);
  837.  
  838. }
  839.  
  840. char *Rs(s)        /* strip trailing blanks from string  */
  841. char s[];
  842. {
  843.     int n;
  844.  
  845.     for (n=strlen(s)-1 ; n>=0 && isspace(s[n]) ; n--);
  846.     s[n+1] = '\0';
  847.     return(s); 
  848. }
  849.  
  850. int Cmemb(a,b)    /*  is character "a" a member of string "b"  */
  851. char  a, *b;
  852. {
  853.     while  (*b)  
  854.         if (a == *b++)  return(1);
  855.     if (!a)     return(1);
  856.     else     return(0);
  857. }
  858.  
  859.