home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 344_02 / xc3.c < prev    next >
C/C++ Source or Header  |  1990-12-11  |  38KB  |  1,324 lines

  1. /*
  2.         HEADER:         CUG236;
  3.         TITLE:          Cross Reference Generator;
  4.         DATE:           04/27/1988;
  5.         DESCRIPTION:    "C-language program cross-referencer, modified for
  6.                             Microsoft C5.0, with enhancements."
  7.         VERSION:        1.1;
  8.         KEYWORDS:       Cross Reference;
  9.         FILENAME:       XC2.C;
  10.         SEE-ALSO:       CUG126, CUG171;
  11.         COMPILERS:      Vanilla;
  12.         AUTHORS:        Phillip N. Hisley, David N. Smith, Fred C. Smith,
  13.                         William C. Colley III;
  14. */
  15. /**********************************************************
  16.  
  17.         XC - A 'C' Concordance Utility
  18.  
  19.         Version 1.0 January, 1982
  20.  
  21.         Copyright (c) 1982 by Philip N. Hisley
  22.  
  23.             Philip N. Hisley
  24.             548H Jamestown Court
  25.             Edgewood, Maryland 21040
  26.             (301) 679-4606
  27.  
  28.         Released for non-commercial distribution only
  29.  
  30.  
  31.         Converted to IBM/PC CI/C86 by David N. Smith, May/June 1983
  32.         with enhancements and Lattice compiler support in December 1983.
  33.  
  34.             David N. Smith
  35.             44 Ole Musket Lane
  36.             Danbury, CT 06810
  37.             (203) 748-5934
  38.  
  39.         Changes Copyright (c) 1983 by David N. Smith
  40.  
  41.         PC Enhancements include:
  42.  
  43.             1)  Nested #INCLUDE statements
  44.             2)  Single spaced cross-reference list
  45.             3)  Removal of tabbing on output device
  46.                 (Since many printers don't support it)
  47.             4)  #INCLUDE statements with both "--" and <-->
  48.                 syntax and with a full fileid in the quotes.
  49.             5)  Multiple input filenames on command line.
  50.  
  51.  
  52.         Converted to Microsoft C V5.0 with enhancements.
  53.         November/December 1987.
  54.  
  55.                 Fred C. Smith
  56.                 20 Whipple Ave.
  57.                 Stoneham, MA 02180
  58.  
  59.         Enhancements/modifications include:
  60.  
  61.         1)  Call to reargv() at beginning of main(). If you are running
  62.             Allen Holub's Unix-like shell, reargv() will rebuild argc/argv
  63.             to contain the 2kbyte command-line which the shell provides.
  64.             If not using that shell, reargv is a no-op. (That shell is
  65.             available from M&T Books for around $40, including source!)
  66.         2)  Modify the include file lookups to use the same algorithm as
  67.             used by the Microsoft C compiler, i.e., look first in the
  68.             current directory for quote-delimited files. If a complete
  69.             pathname is specified look there only then quit. Any remaining
  70.             includes, including '<' or '"' delimited ones are then
  71.             searched for in the place(s) (if any) specified in the
  72.             optional parameter to the -i switch. If not found there,
  73.             searches the pathname(s) specified in the INCLUDE environment
  74.             variable.
  75.         3)  Modify the -i switch so that an optional trailing argument
  76.             specifies an alternate path for the includes, as in the -I
  77.             switch in the Microsoft C compiler's "cl" command. Multiple
  78.             -i switches may be given, each with a single pathname. These
  79.             multiple pathnames are saved in the order given.
  80.         4)  Make the default behavior to assume that comments are NOT
  81.             nested. Some PC-based C compilers (e.g. Lattice) support
  82.             nested comments, but Microsoft's does not. Also, those on
  83.             Unix and other larger systems do not. The ANSI standard
  84.             does not. For those who prefer to have support for nested
  85.             comments, a new command-line switch has been added so that
  86.             you can (optionally) have your cake, and eat it, too!
  87.         5)  Add recognition of keywords recognized in ANSI C, i.e.,
  88.             const, enum, signed, volatile, void. Remove recognition of
  89.             entry as a keyword (not in ANSI C). Also, add optional
  90.             recognition of Microsoft-specific keywords: cdecl, far,
  91.             fortran, huge, near and pascal. Use the -m switch for this
  92.             last group.
  93.         6)  Fix the awful kludge which previously existed in xc, in
  94.             which struct rf_blk.ref_cnt was declared as an int, but
  95.             under certain circumstances was used to hold a pointer to
  96.             a struct rf_blk. Replaced the declaration of ref_cnt as
  97.             an int with an appropriately declared union of the two
  98.             types needed.
  99.         7)  Minor tweaks to proc_file to fix incorrect line numbers
  100.             being generated around included files.
  101.         8)  In fil_chr(), used ferror() and feof() to implement the
  102.             original error-checking logic which had been commented
  103.             out in previous versions of the code.
  104.  
  105.     Version 1.1 -- April 1988:
  106.  
  107.         Microsoft-isms removed by William C. Colley, III.  In particular
  108.         the function access() is not available in many environments.  A
  109.         reorganization of the code eliminates the use of this function.  Note,
  110.         however, that the function open_include_file() does chop on file names
  111.         which is an inherently non-portable operation, so that function will
  112.         have to be cut to fit different operating systems' file naming
  113.         conventions.  Also, the call to getenv() may have to be modified or
  114.         removed.
  115.  
  116.         Also, added the -x option to remove the directories specified in the
  117.         INCLUDE environment variable from the search path for #include files.
  118.         WCC3.
  119.  
  120.     Abstract:
  121.  
  122.         'XC' is a cross-reference utility for 'C' programs.  Its has the
  123.         ability to handle nested include files to a depth of 8 levels and
  124.         properly processes nested comments as supported by BDS C. Option flags
  125.         support the following features:
  126.  
  127.             - Routing of list output to disk
  128.             - Cross-referencing of reserved words
  129.             - Processing of nested include files
  130.             - Generation of listing only
  131.  
  132.         Usage: xc <filename> <flag(s)>
  133.  
  134.         Flags:  -c                = Recognize Mapper C keywords
  135.                 -i [pathname]     = Enable file inclusion
  136.                 -l                = Generate listing only
  137.                 -m                = Recognize Microsoft-specific keywords
  138.                 -n                = Allow nested comments
  139.                 -o <filename>     = Write output to named file
  140.                 -p                = Exclude page breaks
  141.                 -r                = Cross-ref reserved words
  142.                 -w <width>        = Maximum listing width
  143.                 -x                = Exclude default include file dir's
  144.  
  145.         Note:   For the -i option, the pathname is optional.  The -i flag may
  146.                 be given multiple times, each time with a pathname. These
  147.                 pathnames are saved, building a list of places to search for
  148.                 include files.  If no list is given the standard places will
  149.                 be used.  If the -i option flag is not used, includes will not
  150.                 be cross-referenced.
  151.  
  152. ***********************************************************/
  153.  
  154. /* Compiler specific stuff */
  155.  
  156. #define LINT_ARGS
  157. #include <stdio.h>
  158. #include <stdlib.h>
  159. #include <ctype.h>
  160. #include <alloc.h>         /* was malloc.h dnh 7/21/89 */
  161. #include <string.h>
  162. #include <dos.h>           /* DNH 10/16/89 */
  163. #undef LINT_ARGS
  164.  
  165. /* end compiler specific section */
  166.  
  167. /* Function declarations for xc's routines. */
  168.  
  169. #include "xc2.h"
  170.  
  171. #ifndef TRUE
  172. #define TRUE        1
  173. #define FALSE       0
  174. #endif
  175.  
  176. #define INDENT      15
  177. #define DUMMY       0       /* a dummy integer value */
  178. #define ERROR       -1
  179. #define MAX_REF     5       /* maximum refs per ref-block */
  180. #define MAX_LEN     32      /* maximum identifier length */
  181. /* was 20 dnh 7/21/89 - deeper error !! */
  182. #define MAX_WRD     749     /* maximum number of identifiers */
  183. #define MAX_ALPHA   53      /* maximum alpha chain heads */
  184. #define REFS_PER_LINE 10    /* maximum refs per line */
  185. #define LINES_PER_PAGE 57
  186. #define MAXCOL      78      /* default max column number for listing line */
  187. #define MINCOL      30      /* minimum value for -w option */
  188. #define PATHLEN     128     /* maximum pathname length in chars. */
  189. #define FF          0x0C    /* formfeed */
  190.  
  191. /*      typedef union {
  192.     int cnt;
  193.     struct rf_blk *pnext;
  194. } cnt;               */
  195.  
  196. struct rf_blk {
  197.    int           ref_item[MAX_REF];
  198.    int           ref_cnt;
  199.    struct rf_blk *pnext;
  200. onerf;
  201.  
  202. struct id_blk {
  203.    char id_name[MAX_LEN];
  204.    struct id_blk *alpha_lnk;
  205.    struct rf_blk *top_lnk;
  206.    struct rf_blk *lst_lnk;
  207. oneid;
  208.  
  209. struct id_blk *id_vector[MAX_WRD];
  210.  
  211. struct alpha_hdr {
  212.    struct id_blk *alpha_top;
  213.    struct id_blk *alpha_lst;
  214. };
  215.  
  216. struct alpha_hdr alpha_vector[MAX_ALPHA];
  217.  
  218. struct date today;
  219.  
  220. struct time now;
  221.  
  222. int lin_refs = (MAXCOL-30)/5; /* max refs on a printed line */
  223. int linum;              /* line number */
  224. int edtnum = 0;         /* edit line number */
  225. int fil_cnt = 0;        /* active file index */
  226. int wrd_cnt = 0;        /* token count */
  227. int pagno = 0;          /* page number */
  228. int id_cnt = 0;         /* number of unique identifiers */
  229. int rhsh_cnt = 0;       /* number of conflict hits */
  230. int filevl = 0;         /* file level  */
  231. int paglin = 0;         /* page line counter */
  232. int maxcol = MAXCOL;    /* maximum right column for listing line */
  233. int prt_ref = FALSE;
  234. char act_fil[PATHLEN];
  235. char lst_fil[PATHLEN];
  236. char gbl_fil[PATHLEN];
  237. char gbl_trc[PATHLEN];
  238. char i_path[PATHLEN];
  239. FILE *f_lst_fil;
  240. int c_flg = FALSE;
  241. int i_flg = FALSE;
  242. int l_flg = FALSE;
  243. int m_flg = FALSE;
  244. int n_flg = FALSE;
  245. int o_flg = FALSE;
  246. int p_flg = FALSE;
  247. int r_flg = FALSE;
  248. int x_flg = FALSE;
  249. int in_refs = 0;
  250.  
  251. /*************************************************************************/
  252.  
  253. int main(p_argc, p_argv)
  254. int p_argc;
  255. char **p_argv;
  256. {
  257.    char *arg, **argv;
  258.    int argc, i;
  259.    FILE *f;
  260.  
  261. #ifdef REARGV
  262.    reargv (&p_argc, &p_argv);
  263. #endif
  264.  
  265.    argc = p_argc;  
  266.    argv = p_argv;
  267.    if (argc < 2) 
  268.       use_err();
  269.    while (--argc)
  270.       if (*(arg = *++argv) == '-')
  271.          switch (*++arg) {
  272.  
  273.          case 'c':
  274.          case 'C':
  275.             c_flg++;
  276.             break;
  277.  
  278.          case 'i':
  279.          case 'I':
  280.             i_flg = TRUE;
  281.             if (argc > 1 && **(argv + 1) != '-' && **(argv + 1)) {
  282.                if (strlen(i_path)) {
  283.                   strcat(i_path,";");
  284.                   strcat(i_path,*++argv);
  285.                } 
  286.                else
  287.                   strcpy(i_path,*++argv);
  288.             } 
  289.             else
  290.                i_path[0] = '\0';
  291.             if (i_path[0] == '-')
  292.                use_err();
  293.             break;
  294.  
  295.          case 'l':
  296.          case 'L':
  297.             l_flg++;
  298.             break;
  299.  
  300.          case 'm':
  301.          case 'M':
  302.             m_flg++;
  303.             break;
  304.  
  305.          case 'n':
  306.          case 'N':
  307.             n_flg++;
  308.             break;
  309.  
  310.          case 'o':
  311.          case 'O':
  312.             o_flg++;
  313.             if (!--argc)
  314.                use_err();
  315.             strcpy(lst_fil,*++argv);
  316.             if (lst_fil[0] == '-')
  317.                use_err();
  318.             break;
  319.  
  320.          case 'p':
  321.          case 'P':
  322.             p_flg++;
  323.             break;
  324.  
  325.          case 'r':
  326.          case 'R':
  327.             r_flg++;
  328.             break;
  329.  
  330.          case 'w':
  331.          case 'W':
  332.             if (!--argc)
  333.                use_err();
  334.             if ((i = atoi(*++argv)) <= MINCOL || i >= 255)
  335.                use_err();
  336.             maxcol = i;
  337.             lin_refs = (maxcol-30)/5;
  338.             break;
  339.  
  340.          case 'x':
  341.          case 'X':
  342.             x_flg++;
  343.             break;
  344.  
  345.          default:
  346.             use_err();
  347.             break;
  348.          }
  349.  
  350.    getdate(&today);
  351.    gettime(&now);
  352.    if (o_flg) {
  353.       if (!(f_lst_fil = fopen(lst_fil,"w"))) {
  354.          printf("ERROR: Unable to create list file - %s\n",lst_fil);
  355.          exit(0);
  356.       }
  357.       printf("XC ... 'C' Concordance Utility  v1.0\n\n");
  358.    }
  359.    for (linum = 0;  linum < MAX_WRD;  ++linum)
  360.       id_vector[linum] = NULL;
  361.    for (linum = 0; linum < MAX_ALPHA; ++linum)
  362.       alpha_vector[linum].alpha_top = alpha_vector[linum].alpha_lst = NULL;
  363.    linum = 0;
  364.    while (--p_argc && **++p_argv != '-') {
  365.       strcpy(gbl_fil,*p_argv);  
  366.       strcpy(act_fil,*p_argv);
  367.       i = 0;
  368.       while ((gbl_fil[i] != '.') & (gbl_fil[i] != 0x00)) {
  369.          gbl_trc[i] = gbl_fil[i];
  370.          i++;
  371.       }
  372.       gbl_trc[i] = 0x00;
  373.       if (!(f = fopen(gbl_fil,"r")))
  374.          printf("\nERROR: Unable to open input file: %s\n",gbl_fil);
  375.       else
  376.          proc_file(f,DUMMY);
  377.    }
  378.    if (!l_flg) {
  379.       prnt_tbl();
  380.       printf("\nAllowable Symbols: %d\n",MAX_WRD);
  381.       printf("   Unique Symbols: %d\n",id_cnt);
  382.    }
  383.    if (o_flg) {
  384.       fprintf(f_lst_fil,"     %d symbols\n",id_cnt);
  385.       echo(FF);
  386.       fclose(f_lst_fil);
  387.    }
  388.    return 0;
  389. }
  390.  
  391. /*************************************************************************/
  392.  
  393. void lst_err()
  394. {
  395.    printf("\nERROR: Write error on list output file - %s\n", lst_fil);
  396.    exit(0);
  397. }
  398.  
  399. /*************************************************************************/
  400.  
  401. void use_err()
  402. {
  403.    printf("\nERROR: Invalid parameter specification\n\n");
  404.    printf("Usage: xc <filename>... <flag(s)>\n\n");
  405.    printf("Flags: -c                = Recognize Mapper C keywords\n");
  406.    printf("       -i <opt. path(s)> = Enable file inclusion\n");
  407.    printf("       -l                = Generate listing only\n");
  408.    printf("       -m                = Recognize Microsoft keywords\n");
  409.    printf("       -n                = Allow nested comments\n");
  410.    printf("       -o <outfile>      = Write output to named file\n");
  411.    printf("       -p                = Exclude page headers\n");
  412.    printf("       -r                = Cross-reference reserved words\n");
  413.    printf("       -w width          = Width of output page; default=78\n");
  414.    printf("       -x                = Exclude default include file dir's\n");
  415.    printf("Flags must follow all input file names");
  416.    exit(0);
  417. }
  418.  
  419. /*************************************************************************/
  420.  
  421. int proc_file(infile,incnum)
  422. FILE *infile;
  423. int incnum;         /* prev. included line number (return to caller) */
  424. {
  425.    char token[MAX_LEN];    /* token buffer */
  426.    char cur_fil[PATHLEN];  /* name of file we are currently processing */
  427.    int eof_flg;            /* end-of-file indicator */
  428.    int tok_len;            /* token length */
  429.    char nl_flg;            /* newline flag */
  430.    FILE *f, *get_include_file();
  431.  
  432.    edtnum=0;
  433.    if (!filevl++)
  434.       prt_hdr();
  435.    else
  436.       nl();
  437.    eof_flg = FALSE;
  438.    do {
  439.       nl_flg = 0;
  440.       if (get_token(infile,token,&tok_len,&eof_flg,0)) {
  441.          if (token[tok_len] == '\n') { /* fix for doing nl() early */
  442.             token[tok_len] = '\0';
  443.             nl_flg = 1;
  444.          }
  445.          if (chk_token(token))
  446.             if (!strcmp(token,"#include")) {
  447.                strcpy(cur_fil,act_fil);
  448.                if (f = get_include_file(infile))
  449.                   edtnum = proc_file(f,edtnum);
  450.                else
  451.                   if (i_flg)
  452.                      printf("\nERROR: Unable to open input file: %s\n", act_fil);
  453.                strcpy(act_fil,cur_fil);
  454.             } 
  455.             else
  456.                if (nl_flg)
  457.                   put_token(token,linum - 1);
  458.                else
  459.                   put_token(token,linum);
  460.       }
  461.    } 
  462.    while (!eof_flg);
  463.  
  464.    --filevl;
  465.    fclose(infile);
  466.    return incnum;
  467. }
  468.  
  469. /*****************************************************************************
  470.  *  Reads the include filename from the source file and saves it into a global
  471.  *  variable, act_fil[].  It is assumed that the include statement gives the
  472.  *  filename only, without any drive specifier or path, as in the previous
  473.  *  version of XC.  Calls open_include_file() to flesh out the filename into a
  474.  *  full pathname and actually get the file opened.
  475.  */
  476.  
  477. FILE *get_include_file(infile)
  478. FILE *infile;
  479. {
  480.    char c, term, *p;
  481.    FILE *open_include_file();
  482.  
  483.    p = act_fil;
  484.  
  485.    while ((term = getc(infile)) == ' ')
  486.       echo(term);
  487.    echo(term);
  488.    if (term == '<')
  489.       term = '>';    /* terminator is > or " */
  490.    if ((term != '>') && (term != '"')) {
  491.       printf("Error scanning #INCLUDE fileid: %c\n",term);
  492.       exit(1);
  493.    }
  494.  
  495.    do {
  496.       if ((c = getc(infile)) != ' ')
  497.          *p++ = c;
  498.       echo(c);
  499.    } 
  500.    while (c != term);
  501.    *--p = '\0';
  502.  
  503.    if (i_flg)
  504.       return open_include_file(act_fil,term);
  505.    else
  506.       return NULL;
  507. }
  508.  
  509. /*************************************************************************/
  510.  
  511. FILE *open_include_file(filenam,delim)
  512. char *filenam, delim;
  513. {
  514.    char fullnam[PATHLEN];
  515.    char includevar[4 * PATHLEN];
  516.    char *temp1, *temp2;
  517.    int include_len;
  518.    FILE *f;
  519.  
  520.    /*
  521.     *  First, if delimited by quotes and file exists in current directory, return
  522.     *  a file handle for the opened file.  Next, if a complete pathname
  523.     *  specified, return a file handle for the opened file or NULL if the file
  524.     *  cannot be found.
  525.     */
  526.  
  527.    if (delim == '"' && (f = fopen(filenam,"r")))
  528.       return f;
  529.    if (filenam[1] == ':' || filenam[0] == '\\' || filenam[0] == '/')
  530.       return fopen(filenam,"r");
  531.  
  532.    /*
  533.     *  Next, if a non-null pathname was provided with the -i switch, check in
  534.     *  that place.  Finally, check in the places specified by the INCLUDE
  535.     *  environment variable unless the -x switch was used.
  536.     */
  537.  
  538.    if (i_path[0] || (temp1 = getenv("INCLUDE"))) {
  539.       strcpy(includevar,";");
  540.       if (i_path[0]) {
  541.          strcat(includevar,i_path);
  542.          strcat(includevar,";");
  543.       }
  544.       if (!x_flg)
  545.          strcat(includevar,temp1);
  546.       include_len = strlen(temp2 = includevar);
  547.  
  548.       /*
  549.        *  Break up the semicolon-delimited list of directories into
  550.        *  null-terminated strings and check each of them.
  551.        */
  552.  
  553.       while (include_len > 0) {
  554.          for (temp1 = temp2;  *temp2 != ';' && *temp2;  ++temp2)
  555.             --include_len;
  556.          if (*temp2 == ';') {
  557.             *temp2++ = '\0';
  558.             --include_len;
  559.          }
  560.          strcpy(fullnam,temp1);
  561.          strcat(fullnam,"\\");
  562.          strcat(fullnam,filenam);
  563.          if (f = fopen(fullnam,"r"))
  564.             return f;
  565.       }
  566.    }
  567.    return NULL;
  568. }
  569.  
  570. /*************************************************************************/
  571.  
  572. void echo(c)
  573. char c;
  574. {
  575.    static int col = INDENT;
  576.    int i;
  577.  
  578.    if (!p_flg | (p_flg & (c != FF)))
  579.       echochar(c);
  580.    if (c == '\n')
  581.       col = INDENT;
  582.    else
  583.       if (++col > (maxcol + 1)) {
  584.          col = INDENT;
  585.          ++paglin;
  586.          echochar('\n');
  587.          for (i = 1;  i <= INDENT;  ++i)
  588.             echochar(' ');
  589.       }
  590. }
  591. /************************************************************/
  592. void echochar(c)
  593. char c;
  594. {
  595.    if (o_flg) {
  596.       if (fprintf(f_lst_fil,"%c",c) == ERROR)
  597.          lst_err();
  598.    } 
  599.    else
  600.       printf("%c",c);
  601. }
  602.  
  603. /*************************************************************************/
  604.  
  605. int get_token(infile,g_token,g_toklen,g_eoflg,g_flg)
  606. FILE *infile;
  607. char *g_token;
  608. int *g_toklen, *g_eoflg, g_flg;
  609. {
  610.  
  611.    /*
  612.            'getoken' returns the next valid identifier or
  613.            reserved word from a given file along with the
  614.            character length of the token and an end-of-file
  615.            indicator
  616.    */
  617.  
  618.    int c;
  619.    char *h_token, tmpchr;
  620.  
  621.    h_token = g_token;
  622.  
  623. gtk:
  624.    *g_toklen = 0;
  625.    g_token = h_token;
  626.  
  627.    /*
  628.            Scan and discard any characters until an alphabetic or
  629.            '_' (underscore) character is encountered or an end-of-file
  630.            condition occurs
  631.    */
  632.  
  633.    while ((!isalpha(*g_token = rdchr(infile,g_eoflg,g_flg)))
  634.        && !*g_eoflg && *g_token != '_' && *g_token != '0'
  635.        && *g_token != '#');
  636.  
  637.    if (*g_eoflg)
  638.       return FALSE;
  639.    *g_toklen += 1;
  640.  
  641.    /*
  642.            Scan and collect identified alpanumeric token until
  643.            a non-alphanumeric character is encountered or and
  644.            end-of-file condition occurs
  645.    */
  646.  
  647.    if (g_flg)
  648.       tmpchr = '.';
  649.    else
  650.       tmpchr = '_';
  651.    while ((isalpha(c = rdchr(infile,g_eoflg,g_flg))
  652.        || isdigit(c) || c == '_' || c == tmpchr) && !*g_eoflg)
  653.       if (*g_toklen < MAX_LEN) {
  654.          *++g_token = c;
  655.          ++*g_toklen;
  656.       } 
  657.       else
  658.          *g_token = NULL;
  659.  
  660.    /*
  661.            Check to see if a numeric hex or octal constant has
  662.            been encountered ... if so dump it and try again
  663.    */
  664.  
  665.    if (*h_token == '0')
  666.       goto gtk;
  667.  
  668.    /*
  669.            Tack a NUL character onto the end of the token
  670.    */
  671.    if ((*h_token != '#') && (c == '\n'))
  672.       *++g_token = c;
  673.    else
  674.       *++g_token = '\0';
  675.  
  676.    /*
  677.            Screen out all #token strings except #include
  678.    */
  679.  
  680.    if (*h_token == '#' && strcmp(h_token,"#include"))
  681.       goto gtk;
  682.  
  683.    return(TRUE);
  684. }
  685.  
  686. /*************************************************************************/
  687.  
  688. int fil_chr(infile,f_eof)
  689. FILE *infile;
  690. int *f_eof;
  691. {
  692.    int fc;
  693.  
  694.    if ((fc = getc(infile)) == EOF)
  695.       if (ferror (infile)) {
  696.          printf("\nERROR: Error while processing input file - %s\n",
  697.          act_fil);
  698.          exit(0);
  699.       } 
  700.       else
  701.          if (feof(infile)) {
  702.             *f_eof = TRUE;
  703.             fc = NULL;
  704.          }
  705.  
  706.    return fc;
  707. }
  708.  
  709. /*************************************************************************/
  710.  
  711. int rdchr(infile,r_eoflg,rd_flg)
  712. FILE *infile;
  713. int *r_eoflg, rd_flg;
  714. {
  715.  
  716.    /*
  717.            'rdchr' returns the next valid character in a file
  718.            and an end-of-file indicator. A valid character is
  719.            defined as any which does not appear in either a
  720.            commented or a quoted string ... 'rdchr' will correctly
  721.            handle comment tokens which appear within a quoted
  722.            string
  723.    */
  724.  
  725.    int c;
  726.    int q_flg;          /* double quoted string flag */
  727.    int q1_flg;         /* single quoted string flag */
  728.    int cs_flg;         /* comment start flag */
  729.    int ce_flg;         /* comment end flag */
  730.    int c_cnt;          /* comment nesting level */
  731.    int t_flg;          /* transparency flag */
  732.  
  733.    q_flg = q1_flg = cs_flg = ce_flg = t_flg = FALSE;
  734.    c_cnt  = 0;
  735.  
  736. rch:
  737.  
  738.    /*
  739.            Fetch character from file
  740.    */
  741.  
  742.    c = fil_chr(infile,r_eoflg);
  743.    if (*r_eoflg)
  744.       return c;        /* EOF encountered */
  745.    if (c == '\n')
  746.       nl();
  747.    else
  748.       echo(c);
  749.  
  750.    if (rd_flg)
  751.       return c;
  752.  
  753.    if (t_flg) {
  754.       t_flg = !t_flg;
  755.       goto rch;
  756.    }
  757.    if (c == '\\') {
  758.       t_flg = TRUE;
  759.       goto rch;
  760.    }
  761.  
  762.    /*
  763.            If the character is not part of a quoted string
  764.            check for and process commented strings...
  765.            nested comments are handled correctly but unbalanced
  766.            comments are not ... the assumption is made that
  767.            the syntax of the program being xref'd is correct.
  768.      NOTE: Now nested comment support is optional. The source for XC
  769.            formerly contained an un-matched begin comment. If nested
  770.            comment support is used to cross-reference the xc source
  771.            the program produces an incorrect cross-reference, yet
  772.            the Microsoft compiler compiles it correctly, as it
  773.            should. Nested comments are a non-standard extension to
  774.            the language. Therefore, nested comment support has been made
  775.            optional.
  776.            See usage information in comment at top of file.
  777.    */
  778.  
  779.    if (!q_flg && !q1_flg) {
  780.       if (c == '*' && c_cnt && !cs_flg) {
  781.          ce_flg = TRUE;
  782.          goto rch;
  783.       }
  784.       if (c == '/' && ce_flg) {
  785.          c_cnt -= 1;
  786.          ce_flg = FALSE;
  787.          goto rch;
  788.       }
  789.       ce_flg = FALSE;
  790.       if (c == '/') {
  791.          cs_flg = TRUE;
  792.          goto rch;
  793.       }
  794.       if (c == '*' && cs_flg) {
  795.          c_cnt = (!n_flg) ? TRUE : c_cnt + 1; /* optional nested comments */
  796.          cs_flg = FALSE;
  797.          goto rch;
  798.       }
  799.       cs_flg = FALSE;
  800.       if (c_cnt)
  801.          goto rch;
  802.    }
  803.  
  804.    /*
  805.            Check for and process quoted strings
  806.    */
  807.  
  808.    if (c == '"' && !q1_flg) {
  809.       q_flg = !q_flg;        /* toggle quote flag */
  810.       goto rch;
  811.    }
  812.    if (q_flg)
  813.       goto rch;
  814.  
  815.    if (c == '\'') {
  816.       q1_flg = !q1_flg;       /* toggle quote flag */
  817.       goto rch;
  818.    }
  819.    if (q1_flg)
  820.       goto rch;
  821.  
  822.    /*
  823.            Valid character ... return to caller
  824.    */
  825.  
  826.    return c;
  827. }
  828.  
  829. /*************************************************************************/
  830.  
  831. int chk_token(c_token)
  832. char *c_token;
  833. {
  834.    char u_token[MAX_LEN];
  835.    int i;
  836.  
  837.    if (r_flg)
  838.       return TRUE;
  839.    i = 0;
  840.    do
  841.        u_token[i] = toupper(c_token[i]);
  842.    while (c_token[i++] != NULL);
  843.  
  844.    /*
  845.     *  Support for the Microsoft extended keywords.
  846.     */
  847.  
  848.    if (m_flg)
  849.       switch (u_token[0]) {
  850.       case 'C':
  851.          if (!strcmp(u_token,"CDECL")) 
  852.             return FALSE;
  853.          break;
  854.       case 'F':
  855.          if (!strcmp(u_token,"FORTRAN")) 
  856.             return FALSE;
  857.          if (!strcmp(u_token,"FAR")) 
  858.             return FALSE;
  859.          break;
  860.       case 'H':
  861.          if (!strcmp(u_token,"HUGE")) 
  862.             return FALSE;
  863.          break;
  864.       case 'N':
  865.          if (!strcmp(u_token,"NEAR")) 
  866.             return FALSE;
  867.          break;
  868.       case 'P':
  869.          if (!strcmp(u_token,"PASCAL")) 
  870.             return FALSE;
  871.          break;
  872.       case '_':
  873.          if (!strcmp(u_token,"_CDECL")) 
  874.             return FALSE;
  875.          if (!strcmp(u_token,"_FAR")) 
  876.             return FALSE;
  877.          break;
  878.       }
  879.  
  880.    /*
  881.     *  Support for the Mapper C keywords.
  882.     */
  883.  
  884.    if (c_flg)
  885.       switch (u_token[0]) {
  886.       case 'I':
  887.          if (!strcmp(u_token,"INTERNAL_NUMBER")) 
  888.             return FALSE;    
  889.          break;
  890.       case 'K':
  891.          if (!strcmp(u_token,"KONST")) 
  892.             return FALSE;    
  893.          break;
  894.       case 'L':
  895.          if (!strcmp(u_token,"LINT")) 
  896.             return FALSE;
  897.          if (!strcmp(u_token,"LO8")) 
  898.             return FALSE;
  899.          break;
  900.       case 'M':
  901.          if (!strcmp(u_token,"MO8")) 
  902.             return FALSE;
  903.          break;
  904.       case 'N':
  905.          if (!strcmp(u_token,"NORET")) 
  906.             return FALSE;
  907.          break;
  908.       case 'S':
  909.          if (!strcmp(u_token,"SINT")) 
  910.             return FALSE;
  911.          break;
  912.       case 'U':
  913.          if (!strcmp(u_token,"ULINT")) 
  914.             return FALSE;
  915.          if (!strcmp(u_token,"USINT")) 
  916.             return FALSE;
  917.          break;
  918.       }
  919.  
  920.    /*
  921.     *  Standard keyword support.
  922.     */
  923.  
  924.    switch (u_token[0]) {
  925.    case 'A':
  926.       if (!strcmp(u_token,"AUTO")) 
  927.          return FALSE;
  928.       break;
  929.    case 'B':
  930.       if (!strcmp(u_token,"BREAK")) 
  931.          return FALSE;
  932.       break;
  933.    case 'C':
  934.       if (!strcmp(u_token,"CHAR")) 
  935.          return  FALSE;
  936.       if (!strcmp(u_token,"CONTINUE")) 
  937.          return  FALSE;
  938.       if (!strcmp(u_token,"CONST")) 
  939.          return  FALSE;
  940.       if (!strcmp(u_token,"CASE")) 
  941.          return  FALSE;
  942.       break;
  943.    case 'D':
  944.       if (!strcmp(u_token,"DOUBLE")) 
  945.          return FALSE;
  946.       if (!strcmp(u_token,"DO")) 
  947.          return FALSE;
  948.       if (!strcmp(u_token,"DEFAULT")) 
  949.          return FALSE;
  950.       break;
  951.    case 'E':
  952.       if (!strcmp(u_token,"EXTERN")) 
  953.          return FALSE;
  954.       if (!strcmp(u_token,"ELSE")) 
  955.          return FALSE;
  956.       if (!strcmp(u_token,"ENUM")) 
  957.          return FALSE;
  958.       break;
  959.    case 'F':
  960.       if (!strcmp(u_token,"FLOAT")) 
  961.          return FALSE;
  962.       if (!strcmp(u_token,"FOR")) 
  963.          return FALSE;
  964.       break;
  965.    case 'G':
  966.       if (!strcmp(u_token,"GOTO")) 
  967.          return FALSE;
  968.       break;
  969.    case 'I':
  970.       if (!strcmp(u_token,"INT")) 
  971.          return FALSE;
  972.       if (!strcmp(u_token,"IF")) 
  973.          return FALSE;
  974.       break;
  975.    case 'L':
  976.       if (!strcmp(u_token,"LONG")) 
  977.          return FALSE;
  978.       break;
  979.    case 'R':
  980.       if (!strcmp(u_token,"RETURN")) 
  981.          return FALSE;
  982.       if (!strcmp(u_token,"REGISTER")) 
  983.          return FALSE;
  984.       break;
  985.    case 'S':
  986.       if (!strcmp(u_token,"STRUCT")) 
  987.          return FALSE;
  988.       if (!strcmp(u_token,"SHORT")) 
  989.          return FALSE;
  990.       if (!strcmp(u_token,"STATIC")) 
  991.          return FALSE;
  992.       if (!strcmp(u_token,"SIZEOF")) 
  993.          return FALSE;
  994.       if (!strcmp(u_token,"SWITCH")) 
  995.          return FALSE;
  996.       if (!strcmp(u_token,"SIGNED")) 
  997.          return FALSE;
  998.       break;
  999.    case 'T':
  1000.       if (!strcmp(u_token,"TYPEDEF")) 
  1001.          return FALSE;
  1002.       break;
  1003.    case 'U':
  1004.       if (!strcmp(u_token,"UNION")) 
  1005.          return FALSE;
  1006.       if (!strcmp(u_token,"UNSIGNED")) 
  1007.          return FALSE;
  1008.       break;
  1009.    case 'V':
  1010.       if (!strcmp(u_token,"VOID")) 
  1011.          return FALSE;
  1012.       if (!strcmp(u_token,"VOLATILE")) 
  1013.          return FALSE;
  1014.       break;
  1015.    case 'W':
  1016.       if (!strcmp(u_token,"WHILE")) 
  1017.          return FALSE;
  1018.       break;
  1019.    }
  1020.    return TRUE;
  1021. }
  1022.  
  1023. /*************************************************************************/
  1024.  
  1025. /*
  1026.    Install parsed token and line reference in linked structure
  1027. */
  1028.  
  1029. void put_token(p_token,p_ref)
  1030. char *p_token;
  1031. int p_ref;
  1032. {
  1033.    int hsh_index, i, j, d, found;
  1034.    struct id_blk *idptr;
  1035.    struct id_blk *alloc_id();
  1036.    struct rf_blk *alloc_rf(), *add_rf();
  1037.  
  1038.    if (l_flg)
  1039.       return;
  1040.    j=0;
  1041.    for (i = 0;  p_token[i] != NULL;  ++i)      /* Hashing algorithm is far */
  1042.       j = j * 10 + p_token[i];                /* from optimal but is      */
  1043.    /* adequate for a memory-   */
  1044.    hsh_index = abs(j) % MAX_WRD;               /* bound index vector!      */
  1045.    found = FALSE;
  1046.    d = 1;
  1047.    do {
  1048.       idptr = id_vector[hsh_index];
  1049.       if (idptr == NULL) {
  1050.          id_cnt++;
  1051.          idptr = id_vector[hsh_index] = alloc_id(p_token);
  1052.          chain_alpha(idptr,p_token);
  1053.          idptr->top_lnk = idptr->lst_lnk = alloc_rf(p_ref);
  1054.          found = TRUE;
  1055.       } 
  1056.       else
  1057.          if (!strcmp(p_token,idptr->id_name)) {
  1058.             idptr->lst_lnk = add_rf(idptr->lst_lnk,p_ref);
  1059.             found = TRUE;
  1060.          } 
  1061.          else {
  1062.             hsh_index += d;  
  1063.             d += 2;  
  1064.             rhsh_cnt++;
  1065.             if (hsh_index >= MAX_WRD)
  1066.                hsh_index -= MAX_WRD;
  1067.             if (d == MAX_WRD) {
  1068.                printf("\nERROR: Symbol table overflow\n");
  1069.                exit(0);
  1070.             }
  1071.          }
  1072.    } 
  1073.    while (!found);
  1074. }
  1075.  
  1076. /*************************************************************************/
  1077.  
  1078. void chain_alpha(ca_ptr,ca_token)
  1079. struct id_blk *ca_ptr;
  1080. char  *ca_token;
  1081. {
  1082.    char c;
  1083.    struct id_blk *cur_ptr;
  1084.    struct id_blk *lst_ptr;
  1085.  
  1086.    if ((c = ca_token[0]) == '_')
  1087.       c = 0;
  1088.    else
  1089.       if (isupper(c))
  1090.          c = 1 + ((c - 'A') * 2);
  1091.       else
  1092.          c = 2 + ((c - 'a') * 2);
  1093.  
  1094.    if (!alpha_vector[c].alpha_top) {
  1095.       alpha_vector[c].alpha_top = alpha_vector[c].alpha_lst = ca_ptr;
  1096.       ca_ptr->alpha_lnk = NULL;
  1097.       return;
  1098.    }
  1099.  
  1100.    /*
  1101.        check to see if new id_blk should be inserted between
  1102.        the alpha_vector header block and the first id_blk in
  1103.        the current alpha chain
  1104.    */
  1105.  
  1106.    if (strcmp(alpha_vector[c].alpha_top->id_name,ca_token) > 0) {
  1107.       ca_ptr->alpha_lnk=alpha_vector[c].alpha_top;
  1108.       alpha_vector[c].alpha_top=ca_ptr;
  1109.       return;
  1110.    }
  1111.    if (strcmp(alpha_vector[c].alpha_lst->id_name,ca_token) < 0) {
  1112.       alpha_vector[c].alpha_lst->alpha_lnk = ca_ptr;
  1113.       ca_ptr->alpha_lnk = NULL;
  1114.       alpha_vector[c].alpha_lst=ca_ptr;
  1115.       return;
  1116.    }
  1117.    cur_ptr = alpha_vector[c].alpha_top;
  1118.    while (strcmp(cur_ptr->id_name,ca_token) < 0) {
  1119.       lst_ptr = cur_ptr;
  1120.       cur_ptr = lst_ptr->alpha_lnk;
  1121.    }
  1122.    lst_ptr->alpha_lnk = ca_ptr;
  1123.    ca_ptr->alpha_lnk = cur_ptr;
  1124.    return;
  1125. }
  1126.  
  1127. /*************************************************************************/
  1128.  
  1129. struct id_blk *alloc_id(aid_token)
  1130. char *aid_token;
  1131. {
  1132.    int ai;
  1133.    struct id_blk *aid_ptr;
  1134.  
  1135.    if (!(aid_ptr = (struct id_blk *)malloc(sizeof(struct id_blk)))) {
  1136.       printf("\nERROR: Unable to allocate identifier block\n");
  1137.       exit(0);
  1138.    }
  1139.    ai = 0;
  1140.    do
  1141.        aid_ptr->id_name[ai] = aid_token[ai];
  1142.    while (aid_token[ai++] != NULL);
  1143.    return aid_ptr;
  1144. }
  1145.  
  1146. /*************************************************************************/
  1147.  
  1148. struct rf_blk *alloc_rf(arf_ref)
  1149. int arf_ref;
  1150. {
  1151.    int ri;
  1152.    struct rf_blk *arf_ptr;
  1153.  
  1154.    if (!(arf_ptr = (struct rf_blk *)malloc(sizeof(struct rf_blk)))) {
  1155.       printf("\nERROR: Unable to allocate reference block\n");
  1156.       exit(0);
  1157.    }
  1158.    arf_ptr->ref_item[0] = arf_ref;
  1159.    arf_ptr->ref_cnt = 1;
  1160.    for (ri = 1;  ri < MAX_REF;  ++ri)
  1161.       arf_ptr->ref_item[ri] = NULL;
  1162.    arf_ptr->pnext = NULL;
  1163.    in_refs++;
  1164.    return arf_ptr;
  1165. }
  1166.  
  1167. /*************************************************************************/
  1168.  
  1169. struct rf_blk *add_rf(adr_ptr,adr_ref)
  1170. struct rf_blk *adr_ptr;
  1171. int adr_ref;
  1172. {
  1173.    struct rf_blk *tmp_ptr;
  1174.  
  1175.    tmp_ptr = adr_ptr;
  1176.    if (adr_ptr->ref_cnt == MAX_REF) {
  1177.       tmp_ptr = alloc_rf(adr_ref);
  1178.       adr_ptr->pnext = tmp_ptr;
  1179.       in_refs--;
  1180.    } 
  1181.    else
  1182.       adr_ptr->ref_item[adr_ptr->ref_cnt++] = adr_ref;
  1183.    in_refs++;
  1184.    return tmp_ptr;
  1185. }
  1186.  
  1187. /*************************************************************************/
  1188.  
  1189. void prnt_tbl()
  1190. {
  1191.    int prf_cnt, pti, pref, lin_cnt, refs=0;
  1192.    struct id_blk *pid_ptr;
  1193.    struct rf_blk *ptb_ptr;
  1194.  
  1195.    prt_ref = TRUE;
  1196.    prt_hdr();
  1197.    for (pti = 0;  pti < MAX_ALPHA;  ++pti) {
  1198.       if (pid_ptr = alpha_vector[pti].alpha_top) {
  1199.          do {
  1200.             if (o_flg) {
  1201.                if (fprintf(f_lst_fil,"     %-20.19s:",pid_ptr->id_name)
  1202.                    == ERROR) lst_err();
  1203.             } 
  1204.             else
  1205.                printf("%-20.19s:",pid_ptr->id_name);
  1206.             ptb_ptr = pid_ptr->top_lnk;
  1207.             lin_cnt = -1;
  1208.             prf_cnt = 0;
  1209.             do {
  1210.                if (prf_cnt == MAX_REF) {
  1211.                   prf_cnt = 0;
  1212.                   ptb_ptr = (struct rf_blk *)ptb_ptr->pnext;
  1213.                }
  1214.                if (ptb_ptr) {
  1215.                   if (pref = ptb_ptr->ref_item[prf_cnt++]) {
  1216.                      refs += 1;
  1217.                      if (++lin_cnt == lin_refs) {   /* was REFS_PER_LINE dnh 7/21/89 */
  1218.                         nl();
  1219.                         if (o_flg) {
  1220.                            if (fprintf(f_lst_fil,
  1221.                            "                          ") == ERROR)
  1222.                               lst_err();
  1223.                         } 
  1224.                         else
  1225.                            printf("                          ");
  1226.                         lin_cnt=0;
  1227.                      }
  1228.                      if (o_flg) {
  1229.                         if (fprintf(f_lst_fil,"%5u",pref) == ERROR)
  1230.                            lst_err();
  1231.                      } 
  1232.                      else
  1233.                         printf("%5u",pref);
  1234.                   }
  1235.                }
  1236.                else
  1237.                   pref=0;
  1238.             } 
  1239.             while (pref);
  1240.             nl();
  1241.          } 
  1242.          while ((pid_ptr=pid_ptr->alpha_lnk) != NULL);
  1243.       }
  1244.    }
  1245.    /*for*/
  1246.    echo( '\n' );
  1247.    if (o_flg)
  1248.       if (fprintf(f_lst_fil, "  %6d references", refs) == ERROR)
  1249.          lst_err();
  1250.  
  1251.    printf("\n%6d references\n", refs);
  1252.    printf("%6d in_refs\n", in_refs);
  1253.    echo( '\n' );
  1254. }
  1255.  
  1256. /*************************************************************************/
  1257.  
  1258. void prt_hdr()
  1259. {
  1260.  
  1261.    if (pagno++) {
  1262.       echo('\n');
  1263.       echo(FF);
  1264.    }
  1265.  
  1266.    if (o_flg) {
  1267.       if (p_flg) {
  1268.          if (fprintf(f_lst_fil,
  1269.          "       'C' Concordance Utility   %-20s      Date:%d/%d/%02d %02d:%02d:%02d",
  1270.          gbl_trc, today.da_mon, today.da_day, today.da_year,
  1271.          now.ti_hour, now.ti_min, now.ti_sec)
  1272.              == ERROR) lst_err();
  1273.       } 
  1274.       else
  1275.          if (fprintf(f_lst_fil,
  1276.          "       'C' Concordance Utility   %-20s      Date:%d/%d/%02d %02d:%02d:%02d Page: %d",
  1277.          gbl_trc, today.da_mon, today.da_day, today.da_year,
  1278.          now.ti_hour, now.ti_min, now.ti_sec, pagno)
  1279.              == ERROR) lst_err();
  1280.    } 
  1281.    else
  1282.       printf("XC ... 'C' Concordance Utility   %-20s       Page %d", gbl_trc, pagno);
  1283.  
  1284.    echo('\n');
  1285.    paglin = 1;
  1286.    nl();
  1287.  
  1288. }
  1289.  
  1290. /*************************************************************************/
  1291.  
  1292. void nl()
  1293. {
  1294.    echo('\n');
  1295.  
  1296.    if (++paglin >= LINES_PER_PAGE & (!p_flg))
  1297.       prt_hdr();
  1298.    else
  1299.       if (!prt_ref) {
  1300.          if (o_flg) {
  1301.             if (fprintf(f_lst_fil,"     ") == ERROR)
  1302.                lst_err();
  1303.             ++linum;
  1304.             ++edtnum;
  1305.          } 
  1306.          else
  1307.             printf("%-4d %4d: ",++linum,++edtnum);
  1308.  
  1309.          if (o_flg)
  1310.             if (linum % 60 == 1)
  1311.                printf("\n<%04d> ",linum);
  1312.             else {
  1313.                printf(".");
  1314.                fflush(stdout);
  1315.             }
  1316.       }
  1317.    return;
  1318. }
  1319.  
  1320.  
  1321. /***************************************/
  1322.