home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d166 / cref.lha / Cref / cref.c < prev    next >
C/C++ Source or Header  |  1988-11-22  |  18KB  |  914 lines

  1. /*
  2. **   cref - C cross referencer VERSION 2.
  3. **    This program reads its standard input or one or more files
  4. **    and prints the file plus an alphabetic list of word references
  5. **    by line number.
  6. **
  7. **    To run:
  8. **        cref [-q] [-lnnn] [-wnnn] [-hheading] [-tnnn] [-?] [file ...]
  9. **
  10. **    Options:
  11. **        q    - don't print normal input file listing.
  12. **        lnnn - set page length to n instead of the default 66.
  13. **        wnnn - set page width to n instead of the default 132.
  14. **        hccc - set page heading to 'ccc' rather than file names.
  15. **        tnnn - set tab spaces to n instead if the default 8.
  16. **      ?    - display this list.
  17. **
  18. **    Mike Edmonds - 5/81
  19. **--------------------------------------------------------------------
  20. **
  21. **  VERSION 2 with comment bug fixed. May 1988
  22. **
  23. **  Amiga port by Joel Swank 9/87
  24. **
  25. **  Compiled under Manx:
  26. **  cc cref.c
  27. **  ln cref.o -lc
  28. **
  29. **  Changes besides porting:
  30. **
  31. **  + Deleted temporary file option because the Amiga sort command
  32. **      cannot sort files larger than memory.
  33. **  + Added -t option
  34. **  + Added -? option
  35. **  + Added Usage message and error msgs.
  36. **  + Rewrote case statments that overflowed compiler table
  37. **  + Fixed BUG that caused end of comment to be missed. star-star-slash
  38. **    was missed.
  39. */
  40.  
  41. #include <stdio.h>
  42. #include <ctype.h>
  43. #include <signal.h>
  44. #include <exec/types.h>
  45. #include <stat.h>
  46.  
  47. #define MAXWORD        15        /* maximum chars in word */
  48. #define MAXPAGLINES    9999    /* maximum posible lines in page */
  49. #define MINPAGLINES    4        /* minimum posible lines in page */
  50. #define MAXLINWIDTH    132        /* maximum posible chars in line */
  51. #define MINLINWIDTH    MAXWORD+12    /* minimum posible chars in line */
  52. #define MAXTABSIZE    132        /* maximum posible chars in tab */
  53. #define MINTABSIZE    1        /* minimum posible chars in tab */
  54.  
  55. #define igncase(c)    (isupper(c)? tolower(c) : (c))
  56.  
  57. #undef FALSE
  58. #undef TRUE
  59. #define FALSE    0
  60. #define TRUE    1
  61.  
  62. #ifdef    DEBUG
  63. #define debug(a,b)    fprintf(stderr,(a),(b))
  64. #else
  65. #define debug(a,b)
  66. #endif
  67.  
  68.  
  69.  
  70. /*
  71.  *  global structures
  72.  */
  73.  
  74. #define LINLIST    struct    _linlist
  75. #define WRDLIST    struct    _wrdlist
  76.  
  77. struct    _linlist {        /* line number list node */
  78.     long     ln_no ;      /* line number */
  79.     LINLIST    *ln_next ;      /* next element pointer (or NULL) */
  80. } ;
  81.  
  82. struct    _wrdlist {        /* word list node */
  83.     char    *wd_wd ;      /* pointer to word */
  84.     char    *wd_lwd ;      /* pointer to word (lower case) */
  85.     LINLIST     wd_ln ;      /* first element of line list */
  86.     WRDLIST    *wd_low ;      /* lower child */
  87.     WRDLIST    *wd_hi ;      /* higher child */
  88. } ;
  89.  
  90.  
  91.  
  92. /*
  93.  *  options
  94.  */
  95.  
  96. char    *Progname ;
  97. int     Quiet = FALSE ;    /* don't print input file listing? (-q) */
  98. int     Maxpaglines = 66 ;    /* maximum lines in page (-l) */
  99. int     Maxlinwidth = 132 ;    /* maximum chars in print line (-w) */
  100. int  Tabsize    = 8 ;    /* default length of tab */
  101.  
  102.  
  103.  
  104. /*
  105.  *  global variables
  106.  */
  107.  
  108. char     Crefhdr[MAXLINWIDTH+1] ;/* report header */
  109. char    *Filename ;        /* name of current input file */
  110. char     Date[30] ;        /* current or last file modify date */
  111. long     Hiline = 1L ;        /* current (and max.) input file line number */
  112. int         files=0 ;      /* count of source files */
  113. WRDLIST    *Wdtree = NULL ;    /* ptr to root node of binary word list */
  114.  
  115.  
  116.  
  117. /*
  118.  *  C language reserved keywords (in pseudo random order)
  119.  */
  120. char    *Ckeywords[] = {
  121.     "char",
  122.     "static",
  123.     "break",
  124.     "#define",
  125.     "#if",
  126.     "default",
  127.     "#ifdef",
  128.     "#ifndef",
  129.     "register",
  130.     "void",
  131.     "if",
  132.     "while",
  133.     "#line",
  134.     "union",
  135.     "switch",
  136.     "#else",
  137.     "asm",
  138.     "do",
  139.     "#include",
  140.     "#undef",
  141.     "#endif",
  142.     "long",
  143.     "continue",
  144.     "float",
  145.     "short",
  146.     "typedef",
  147.     "for",
  148.     "struct",
  149.     "case",
  150.     "else",
  151.     "unsigned",
  152.     "int",
  153.     "extern",
  154.     "auto",
  155.     "goto",
  156.     "entry",
  157.     "return",
  158.     "double",
  159.     "sizeof",
  160.     0
  161. } ;
  162.  
  163.  
  164.  
  165.  
  166. /*
  167.  *  main - Store C keywords.
  168.  *       Get program options and format heading lines.
  169.  *       Get words from input file (or files) and store in tree.
  170.  *       Retrieve and print in word sequence.
  171.  */
  172. main(argc, argv)
  173. int     argc ;
  174. char    *argv[] ;
  175. {
  176.     char    wordfilebuf[BUFSIZ] ;
  177.     register FILE    *filep ;
  178.     char    *getword(), *word ;
  179.     struct     stat    stbuf ;
  180.     long     time() ;
  181.     register cnt ;
  182.  
  183.     Progname = *argv ;        /* get options */
  184.     getcmd(argc, argv) ;
  185.  
  186.  
  187.                     /* store C keywords */
  188.     for (cnt=0 ; Ckeywords[cnt] ; cnt++)
  189.         storword(Ckeywords[cnt], 0L) ;
  190.  
  191.  
  192.     listchr(-2);    /* clear output line */
  193.  
  194.                     /* read and store files */
  195.     for (cnt=1 ; cnt < argc ; cnt++)
  196.         if (*argv[cnt] != '-')
  197.         {    files++ ;
  198.             Filename = argv[cnt] ;
  199.             if ((filep = fopen(Filename, "r")) == NULL)
  200.                 fatal("can't open %s", Filename) ;
  201.             stat(Filename, &stbuf) ;
  202.             mkdate((long)stbuf.st_mtime) ;
  203.             while (word = getword(filep))
  204.                 storword(word, Hiline);
  205.             fclose(filep) ;
  206.         }
  207.  
  208.     if (!files)            /* no files - read stdin */
  209.     {    if (*Crefhdr)
  210.             Filename = Crefhdr ;
  211.         else
  212.             Filename = "stdin" ;
  213.         mkdate(time( (long *)0)) ;
  214.         while (word = getword(stdin))
  215.             storword(word, Hiline) ;
  216.     }
  217.  
  218.  
  219.     /*  print cross reference report */
  220.     cref(Wdtree) ;
  221.  
  222.     exit(0) ;
  223. }
  224.  
  225.  
  226.  
  227.  
  228.  
  229.  
  230.  
  231.  
  232. /*
  233.  *  getcmd - get arguments from command line & build page headings
  234.  */
  235. getcmd(argc, argv)
  236. register argc ;
  237. register char    *argv[] ;
  238. {
  239.     register cnt ;
  240.  
  241.     debug("GETCMD(%d", argc) ;
  242.     debug(", %s)\n", argv[0]) ;
  243.  
  244.     *Crefhdr = '\0' ;
  245.                     /* get command options */
  246.     for (cnt=1; cnt < argc; cnt++)
  247.     {    if (*argv[cnt] == '-')
  248.         {    switch(argv[cnt][1])
  249.             {  case 'q':
  250.                 Quiet = TRUE ;
  251.                 break ;
  252.  
  253.                case 'l':
  254.                 Maxpaglines = atoi(&argv[cnt][2]) ;
  255.                 if (Maxpaglines < MINPAGLINES
  256.                  || Maxpaglines > MAXPAGLINES)
  257.                     fatal("Bad -l value: %s", argv[cnt]) ;
  258.                 break ;
  259.  
  260.                case 'w':
  261.                 Maxlinwidth = atoi(&argv[cnt][2]) ;
  262.                 if (Maxlinwidth < MINLINWIDTH
  263.                  || Maxlinwidth > MAXLINWIDTH)
  264.                     fatal("Bad -w value: %s", argv[cnt]) ;
  265.                 break ;
  266.  
  267.                case 't':
  268.                 Tabsize = atoi(&argv[cnt][2]) ;
  269.                 if (Tabsize < MINTABSIZE
  270.                  || Tabsize > MAXTABSIZE)
  271.                     fatal("Bad -t value: %s", argv[cnt]) ;
  272.                 break ;
  273.  
  274.                case 'h':
  275.                 strncpy(Crefhdr, &argv[cnt][2], MAXLINWIDTH) ;
  276.                 Crefhdr[MAXLINWIDTH] = '\0' ;
  277.                 break ;
  278.  
  279.                case '?':                    /* help option */
  280.                  usage();
  281.                  printf(" Options:\n");
  282.                  printf(" q    - don't print normal input file listing\n");
  283.                  printf(" lnnn - set page length to n instead of the default 66.\n");
  284.                  printf(" wnnn - set page width to n instead of the default 132.\n");
  285.                  printf(" hccc - set page heading to 'ccc' rather than file names\n");
  286.                  printf(" tnnn - set tab spacing to n instead of the default 8\n");
  287.                  printf(" ?    - display this list.\n");
  288.                 exit(0);
  289.  
  290.                default:
  291.                  usage();
  292.                  exit(0);
  293.             }
  294.         }
  295.     }
  296.  
  297.                     /* insert file names in hdr */
  298.     if (!*Crefhdr)
  299.         for (cnt=1; cnt < argc; cnt++)
  300.             if (*argv[cnt] != '-')
  301.                 strjoin(Crefhdr, ' ', argv[cnt], MAXLINWIDTH) ;
  302. }
  303.  
  304.  
  305.  
  306. usage()
  307. {
  308. printf("usage:cref [-q] [-lnnn] [-wnnn] [-hheading] [-tnnn] [-?] [file ...]\n");
  309. }
  310.  
  311.  
  312.  
  313.  
  314. /*
  315.  *  getword - read, print and return next word from file
  316.  */
  317. char *
  318. getword(filep)
  319. FILE    *filep ;
  320. {
  321.     static     char    wordbuf[MAXWORD+1] ;
  322.     register char    *wp = wordbuf ;
  323.     register maxw = sizeof(wordbuf) ;
  324.     register chr ;
  325.     int     inword=0, lastchr=0 ;
  326.     long     slineno ;
  327.  
  328. #define    _listchr(chr)    if (!Quiet) listchr(chr)
  329.  
  330. #define    _rtrnwrd(wp)             \
  331.     {    ungetc(chr, filep) ;    \
  332.         *(wp) = '\0' ;        \
  333.         return wordbuf ;    \
  334.     }
  335.  
  336.     while ((chr = getc(filep)) != EOF)
  337.     {    
  338.             /* normal char - add to current word */
  339.         if ((chr <= 'z' && chr >= 'a') || 
  340.             (chr <= 'Z' && chr >= 'A') || 
  341.              chr == '_' )
  342.             {
  343.             if (maxw-- <= 1)
  344.                 _rtrnwrd(wp) ;
  345.             *wp++ = chr ;
  346.             inword++ ;
  347.             _listchr(chr) ;
  348.             }
  349.  
  350.         else switch (chr)
  351.         {
  352.                     /* digit - can't be 1st char in word */
  353.            case '0': case '1': case '2': case '3': case '4':
  354.            case '5': case '6': case '7': case '8': case '9':
  355.             if (inword)
  356.             {    if (maxw-- <= 1)
  357.                     _rtrnwrd(wp) ;
  358.                 *wp++ = chr ;
  359.             }
  360.             _listchr(chr) ;
  361.             break ;
  362.  
  363.                     /* '#' - must be 1st char in word */
  364.            case '#':
  365.             if (inword)
  366.                 _rtrnwrd(wp) ;
  367.             *wp++ = chr ;
  368.             inword++ ;
  369.             _listchr(chr) ;
  370.             break ;
  371.  
  372.                     /* newline - end current word */
  373.            case '\n':
  374.             if (inword)
  375.                 _rtrnwrd(wp) ;
  376.             _listchr(chr) ;
  377.             Hiline++ ;
  378.             break ;
  379.  
  380.                     /* comments - print & bypass */
  381.            case '/':
  382.             if (inword)
  383.                 _rtrnwrd(wp) ;
  384.             _listchr(chr) ;
  385.             slineno = Hiline ;
  386.             if ((chr = getc(filep)) == '*')
  387.             {    _listchr(chr) ;
  388.                 while (chr != EOF)
  389.                 {    chr = getc(filep) ;
  390.                     _listchr(chr) ;
  391.                     if (chr == '\n')
  392.                         Hiline++ ;
  393.                     else if (chr == '*')
  394.                     {    
  395.                       restar:  /* Fix for missing end of comment bug */
  396.                         chr = getc(filep) ; /* star-star-slash was missed */
  397.                         _listchr(chr) ;
  398.                         if (chr == '\n')
  399.                             Hiline++ ;
  400.                         else if (chr == '/')
  401.                             break ; ;
  402.                         if (chr == '*') goto restar; /* JHS 5/24/88 */
  403.                     }
  404.                 }
  405.                 if (chr == EOF)
  406.                     fatal("unterminated comment at %ld in %s", slineno, Filename) ;
  407.             }
  408.             else
  409.                 ungetc(chr, filep) ;
  410.             break ;
  411.  
  412.                     /* words in quotes - print & bypass */
  413.            case '"':
  414.             if (inword)
  415.                 _rtrnwrd(wp) ;
  416.             _listchr(chr) ;
  417.             slineno = Hiline ;
  418.             if (lastchr != '\\')
  419.             {    do
  420.                 {    if (chr == '\\' && lastchr == '\\')
  421.                         lastchr = '\0' ;
  422.                     else
  423.                         lastchr = chr ;
  424.                     if ((chr = getc(filep)) == EOF)
  425.                         fatal("unterminated quote at %ld in %s", slineno, Filename) ;
  426.                     _listchr(chr) ;
  427.                     if (chr == '\n')
  428.                         Hiline++ ;
  429.                 } while (chr != '"' || lastchr == '\\') ;
  430.             }
  431.             break ;
  432.  
  433.                     /* letters in quotes - print & bypass */
  434.            case '\'':
  435.             if (inword)
  436.                 _rtrnwrd(wp) ;
  437.             _listchr(chr) ;
  438.             if (isprint(chr = getc(filep)))
  439.             {    _listchr(chr) ;
  440.                 if (chr == '\\')
  441.                 {    if (!isprint(chr = getc(filep)))
  442.                         goto toofar ;
  443.                     _listchr(chr) ;
  444.                 }
  445.                 if ((chr = getc(filep)) != '\'')
  446.                     goto toofar ;
  447.                 _listchr(chr) ;
  448.             }
  449.             else
  450.                toofar:
  451.                 ungetc(chr, filep) ;
  452.             break ;
  453.  
  454.            default:
  455.             if (inword)
  456.                 _rtrnwrd(wp) ;
  457.             _listchr(chr) ;
  458.             break ;
  459.         }
  460.  
  461.         lastchr = chr ;
  462.     }
  463.  
  464.     if (inword)
  465.         _rtrnwrd(wp) ;
  466.     _listchr(EOF) ;
  467.     return NULL ;
  468. }
  469.  
  470.  
  471.  
  472.  
  473.  
  474.  
  475.  
  476.  
  477. /*
  478.  *  listchr - list the input files one character at a time
  479.  */
  480.  
  481. static    Listpage = 0 ;
  482. static    Listpline = MAXPAGLINES ;
  483.  
  484. listchr(chr)
  485. register chr ;
  486. {
  487.     static    char     linebuf[MAXLINWIDTH*2], *lineptr=linebuf ;
  488.     static    lastchr=0, linecnt=0 ;
  489.     int    remain;
  490.  
  491.     if (chr == -2)            /* clear line buffer */
  492.         {
  493.         setmem(linebuf,Maxlinwidth,' ');
  494.         return;
  495.         }
  496.  
  497.     if (chr == EOF)            /* EOF - print final line */
  498.     {    *lineptr = '\0' ;
  499.         listline(linebuf) ;
  500.         Listpage = 0 ;
  501.         Listpline = MAXPAGLINES ;
  502.         lineptr = linebuf ;
  503.         linecnt = 0 ;
  504.         return ;
  505.     }
  506.  
  507.     if (lineptr == linebuf)        /* new line - format line number */
  508.     {    ltoc(linebuf, Hiline, 6) ;
  509.         lineptr = linebuf+6 ;
  510.         *lineptr++ = ' ' ;
  511.         *lineptr++ = ' ' ;
  512.         linecnt = 8 ;
  513.     }
  514.  
  515. #define    _lineoflo(ctr, newctr)        \
  516.     if ((ctr) >= Maxlinwidth)    \
  517.     {    *lineptr = '\0' ;    \
  518.         listline(linebuf) ;    \
  519.         lineptr = &linebuf[8] ;    \
  520.         linecnt = (newctr) ;    \
  521.     }
  522.  
  523.     switch (chr)
  524.     {                /* newline - print last line */
  525.        case '\n':
  526.         if (lastchr != '\f')
  527.         {    *lineptr = '\0' ;
  528.             listline(linebuf) ;
  529.         }
  530.         lineptr = linebuf ;
  531.         linecnt = 0 ;
  532.         break ;
  533.  
  534.                      /* formfeed - print line and end page */
  535.        case '\f':
  536.         if (linecnt != 8)
  537.         {    *lineptr = '\0' ;
  538.             listline(linebuf) ;
  539.         }
  540.         Listpline = MAXPAGLINES ;
  541.         lineptr = linebuf ;
  542.         linecnt = 0 ;
  543.         break ;
  544.  
  545.                     /* tab - skip to next tab stop */
  546.        case '\t':
  547.         linecnt += Tabsize ;
  548.         remain =  linecnt % Tabsize ;
  549.         linecnt -= remain;
  550.         _lineoflo(linecnt, 8) ;
  551.         lineptr += Tabsize ;
  552.         lineptr -= remain;
  553.         break ;
  554.  
  555.                     /* backspace - print, but don't count */
  556.        case '\b':
  557.         *lineptr++ = chr ;
  558.         break ;
  559.  
  560.                     /* ctl-char - print as "^x" */
  561.              case 001: case 002: case 003:
  562.        case 004: case 005: case 006: case 007:
  563.                      case 013:
  564.                  case 015: case 016: case 017:
  565.        case 020: case 021: case 022: case 023:
  566.        case 024: case 025: case 026: case 027:
  567.        case 030: case 031: case 032: case 033:
  568.        case 034: case 035: case 036: case 037:
  569.         _lineoflo(linecnt+=2, 10) ;
  570.         *lineptr++ = '^' ;
  571.         *lineptr++ = ('A'-1) + chr ;
  572.         break ;
  573.  
  574.        default:
  575.         if (isprint(chr))
  576.         {    _lineoflo(++linecnt, 9) ;
  577.             *lineptr++ = chr ;
  578.         }
  579.  
  580.         else        /* non-ascii chars - print as "\nnn" */
  581.         {    _lineoflo(linecnt+=4, 12) ;
  582.             *lineptr++ = '\\' ;
  583.             *lineptr++ = '0' + ((chr & 0300) >> 6) ;
  584.             *lineptr++ = '0' + ((chr & 070) >> 3) ;
  585.             *lineptr++ = '0' + (chr & 07) ;
  586.         }
  587.         break ;
  588.     }
  589.     lastchr = chr ;
  590. }
  591.  
  592.             /* print a completed line from the input file */
  593. listline(line)
  594. register char    *line ;
  595. {
  596.     if (*line)
  597.     {    if (++Listpline >= (Maxpaglines-8))
  598.         {    if (files >1 || Listpage) putchar('\f') ;
  599.             printf("\n%s %s  Page %d\n\n",
  600.                 Date, Filename, ++Listpage) ;
  601.             Listpline = 0 ;
  602.         }
  603.         puts(line) ;
  604.         listchr(-2);    /* clear line buffer */
  605.     }
  606. }
  607.  
  608.  
  609.  
  610.  
  611.  
  612.  
  613.  
  614.  
  615.  
  616. /*
  617.  *  storword - store word and line # in binary word tree or word file
  618.  */
  619.  
  620. storword(word, lineno)
  621. register char    *word ;
  622. long     lineno ;
  623. {
  624.     char     lword[MAXWORD+1] ;
  625.     register char    *cp1, *cp2 ;
  626.     WRDLIST    *addword() ;
  627.  
  628.                     /* convert word to lower case */
  629.     for (cp1=word, cp2=lword ; *cp2++ = igncase(*cp1) ; cp1++)
  630.         ;
  631.  
  632.                     /* store words and lineno */
  633.     Wdtree = addword(Wdtree, word, lword, lineno) ;
  634. }
  635.  
  636.  
  637.  
  638. /*
  639.  *  addword - add word and line# to in-core word list
  640.  */
  641. WRDLIST *
  642. addword(wdp, word, lword, lineno)
  643. register WRDLIST *wdp ;
  644. char    *word, *lword ;
  645. long     lineno ;
  646. {
  647.     char    *malloc() ;
  648.     int     comp ;
  649.  
  650.                     /* insert new word into list */
  651.     if (wdp == NULL)
  652.     {    register wordlen = strlen(word) + 1 ;
  653.  
  654.         wdp = (WRDLIST *)malloc((wordlen * 2) + sizeof(WRDLIST)) ;
  655.         if (wdp == NULL)
  656.             goto nomemory ;
  657.  
  658.         wdp->wd_wd  = (char *)wdp + sizeof(WRDLIST) ;
  659.         wdp->wd_lwd = wdp->wd_wd + wordlen ;
  660.         strcpy(wdp->wd_wd,  word) ;
  661.         strcpy(wdp->wd_lwd, lword) ;
  662.  
  663.         wdp->wd_hi = wdp->wd_low = NULL ;
  664.         wdp->wd_ln.ln_no = lineno ;
  665.         wdp->wd_ln.ln_next = NULL ;
  666.     }
  667.  
  668.                     /* word matched in list? */
  669.     else if (((comp = strcmp(lword, wdp->wd_lwd)) == 0)
  670.           && ((comp = strcmp(word,  wdp->wd_wd))  == 0))
  671.     {    register LINLIST *lnp, **lnpp ;
  672.  
  673.         if (wdp->wd_ln.ln_no)
  674.         {              /* add line# to linked list */
  675.             lnp = &wdp->wd_ln ;
  676.             do
  677.             {    if (lineno == lnp->ln_no)
  678.                     return wdp ;
  679.                 lnpp = &lnp->ln_next ;
  680.             } while ((lnp = *lnpp) != NULL) ;
  681.  
  682.             *lnpp = (LINLIST *)malloc(sizeof(LINLIST)) ;
  683.             if ((lnp = *lnpp) == NULL)
  684.                 goto nomemory ;
  685.             lnp->ln_no = lineno ;
  686.             lnp->ln_next = NULL ;
  687.         }
  688.     }
  689.  
  690.     else if (comp < 0)        /* search for word in children */
  691.         wdp->wd_low = addword(wdp->wd_low, word, lword, lineno) ;
  692.     else
  693.         wdp->wd_hi = addword(wdp->wd_hi, word, lword, lineno) ;
  694.  
  695.     return wdp ;
  696.  
  697.  
  698.                     /* not enough memory - convert to -b */
  699. nomemory:
  700.     fatal("not enough memory for in-core word list") ;
  701. }
  702.  
  703.  
  704.  
  705.  
  706.  
  707.  
  708.  
  709. /*
  710.  *  cref - print cross reference report from internal word list
  711.  */
  712. #define MAXLNOS 2000        /* maximum line nos. for a word */
  713. long    Linenos[MAXLNOS] ;    /* list of line numbers for a word */
  714.  
  715. cref(wdtree)
  716. register WRDLIST *wdtree ;
  717. {
  718.     creftree(wdtree) ;
  719. }
  720.  
  721. creftree(wdp)            /* recursively print word tree nodes */
  722. register WRDLIST *wdp ;
  723. {
  724.     register LINLIST *lnp ;
  725.     register nos ;
  726.  
  727.     if (wdp != NULL)
  728.     {    creftree(wdp->wd_low) ;    /* print lower children */
  729.  
  730.         nos = 0 ;
  731.         if (Linenos[0] = wdp->wd_ln.ln_no)
  732.         {    lnp = &wdp->wd_ln ;
  733.             while ((lnp = lnp->ln_next) != NULL)
  734.                 if (nos < (MAXLNOS-2))
  735.                     Linenos[++nos] = lnp->ln_no ;
  736.             printword(wdp->wd_wd, nos) ;
  737.         }
  738.  
  739.         creftree(wdp->wd_hi) ;    /* print higher children */
  740.     }
  741. }
  742.  
  743.  
  744.  
  745.  
  746.  
  747.  
  748.  
  749. /*
  750.  *  printword - print a word and all its line number references
  751.  */
  752. printword(word, nos)
  753. char    *word ;
  754. register nos ;
  755. {
  756.     static    firstime=TRUE, linecnt, maxlnos, lnosize ;
  757.     register cnt ;
  758.  
  759.     if (firstime)
  760.     {    firstime = FALSE ;
  761.         linecnt = Maxpaglines ;
  762.         for (lnosize=1 ; Hiline ; lnosize++)
  763.             Hiline /= 10L ;
  764.         maxlnos = (Maxlinwidth - (MAXWORD+7)) / lnosize ;
  765.     }
  766.  
  767.     if (linecnt >= (Maxpaglines - 8))
  768.     {    printheads() ;
  769.         linecnt = 5 ;
  770.     }
  771.  
  772.     printf("%-15s%5d  ", word, ++nos) ;
  773.     Linenos[nos] = 0 ;
  774.  
  775.     for (nos=0, cnt=0 ; Linenos[nos] ; nos++)
  776.     {    if (++cnt > maxlnos)
  777.         {    cnt = 1 ;
  778.             if (linecnt++ >= (Maxpaglines - 2))
  779.             {    printheads() ;
  780.                 linecnt = 5 ;
  781.                 printf("%-15s(cont) ", word);
  782.             }
  783.             else
  784.                 printf("\n%22s", " ") ;
  785.         }
  786.         printf("%*ld", lnosize, Linenos[nos]) ;
  787.     }
  788.     putchar('\n') ;
  789.  
  790.     linecnt++ ;
  791. }
  792.  
  793.  
  794.  
  795. /*
  796.  *  printheads - print page headings
  797.  */
  798. printheads()
  799. {
  800.     static    page=0 ;
  801.     long    time() ;
  802.  
  803.     if (!page)
  804.         mkdate(time( (long *)0)) ;
  805.  
  806.     putchar('\f') ;
  807.     printf("\nCREF  %s %.*s  Page %d\n\n",
  808.         Date, (Maxlinwidth-36), Crefhdr, ++page) ;
  809.     printf("word             refs    line numbers\n\n") ;
  810. }
  811.  
  812.  
  813.  
  814.  
  815.  
  816.  
  817.  
  818.  
  819. /*
  820.  *  ltoc - store ASCII equivalent of long value in given field
  821.  */
  822. ltoc(fld, lval, len)
  823. register char    *fld ;
  824. register long    lval ;
  825. register len ;
  826. {
  827.     fld += len ;
  828.     while (len-->0)
  829.         if (lval)
  830.         {    *--fld = '0' + (lval%10L) ;
  831.             lval /= 10L ;
  832.         }
  833.         else
  834.             *--fld = ' ' ;
  835. }
  836.  
  837.  
  838.  
  839. /*
  840.  *  mkdate - build time/date for use in heading lines
  841.  */
  842. mkdate(atime)
  843. long    atime ;
  844. {
  845.     long    mtime ;
  846.     char    *cp, *ctime() ;
  847.  
  848.     debug("MKDATE(%ld)\n", atime) ;
  849.  
  850.     mtime = atime ;
  851.     cp = ctime(&mtime) ;
  852.     *(cp+24) = ' ' ;        /* clear newline */
  853.     strcpy(cp+16, cp+19) ;        /* shift over seconds */
  854.     strcpy(Date, cp+4) ;
  855. }
  856.  
  857.  
  858.  
  859. /*
  860.  *  strjoin - join "str1" to "str2" (separated by "sep")
  861.  *    Truncate if necessary to "max" chars.
  862.  */
  863. strjoin(str1, sep, str2, max)
  864. register char    *str1, *str2;
  865. char    sep ;
  866. register max ;
  867. {
  868.     if (*str2)
  869.     {    if (*str1)
  870.         {    while (*str1++)
  871.                 if (--max <= 0)
  872.                     goto oflo ;
  873.             max--, str1-- ;
  874.             *str1++ = sep ;
  875.         }
  876.         while (*str1++ = *str2++)
  877.             if (--max <= 0)
  878.                 goto oflo ;
  879.     }
  880.     return ;
  881.  
  882. oflo:
  883.     *--str1 = '\0' ;
  884.     return ;
  885. }
  886.  
  887.  
  888.  
  889.  
  890.  
  891.  
  892.  
  893. /*
  894.  *  error - print standard error msg
  895.  */
  896. error(ptrn, data1, data2)
  897. register char    *ptrn, *data1, *data2 ;
  898. {
  899.     fprintf(stderr, "%s: ", Progname) ;
  900.     fprintf(stderr, ptrn, data1, data2) ;
  901.     putc('\n', stderr) ;
  902. }
  903.  
  904.  
  905. /*
  906.  *  fatal - print standard error msg and halt process
  907.  */
  908. fatal(ptrn, data1, data2)
  909. register char    *ptrn, *data1, *data2 ;
  910. {
  911.     error(ptrn, data1, data2) ;
  912.     exit(1);
  913. }
  914.