home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / LANGUAGS / C / XC1E.LBR / XC1E.CZ / XC1E.C
Text File  |  2000-06-30  |  33KB  |  1,058 lines

  1. /***********************************************************/
  2. /*    Abstract:                        */
  3. /*                               */
  4. /*    'XC' is a cross-reference utility for 'C' programs.  */
  5. /*    Its has the ability to handle nested include files   */
  6. /*    to a depth of 8 levels and properly processes nested */
  7. /*    comments as supported by BDS C. Option flags support */
  8. /*    the following features:                   */
  9. /*                               */
  10. /*    - Routing of list output to disk               */
  11. /*    - Cross-referencing of reserved words           */
  12. /*    - Processing of nested include files           */
  13. /*    - Generation of listing only               */
  14. /*                               */
  15. /*    Usage: xc <filename> <flag(s)>               */
  16. /*                               */
  17. /*    Flags: -i        = Enable file inclusion       */
  18. /*         -l        = Generate listing only       */
  19. /*           -c            = Compressed print listing      */
  20. /*         -r        = Cross-ref reserved words       */
  21. /*         -o <filename> = Write output to named file    */
  22. /*                               */
  23. /*************************************************************************/
  24. /*  7-11-85  reworked for CPM 2      David Giunti
  25.     added conditional DOS to allow compilaton bye Aztec C
  26.         defining DOS at compilation will give MS DOS code
  27.         otherwise CPM code
  28.     changed nl() routine by define to allow Aztec to send a cr after
  29.         a lf , fputc becomes aputc  
  30.     changed prt_hdr() by define to omit time data for CPM
  31.     added ffdr(), called by prt_hdr() to save a page on printouts  
  32.     added conditionals MX for Epson and IDS for that printers
  33.         compressed headings, else the printers default is used 
  34. */
  35. /*  1-01-84  Enhancements               S.R. Jacobson                   */
  36. /*     - changed -e option to -c option and added two strings:           */
  37. /*            cprint_hdr sets the printer to compressed print mode       */
  38. /*            cprint_trlr resets the printer to "normal" mode            */
  39. /*         This makes it easier for non-epson printer users              */
  40. /*     -  removed all the BDS C comments (this makes it easier to modify */
  41. /*            in the future.                                             */
  42. /*     -  changed name of the utility to the "print" utility             */
  43. /*     -  if the -i flag is not used, the second line number will not    */
  44. /*            appear.                                                    */ 
  45. /*     -  if a form feed is detected in the source file, a new page is   */
  46. /*            started.  This is useful for structuring the source        */
  47. /*            code by placing each major section on a separate page.     */
  48. /*            You do this by embedding a form feed (control L) in a      */
  49. /*            comment.  The text following the form feed will be placed  */
  50. /*            on the top of the new page.                                */
  51. /*     -  tab characters in the file are expanded to every 8 positions.  */
  52. /*            This may be changed by changing the TABCNT define.         */
  53. /*     -  added the date and time to the printed output. (C-86 only)     */
  54. /*     -  fixed error in hashing algorithm.                 */
  55. /*     -  control characters (other than \n, \f, or \t) are stripped     */ 
  56. /*            from the input stream (converted to blanks).  This         */  
  57. /*            prevents extraneous control chars from interfering with    */
  58. /*            operation of xc.                         */
  59. /*     -  cleaned up the structuring of a number of routines.            */
  60. /*     -  added the file latest update date and time to the printed      */
  61. /*            output. ***DOS 2.0 ONLY ***                                */
  62. /*************************************************************************/
  63. /*   9-26-83   Microsoft C 1.04  Conversion    WHR             */
  64. /*     -  \t between line numbers and text to fix indenting problem.     */
  65. /*     -  added option -e for output to Epson in condensed print.     */
  66. /*     -  toupper() and isupper() are macros, not functions.         */
  67. /*     -  eliminate side effect in toupper(*++arg) in main().         */
  68. /*     -  change alloc() to malloc().                     */
  69. /*     -  add #define NAMES that are not in stdio.h             */
  70. /*     -  MS-C requires () in statement A?(c=B):(c=C)    error or not??     */
  71. /*                                     */
  72. /*   4-30-83   Computer Innovations C-86 1.31 Conversion    WHR      */
  73. /*     -  #include filename changed to allow a disk drive prefix, D:     */
  74. /*     -  convert if(fprintf(...) == ERROR) lst_err(); to fprintf(..);     */
  75. /*     -  convert if(fopen(...) == ERROR) statements to == NULL.     */
  76. /*     -  C86 requires () in statement A?(c=B):(c=C)    error or not??     */
  77. /*     -  remove getc() == ERROR check in fil_chr().             */
  78. /*     -  convert file conventions from BDS C to C-86.             */
  79. /*     -  comment out BDS unique statements, mark revised statements.     */
  80. /*      keep all BDS statements to document conversion effort.     */
  81. /*                                     */
  82. /**  4-19-83   BDS C Version file XC.CQ copied from Laurel RCPM    WHR     */
  83. /*************************************************************************/
  84. /*   **    Original Version: **                   */
  85. /*                               */
  86. /*    Version 1.0   January, 1982               */
  87. /*                               */
  88. /*    Copyright (c) 1982 by Philip N. Hisley           */
  89. /*                               */
  90. /*    Released for non-commercial distribution only       */
  91. /*                               */
  92. /*    Please report bugs/fixes/enhancements to:        */
  93. /*                               */
  94. /*          Philip N. Hisley                   */
  95. /*          548H Jamestown Court               */
  96. /*          Edgewood, Maryland 21040               */
  97. /*          (301) 679-4606                   */
  98. /*          Net Addr: PNH@MIT-AI               */
  99. /*                               */
  100. /*                               */
  101. /***********************************************************/
  102.  
  103. /*  DEFINITIONS AND VARIABLES  */                /*SRJ*/
  104.  
  105. #include "stdio.h"                          /* WHR */
  106.  
  107. #ifndef     DOS
  108. /* Copyright (C) 1984 by Manx Software Systems */
  109.  
  110. extern char ctp_[];
  111.  
  112. #define isalpha(x) (ctp_[(x)+1]&0x03)
  113. #define isupper(x) (ctp_[(x)+1]&0x01)
  114. #define islower(x) (ctp_[(x)+1]&0x02)
  115. #define isdigit(x) (ctp_[(x)+1]&0x04)
  116. #define iscntrl(x) (ctp_[(x)+1]&0x20)
  117.  
  118. FILE *fopen() ;
  119. /* #include "ctype.h"    */ /* include type tests */
  120. /* #undef    toupper    */    /* undefine Aztecs toupper macro  use librarys */
  121. #endif    /* ndef DOS */
  122.  
  123. #define     TABCNT        8        /* expand tabs to every 8 characters */  /*SRJ*/
  124. #define  NULL        0
  125. #define  FALSE        0                          /* WHR */
  126. #define  TRUE        1                          /* WHR */
  127. #define  CPMEOF   0x1A              /* end of file */       /* WHR */
  128. #define  ERROR      (-1)                          /* WHR */
  129.  
  130. #define  MAX_REF    5        /* maximum refs per ref-block */
  131.  
  132. #define  MAX_LEN    20        /* maximum identifier length  */
  133. #define  MAX_WRD   749        /* maximum number of identifiers */
  134. #define  MAX_ALPHA  53        /* maximum alpha chain heads */
  135. #define  REFS_PER_LINE    8    /* maximum refs per line */
  136. #define  LINES_PER_PAGE 60
  137.  
  138. struct    id_blk {
  139.          char  id_name[MAX_LEN];
  140.          struct id_blk *alpha_lnk;
  141.          struct rf_blk *top_lnk;
  142.          struct rf_blk *lst_lnk;
  143.            } oneid;
  144.  
  145. struct    rf_blk {
  146.          int  ref_item[MAX_REF];
  147.          int  ref_cnt;
  148.            } onerf;
  149.  
  150. struct id_blk *id_vector[MAX_WRD];
  151.  
  152. struct alpha_hdr { struct id_blk *alpha_top;
  153.            struct id_blk *alpha_lst;
  154.          };
  155.  
  156. struct alpha_hdr alpha_vector[MAX_ALPHA];
  157.  
  158. struct    regval    {int ax,bx,cx,dx,si,di,ds,es;} reg;  /* structure for sysint */ /*SRJ*/
  159. struct    regv    {int csx,ssx,dsx,esx;} regx;         /* structure for segread */ /*SRJ*/
  160.  
  161.  
  162. int    y,mo,d;            /* year,month and day for date */  /*SRJ*/
  163. int    h,mi,s;            /* hours, minutes, seconds for time */ /*SRJ*/
  164.  
  165. char    *months[]=        /* month names for date */        /*SRJ*/
  166.         {"bad month","January","February","March","April","May","June",
  167.         "July","August","September","October","November","December"};
  168.  
  169. int    ln_chr=0;        /* # of characters in the line (for tab) */ /*SRJ*/
  170.  
  171. unsigned int    handle;            /* dos file handle */        /*SRJ*/
  172. unsigned int file_d,file_mo,file_y,file_h,file_mi;      /* file m/d/y and h:m */ /*SRJ*/
  173.  
  174. FILE    *tb;            /* temp fd */                /*SRJ*/
  175.  
  176.  
  177. int    linum;        /* line number */
  178. int    edtnum;     /* edit line number */
  179. int    fil_cnt;    /* active file index */
  180. int    wrd_cnt;    /* token count */
  181. int    pagno;        /* page number */
  182. int    id_cnt;     /* number of unique identifiers */
  183. int    rhsh_cnt;    /* number of conflict hits */
  184. int    filevl;     /* file level  */
  185. int    paglin;     /* page line counter */
  186. int    prt_ref;
  187. char    act_fil[MAX_LEN];
  188. char    lst_fil[MAX_LEN];
  189. char    gbl_fil[MAX_LEN];
  190. FILE   *l_buffer;                         /*   WHR */
  191. int    i_flg,o_flg,r_flg,l_flg;
  192. int    debug;
  193. int    c_flg;                             /* WHR */
  194.  
  195.  
  196. /* The following two strings are the compressed print header and the
  197. trailer that returns the printer to the normal mode.  These must
  198. be changed for each printer.  They are currently set up for the 
  199. IDS Microprism.                                               ** SRJ **
  200. */
  201. #ifdef IDS
  202. char    cprint_hdr[] = "\033R2$\036";  /* header string for Microprism */ 
  203. char    cprint_trlr[] = "\033R1$\035";  /* trailer string for Microprism */ 
  204. #else
  205. /* Epson header string */
  206. #ifdef    MX
  207. char    cprint_hdr[] = "\x1B\x40\x0F\x1BQ\x84";                 /* WHR */
  208. #else
  209.   /* no printer , or later stack printer defined */
  210.     char    cprint_hdr[] = "\0" ;
  211.     char    cprint_trlr[] = "\0";     /*DAG*/
  212. #endif  /* if def MX or not */
  213. #endif    /* IDS not defined */
  214.  
  215. /* end of printer strings */
  216. /*  MAIN PROGRAM       */                    /*SRJ*/
  217.  
  218.  
  219. main(argc,argv)
  220.      int     argc;
  221.      char    **argv;
  222.  
  223.      {char  *arg;
  224.      char *strcpy();
  225. /*** int  toupper();   ***/             /* Microsoft C   macro */
  226.      char cc;                     /* Microsoft C */
  227.  
  228. /*  The the parameters  */
  229.  
  230.      if (argc < 2) use_err();
  231.      i_flg=r_flg=o_flg=l_flg=FALSE;
  232.      debug = FALSE;
  233.      strcpy(gbl_fil,*++argv);
  234.      --argc;
  235.      if(gbl_fil[0] == '-')
  236.       use_err();
  237.      while(--argc != 0)
  238.      {      if(*(arg=*++argv) == '-')
  239.     /*****{    switch( toupper(*++arg) )     *** side effect in Microsoft C */
  240.       {    switch( cc=*++arg, toupper(cc) )          /* Microsoft C */
  241.            {   case 'I':  i_flg++;
  242.                   break;
  243.            case 'R':  r_flg++;
  244.                   break;
  245.            case 'L':  l_flg++;
  246.                   break;
  247.            case 'O': {o_flg++;
  248.                   if(--argc == 0) use_err();
  249.                   strcpy(lst_fil,*++argv);
  250.                   if(lst_fil[0] == '-') use_err();
  251.                   if(debug) printf("lst_fil=>%s<",lst_fil);
  252.                   break;
  253.                  }
  254.            case 'D':  debug++;
  255.                   break;
  256.            case 'C':  c_flg++;                  /* SRJ */ /* WHR */
  257.                   o_flg++;
  258.                   strcpy(lst_fil,"PRN:");    /* SRJ */
  259.                   break;
  260.            default:   use_err();
  261.            }
  262.       }
  263.      else use_err();
  264.      }
  265.      if(debug) printf("\ni_flg=%d, r_flg=%d, l_flg=%d", i_flg,r_flg,l_flg);
  266.      if(debug) printf("\no_flg=%d, debug=%d", o_flg,debug);
  267.      if (o_flg)
  268.            {if ( (l_buffer = fopen(lst_fil,"w")) == NULL)   /*** output file ***/
  269.           {printf("ERROR: Unable to create list file - %s\n",lst_fil);
  270.            exit(0);
  271.           }
  272.       printf("\nXC ....... 'C' Print Utility  v1.0\n");        /*SRJ*/
  273.       if (c_flg) fprintf(l_buffer,"%s",cprint_hdr);
  274.           }
  275.       else                                /*SRJ*/
  276.       l_buffer=stdout;    /* if no output file, use stdout */    /*SRJ*/
  277.  
  278. /* THE FOLLOWING CODE GETS THE DATE AND THE TIME FROM DOS.  IT USES THE
  279. ROUTINES SYSINT AND SEGREAD PROVIDED BY THE CI C-86 LIBRARY.  THIS IS CI C-86
  280. DEPENDENT CODE AND MUST BE CHANGED FOR OTHER COMPILERS               */  /*SRJ*/
  281. #ifdef    DOS
  282. segread(®x);        /* get the segment registers */            /*SRJ*/
  283. reg.ds=regx.dsx;    /* save the ds in the sysint data */        /*SRJ*/
  284. reg.es=regx.esx;    /* save the es in the sysint data */        /*SRJ*/
  285.  
  286. /* get the date */                            /*SRJ*/
  287. reg.ax=0x2A00;            /* date request code */            /*SRJ*/
  288. sysint(0x21,®,®);        /* DOS interrupt */            /*SRJ*/
  289. y=reg.cx;            /* store year */            /*SRJ*/
  290. mo=reg.dx>>8;            /* store month */            /*SRJ*/
  291. d=reg.dx & 0xFF;        /* get the day */            /*SRJ*/
  292.  
  293. /* get the time */                            /*SRJ*/
  294. reg.ax=0x2C00;            /* time request code */            /*SRJ*/
  295. sysint(0x21,®,®);        /* DOS interrupt */            /*SRJ*/
  296. h=reg.cx>>8;            /* get hours */                /*SRJ*/
  297. mi=reg.cx & 0xFF;        /* get minutes */            /*SRJ*/
  298. s=reg.dx>>8;            /* get seconds */            /*SRJ*/
  299. #endif        /* def DOS */
  300.  
  301. /* NOW WE GET THE FILE LATEST UPDATE DATE AND TIME */  
  302.  
  303. /* first try to open the file */
  304.  
  305. if ((tb = fopen(gbl_fil,"r")) == NULL)  /*open the input file */    /*SRJ*/
  306.     {printf("\nERROR: Unable to open input file: %s\n",gbl_fil);    /*SRJ*/
  307.     exit(10);                            /*SRJ*/
  308.     }
  309. fclose(tb);            /* close the file */            /*SRJ*/
  310.  
  311. /* note-we have no way to get an error indication back from the dos call
  312. below (file open),  so we have to open it to see if it is there before
  313. we can use the proceedure below */                    /*SRJ*/    
  314.  
  315. /* now get the file date and time */                    /*SRJ*/
  316.  
  317. #ifdef    DOS
  318. /* open the file   -  we assume the file exists */            /*SRJ*/
  319. reg.ax=0x3D00;            /* open request code */            /*SRJ*/
  320. reg.dx=gbl_fil;            /* address of file name */        /*SRJ*/
  321. sysint(0x21,®,®);        /* DOS interrupt */            /*SRJ*/
  322. handle=reg.ax;            /* store file handle */            /*SRJ*/
  323.  
  324. /* get the date and time */                        /*SRJ*/
  325. reg.ax=0x5700;            /* time request code */            /*SRJ*/
  326. reg.bx=handle;            /* file handle in bx */            /*SRJ*/
  327. sysint(0x21,®,®);        /* DOS interrupt */            /*SRJ*/
  328.  
  329.  
  330. /* unpack the file time */                        /*SRJ*/
  331. file_h=(reg.cx >> 11) & 0x1F;        /* get hours */            /*SRJ*/
  332. file_mi=(reg.cx >> 5) & 0x3f;        /* get minutes */        /*SRJ*/
  333.  
  334. /* unpack the file date */                        /*SRJ*/
  335. file_d=reg.dx & 0x1F;            /* get the day */        /*SRJ*/
  336. file_mo= (reg.dx >> 5) & 0x0F;        /* get the month */        /*SRJ*/
  337.  
  338. file_y=( (reg.dx >> 9) & 0x7F )+80;    /* get the month */        /*SRJ*/
  339.  
  340. /* close the file */                            /*SRJ*/
  341.  
  342. reg.bx=handle;                                /*SRJ*/
  343. reg.ax=0x3D00;                                /*SRJ*/
  344. sysint(0x21,®,®);        /* DOS interrupt */            /*SRJ*/
  345.  
  346. #endif        /* def DOS */
  347.  
  348. /* END OF CI C-86 DEPENDENT CODE  */                    /*SRJ*/
  349.  
  350.  
  351.      prt_ref = FALSE;
  352.      for(linum=0;linum < MAX_WRD;linum++)
  353.       id_vector[linum] = NULL;
  354.      
  355.      for(linum=0;linum < MAX_ALPHA;linum++)
  356.       alpha_vector[linum].alpha_top =
  357.            alpha_vector[linum].alpha_lst = NULL;
  358.      
  359.      fil_cnt = wrd_cnt = linum = 0;
  360.      filevl=paglin=pagno=edtnum=0;
  361.      id_cnt=rhsh_cnt=0;
  362.      proc_file(gbl_fil);
  363.      if(!l_flg)
  364.      {prnt_tbl();
  365.      printf("\nAllowable Symbols: %d\n",MAX_WRD);
  366.      printf("Unique    Symbols: %d\n",id_cnt);
  367.          }
  368.      if(o_flg)
  369.       {nl();
  370.       fprintf(l_buffer,"\nAllowable Symbols: %d\n",MAX_WRD);   /* WHR */
  371.       fprintf(l_buffer,"Unique    Symbols: %d\n",id_cnt);      /* WHR */
  372.       fprintf(l_buffer,"\f%c",CPMEOF);                      /* WHR */
  373.       fprintf(l_buffer,"%s",cprint_trlr); /* output trailer */ /* SRJ */
  374.       fflush(l_buffer);
  375.       fclose(l_buffer);
  376.           }
  377. }
  378. /*   ERROR MESSAGE PRINT ROUTINES */                /*SRJ*/
  379.  
  380. lst_err()
  381.  
  382. {printf("\nERROR: Write error on list output file - %s\n",lst_fil);
  383. exit(0);
  384. }
  385.  
  386.  
  387. use_err()
  388.  
  389. {printf("\nERROR: Invalid parameter specification\n\n");
  390. printf("Usage: xc <filename> <flag(s)>\n\n");
  391. printf("Flags: -i             = Enable file inclusion\n");
  392. printf("       -l             = Generate listing only\n");
  393. printf("       -c             = Compressed print option\n");  /*SRJ*/
  394. printf("       -r             = Cross-reference reserved words\n");
  395. printf("       -o <filename>  = Write output to named file\n");
  396. exit(0);
  397. }
  398.  
  399. /*   PROCESS THE FILE  */                    /*SRJ*/
  400.  
  401. proc_file(filnam)
  402.  
  403. char    *filnam;
  404.  
  405. {FILE  *buffer;       /* allocated buffer pointer */        /* WHR */
  406. char  token[MAX_LEN]; /* token buffer */
  407. int   eof_flg;       /* end-of-file indicator */
  408. int   tok_len;       /* token length */
  409. int   incnum;       /* included line number */
  410. char *strcpy();
  411.  
  412. strcpy(act_fil,filnam);
  413. if ((buffer = fopen(filnam,"r")) == NULL)  /*** input file ***/ /* WHR */
  414.     {printf("\nERROR: Unable to open input file: %s\n",filnam);
  415.     exit(0);
  416.     }
  417. if(filevl++ == 0)
  418.     {prt_hdr();
  419.     nl();
  420.     }
  421. eof_flg = FALSE;
  422.  
  423. do
  424.     {if(get_token(buffer,token,&tok_len,&eof_flg,0))
  425.         {if (debug) printf("token: %s   length: %d\n",token,tok_len);
  426.         if (chk_token(token))
  427.            
  428.              /* #include processing changed to accept drive:   WHR */
  429.             {if (strcmp(token,"#include") == 0)
  430.                 {if (get_token(buffer,token,&tok_len,&eof_flg,1))
  431.                     {if (debug) printf("**token: %s   length: %d\n",
  432.                           token,tok_len);
  433.                     if (!i_flg)
  434.                         continue;
  435.                       else
  436.                         {incnum=edtnum;
  437.                         edtnum=0;
  438.                         nl();
  439.                         proc_file(token);
  440.                         edtnum=incnum;
  441.                         strcpy(act_fil,filnam);
  442.                         continue;
  443.                         }
  444.                     }
  445.                 }
  446.             put_token(token,linum);
  447.             }
  448.         }
  449.     }
  450. while (!eof_flg);
  451.  
  452. filevl -= 1;
  453. fclose(buffer);
  454. return;
  455. }
  456. /*   GET A TOKEN    */                        /*SRJ*/
  457.  
  458. get_token(g_buffer,g_token,g_toklen,g_eoflg,g_flg)
  459.  
  460. FILE    *g_buffer;
  461. char    *g_token;
  462. int     *g_toklen;
  463. int     *g_eoflg;
  464. int     g_flg;
  465.  
  466. /*
  467. *     'getoken' returns the next valid identifier or
  468. *     reserved word from a given file along with the
  469. *     character length of the token and an end-of-file
  470. *     indicator
  471. *
  472. */
  473.  
  474. {
  475.      int     c;
  476.      char    *h_token;
  477.      char    tmpchr;
  478.      char    tmpchr2;              /* WHR fix for B:filename.ext */
  479.  
  480.      h_token = g_token;
  481.  
  482.  gtk:                   /* top of loop, get new token */
  483.      *g_toklen = 0;
  484.      g_token = h_token;
  485.  
  486.     /*
  487.      *    Scan and discard any characters until an alphabetic or
  488.      *    '_' (underscore) character is encountered or an end-of-file
  489.      *    condition occurs
  490.      */
  491.  
  492.      while(  (!isalpha(*g_token = rdchr(g_buffer,g_eoflg,g_flg)))
  493.          &&  !*g_eoflg    &&  *g_token != '_'
  494.          && *g_token != '0' &&  *g_token != '#' );
  495.      if(*g_eoflg) return(FALSE);
  496.  
  497.      *g_toklen += 1;
  498.  
  499.     /*
  500.      *     Scan and collect identified alpanumeric token until
  501.      *     a non-alphanumeric character is encountered or and
  502.      *     end-of-file condition occurs
  503.      */
  504.  
  505.      if(g_flg) {
  506.       tmpchr  = '.';
  507.       tmpchr2 = ':';                   /* WHR fix for B:filename.ext */
  508.      }
  509.      else {
  510.       tmpchr  = '_';
  511.       tmpchr2 = '_';                   /* WHR fix for B:filename.ext */
  512.      }
  513.      while( (isalpha(c=rdchr(g_buffer,g_eoflg,g_flg)) ||
  514.         isdigit(c) || c == '_' || c == tmpchr || c == tmpchr2)
  515.         && !*g_eoflg)           /* WHR fix for B:filename.ext */
  516.      {      if(*g_toklen < MAX_LEN)
  517.       {    *++g_token = c;
  518.            *g_toklen += 1;
  519.       }
  520.      }
  521.  
  522.  
  523.     /*
  524.      *        Check to see if a numeric hex or octal constant has
  525.      *        been encountered ... if so dump it and try again
  526.      */
  527.  
  528.  
  529.      if (*h_token == '0') goto gtk;
  530.  
  531.  
  532.     /*
  533.      *        Tack a NULL character onto the end of the token
  534.      */
  535.  
  536.      *++g_token = NULL;
  537.  
  538.     /*
  539.      *        Screen out all #token strings except #include
  540.      */
  541.  
  542.      if (*h_token == '#' && strcmp(h_token,"#include")) goto gtk;
  543.  
  544.      return (TRUE);
  545. }
  546. /*  READ A CHARACTER FROM THE FILE AND PROCESS IT */        /*SRJ*/
  547.  
  548.  
  549. rdchr(r_buffer,r_eoflg,rd_flg)
  550.      int     *r_eoflg;
  551.      FILE    *r_buffer;
  552.      int     rd_flg;
  553.  
  554. /*
  555.     'rdchr' returns the next valid character in a file
  556.     and an end-of-file indicator. A valid character is
  557.     defined as any which does not appear in either a
  558.     commented or a quoted string ... 'rdchr' will correctly
  559.     handle comment tokens which appear within a quoted
  560.     string
  561. */
  562.  
  563. {
  564.      int     c;
  565.      int     q_flg;         /* double quoted string flag */
  566.      int     q1_flg;         /* single quoted string flag */
  567.      int     cs_flg;         /* comment start flag */
  568.      int     ce_flg;         /* comment end flag */
  569.      int     c_cnt;         /* comment nesting level */
  570.      int     t_flg;         /* transparency flag */
  571.  
  572.      q_flg = FALSE;
  573.      q1_flg = FALSE;
  574.      cs_flg = FALSE;
  575.      ce_flg = FALSE;
  576.      t_flg = FALSE;
  577.      c_cnt  = 0;
  578.  
  579. rch:
  580.  
  581.  
  582.     /*
  583.      *     Fetch character from file
  584.      */
  585.  
  586.      c = fil_chr(r_buffer,r_eoflg) & 0x7F;    /* read only 7 bit ascii */ /*SRJ*/
  587.  
  588.      if (*r_eoflg) return(c);    /* EOF encountered */
  589.  
  590.      switch(c)            /* test the returned character */   /*SRJ*/
  591.     {case '\n':        /* carriage return */            /*SRJ*/
  592.         nl();        /* output new line and line numbers */ /*SRJ*/
  593.         ln_chr=0;    /* set to first char in line */        /*SRJ*/
  594.         c=' ';        /* return a space */            /*SRJ*/
  595.         break;
  596.  
  597.     case '\f':        /* form feed */                     /*SRJ*/
  598.         prt_hdr();    /* output header and start new page*/ /*SRJ*/
  599.         fprintf(l_buffer,"     "); /* space over line #s */   /*SRJ*/
  600.         ln_chr=0;    /* set to first char in line */        /*SRJ*/
  601.         c=' ';        /* set char to blank */            /*SRJ*/
  602.         break;
  603.  
  604.     case '\t':        /* tab character */        /*SRJ*/
  605.         do        /* expand the tabs */        /*SRJ*/
  606.             fputc(' ',l_buffer);            /*SRJ*/
  607.         while( (++ln_chr % TABCNT) != 0);        /*SRJ*/
  608.         c=' ';        /* set char to blank */            /*SRJ*/
  609.         break;
  610.  
  611.  
  612.     default:
  613.         ln_chr++;        /* move to next char pos */  /*SRJ*/
  614.         if( iscntrl(c) )    /* insure no control chars */ /*SRJ*/
  615.             c=' ';
  616.             fputc(c,l_buffer);    /* and output next char */   /*SRJ*/
  617.     }
  618.  
  619.      if (rd_flg) return(c);
  620.  
  621.      if (t_flg) {
  622.       t_flg = !t_flg;
  623.       goto rch;
  624.      }
  625.  
  626.      if (c == '\\') {
  627.       t_flg = TRUE;
  628.       goto rch;
  629.      }
  630.     /*
  631.     If the character is not part of a quoted string
  632.     check for and process commented strings...
  633.     nested comments are handled correctly but unbalanced
  634.     comments are not ... the assumption is made that
  635.     the syntax of the program being xref'd is correct
  636.     */
  637.  
  638.      if (!q_flg  &&  !q1_flg) {
  639.       if (c == '*'  &&  c_cnt  &&  !cs_flg) {
  640.            ce_flg = TRUE;
  641.            goto rch;
  642.       }
  643.       if (c == '/'  &&  ce_flg) {
  644.            c_cnt -= 1;
  645.            ce_flg = FALSE;
  646.            goto rch;
  647.       }
  648.       ce_flg = FALSE;
  649.       if (c == '/') {
  650.            cs_flg = TRUE;
  651.            goto rch;
  652.       }
  653.       if (c == '*'  &&  cs_flg) {
  654.            c_cnt += 1;
  655.            cs_flg = FALSE;
  656.            goto rch;
  657.       }
  658.       cs_flg = FALSE;
  659.  
  660.       if (c_cnt) goto rch;
  661.      }
  662.  
  663.     /*
  664.     Check for and process quoted strings
  665.     */
  666.  
  667.      if ( c == '"'  &&  !q1_flg) {      /* toggle quote flag */
  668.       q_flg =  !q_flg;
  669.       if(debug) printf("q_flg toggled to: %d\n" ,q_flg);
  670.       goto rch;
  671.      }
  672.      if (q_flg) goto rch;
  673.  
  674.      if (c == '\'') {        /* toggle quote flag */
  675.       q1_flg = !q1_flg;
  676.       if(debug) printf("q1_flg toggled to: %d\n" ,q1_flg);
  677.       goto rch;
  678.      }
  679.      if (q1_flg) goto rch;
  680.  
  681.     /*
  682.     Valid character ... return to caller
  683.     */
  684.  
  685.      return (c);
  686. }/*rdchr.
  687. -----------------------------------------------*/
  688. fil_chr(f_buffer,f_eof)
  689.      FILE *f_buffer;
  690.      int *f_eof;
  691. {
  692.      int fc;
  693.      fc=getc(f_buffer);
  694.      if (fc == CPMEOF || fc == EOF) {
  695.       *f_eof = TRUE;
  696.       fc = NULL;
  697.      }
  698.      return(fc);
  699. }
  700. /*   CHECK THE TOKEN  */                /*SRJ*/
  701.  
  702.  
  703. chk_token(c_token)
  704.      char    *c_token;
  705. {
  706.      char  u_token[MAX_LEN];
  707.      int   i;
  708.  
  709.      {
  710.       if (r_flg) return(TRUE);
  711.       i = 0;
  712.       do { u_token[i] = toupper(c_token[i]);
  713.       } while (c_token[i++] != NULL);
  714.  
  715.       switch(u_token[0]) {
  716.     case 'A': if (strcmp(u_token,"AUTO") == 0) return(FALSE);
  717.           break;
  718.     case 'B': if (strcmp(u_token,"BREAK") == 0) return(FALSE);
  719.           break;
  720.     case 'C': if (strcmp(u_token,"CHAR") == 0) return (FALSE);
  721.           if (strcmp(u_token,"CONTINUE") == 0) return (FALSE);
  722.           if (strcmp(u_token,"CASE") == 0) return (FALSE);
  723.           break;
  724.  
  725.     case 'D': if(strcmp(u_token,"DOUBLE") == 0) return(FALSE);
  726.           if(strcmp(u_token,"DO") == 0) return(FALSE);
  727.           if(strcmp(u_token,"DEFAULT") == 0) return(FALSE);
  728.           break;
  729.     case 'E': if(strcmp(u_token,"EXTERN") == 0) return(FALSE);
  730.           if(strcmp(u_token,"ELSE") == 0) return(FALSE);
  731.           if(strcmp(u_token,"ENTRY") == 0) return(FALSE);
  732.           break;
  733.     case 'F': if(strcmp(u_token,"FLOAT") == 0) return(FALSE);
  734.           if(strcmp(u_token,"FOR") == 0) return(FALSE);
  735.           break;
  736.     case 'G': if(strcmp(u_token,"GOTO") == 0) return(FALSE);
  737.           break;
  738.     case 'I': if(strcmp(u_token,"INT") == 0) return(FALSE);
  739.           if(strcmp(u_token,"IF") == 0) return(FALSE);
  740.           break;
  741.     case 'L': if(strcmp(u_token,"LONG") == 0) return(FALSE);
  742.           break;
  743.     case 'R': if(strcmp(u_token,"RETURN") == 0) return(FALSE);
  744.           if(strcmp(u_token,"REGISTER") == 0) return(FALSE);
  745.           break;
  746.     case 'S': if(strcmp(u_token,"STRUCT") == 0) return(FALSE);
  747.           if(strcmp(u_token,"SHORT") == 0) return(FALSE);
  748.           if(strcmp(u_token,"STATIC") == 0) return(FALSE);
  749.           if(strcmp(u_token,"SIZEOF") == 0) return(FALSE);
  750.           if(strcmp(u_token,"SWITCH") == 0) return(FALSE);
  751.           break;
  752.     case 'T': if(strcmp(u_token,"TYPEDEF") == 0) return(FALSE);
  753.           break;
  754.     case 'U': if(strcmp(u_token,"UNION") == 0) return(FALSE);
  755.           if(strcmp(u_token,"UNSIGNED") == 0) return(FALSE);
  756.           break;
  757.     case 'W': if(strcmp(u_token,"WHILE") == 0) return(FALSE);
  758.           break; }
  759.     }
  760.   return (TRUE);
  761. }/*chk_token.
  762. ---------------------------------------------*/
  763. /*   STORE THE TOKEN  */                    /*SRJ*/
  764.  
  765.   /*
  766.    *    Install parsed token and line reference in linked structure
  767.    */
  768.  
  769. put_token(p_token,p_ref)
  770.      char *p_token;
  771.      int  p_ref;
  772. {
  773.      int  hsh_index;
  774.      int  i;
  775.      unsigned long  j;                            /*SRJ*/
  776.      int  d;
  777.      int  found;
  778.      struct id_blk *idptr;
  779.      struct rf_blk *rfptr;
  780.      struct id_blk *alloc_id();
  781.      struct rf_blk *alloc_rf();
  782.      struct rf_blk *add_rf();
  783.  
  784.      if (l_flg) return;
  785.      j=0;
  786.      for (i=0; p_token[i] != NULL; i++)  /* Hashing algorithm is far from */
  787.      j = j * 10 + p_token[i];     /* memory-bound index vector!      */
  788.  
  789.      hsh_index = j % MAX_WRD;                        /*SRJ*/
  790.      
  791.      if(debug) printf("hash index=%d ",hsh_index);
  792.  
  793.      found = FALSE;
  794.      d = 1;
  795.      do
  796.             {idptr = id_vector[hsh_index];
  797.       if (idptr == NULL)
  798.            {id_cnt++;
  799.            idptr = id_vector[hsh_index] = alloc_id(p_token);
  800.            chain_alpha(idptr,p_token);
  801.            idptr->top_lnk = idptr->lst_lnk = alloc_rf(p_ref);
  802.            found = TRUE;
  803.            if(debug) printf("empty cell in vector\n");
  804.            }
  805.         else
  806.            if (strcmp(p_token,idptr->id_name) == 0)
  807.                   {idptr->lst_lnk = add_rf(idptr->lst_lnk,p_ref);
  808.            if(debug) printf("duplicate token\n");
  809.                found = TRUE;
  810.              }
  811.             else
  812.                {hsh_index += d;
  813.            if(debug) printf("hash clash  hash index=%d\n",hsh_index);
  814.                d += 2;
  815.                rhsh_cnt++;
  816.                if (hsh_index >= MAX_WRD)
  817.                  hsh_index -= MAX_WRD;
  818.                if (d == MAX_WRD)
  819.                      {printf("\nERROR: Symbol table overflow\n");
  820.                  exit(0);
  821.                   }
  822.              }
  823.            }
  824.       while (!found);
  825.  
  826. return;
  827. }/*put_token.
  828. --------------------------------------------*/
  829. /*    BUILD THE CHAINS */                    /*SRJ*/
  830.  
  831. chain_alpha(ca_ptr,ca_token)
  832.      struct id_blk *ca_ptr;
  833.      char  *ca_token;
  834. {
  835.      char  c;
  836.      int   f;
  837.      struct id_blk *cur_ptr;
  838.      struct id_blk *lst_ptr;
  839. /*** int isupper();   ****/           /** Microsoft C     macro **/
  840.  
  841.  
  842.      c = ca_token[0];
  843.      if (c == '_')  c = 0;
  844.      else
  845.      /**  isupper(c) ? c=1+((c-'A')*2) : c=2+((c-'a')*2) ;     error or not??
  846.       **  A good one for the puzzle book! Is the () required around (c=..)?
  847.       **  C86 and Microsoft C both req the ()'s, BDS C did not.
  848.       **  Is it required because = has lower precedence than ?: ????
  849.       **/
  850.       isupper(c) ? (c=1+((c-'A')*2)) : (c=2+((c-'a')*2)) ;
  851.  
  852.      if(alpha_vector[c].alpha_top == NULL)
  853.      {      alpha_vector[c].alpha_top =
  854.           alpha_vector[c].alpha_lst = ca_ptr;
  855.       ca_ptr->alpha_lnk = NULL;
  856.       return;
  857.      }
  858.  
  859.     /*    check to see if new id_blk should be inserted between
  860.      *    the alpha_vector header block and the first id_blk in
  861.      *    the current alpha chain
  862.      */
  863.  
  864.      if(strcmp(alpha_vector[c].alpha_top->id_name,ca_token) >0)
  865.      {      ca_ptr->alpha_lnk=alpha_vector[c].alpha_top;
  866.       alpha_vector[c].alpha_top=ca_ptr;
  867.       return;
  868.      }
  869.  
  870.      if(strcmp(alpha_vector[c].alpha_lst->id_name,ca_token) < 0)
  871.      {      alpha_vector[c].alpha_lst->alpha_lnk = ca_ptr;
  872.       ca_ptr->alpha_lnk = NULL;
  873.       alpha_vector[c].alpha_lst=ca_ptr;
  874.       return;
  875.      }
  876.  
  877.      cur_ptr = alpha_vector[c].alpha_top;
  878.      while(strcmp(cur_ptr->id_name,ca_token) < 0)
  879.      {      lst_ptr = cur_ptr;
  880.       cur_ptr = lst_ptr->alpha_lnk;
  881.      }
  882.  
  883.      lst_ptr->alpha_lnk = ca_ptr;
  884.      ca_ptr->alpha_lnk = cur_ptr;
  885.      return;
  886. }/*chain_alpha.
  887. -----------------------------------------*/
  888. /*   GET MEMORY FOR TOKEN TREE */                /*SRJ*/
  889.      struct id_blk
  890. *alloc_id(aid_token)
  891.      char  *aid_token;
  892. {
  893.      int  ai;
  894.      struct id_blk *aid_ptr;
  895.      char *malloc();                         /* Microsoft C */
  896.  
  897. /*** if((aid_ptr =  alloc(sizeof(oneid))) == 0) { ***/         /* Microsoft C */
  898.      if((aid_ptr = (struct id_blk *) malloc(sizeof(oneid))) == 0) { /* MS C */
  899.  
  900.       printf("\nERROR: Unable to allocate identifier block\n");
  901.       exit(0);
  902.      }
  903.      ai=0;
  904.      do {
  905.       aid_ptr->id_name[ai] = aid_token[ai];
  906.      } while (aid_token[ai++] != NULL);
  907.      return (aid_ptr);
  908. }/*id_blk.
  909. -----------------------------------------*/
  910.  
  911.      struct rf_blk
  912. *alloc_rf(arf_ref)
  913.      int  arf_ref;
  914. {
  915.     int ri;
  916.     struct rf_blk *arf_ptr;
  917.     char * malloc();                       /* Microsoft C */
  918.  
  919. /** if((arf_ptr = alloc(sizeof(onerf))) == 0) { **/    /* Microsoft C */
  920.     if((arf_ptr = (struct rf_blk *) malloc(sizeof(onerf))) == 0) { /* MS C */
  921.      printf("\nERROR: Unable to allocate reference block\n");
  922.      exit(0);
  923.     }
  924.     arf_ptr->ref_item[0] = arf_ref;
  925.     arf_ptr->ref_cnt = 1;
  926.     for (ri=1;ri<MAX_REF;ri++)
  927.       arf_ptr->ref_item[ri] = NULL;
  928.     return (arf_ptr);
  929. }/*alloc_rf.
  930. ------------------------------------------*/
  931. /*   STORE REFERENCE IN TREE */                    /*SRJ*/
  932.  
  933.      struct rf_blk
  934. *add_rf(adr_ptr,adr_ref)
  935.  
  936.      struct rf_blk *adr_ptr;
  937.      int adr_ref;
  938. {
  939.      struct rf_blk *tmp_ptr;
  940.  
  941.      tmp_ptr = adr_ptr;
  942.      if(adr_ptr->ref_cnt == MAX_REF) {
  943.      /*** tmp_ptr = adr_ptr->ref_cnt = alloc_rf(adr_ref);    Microsoft C **/
  944.       adr_ptr->ref_cnt = alloc_rf(adr_ref);       /* Microsoft C **/
  945.       tmp_ptr = (struct rf_blk *) adr_ptr->ref_cnt;   /* Microsoft C **/
  946.      }
  947.      else
  948.      {      adr_ptr->ref_item[adr_ptr->ref_cnt++] = adr_ref;
  949.      }
  950.      return (tmp_ptr);
  951. }/*rf_blk.
  952. ------------------------------------------*/
  953. /*   PRINT THE CROSS REFERENCE TABLE */                /*SRJ*/
  954.  
  955. prnt_tbl()
  956. {
  957.      int prf_cnt;
  958.      int pti;
  959.      int pref;
  960.      int lin_cnt;
  961.      struct id_blk *pid_ptr;
  962.      struct rf_blk *ptb_ptr;
  963.  
  964.      prt_ref = TRUE;
  965.      prt_hdr();
  966.      nl();
  967.      for (pti=0;pti<MAX_ALPHA;pti++)
  968.           {if ((pid_ptr = alpha_vector[pti].alpha_top) != NULL)
  969.            {do
  970.                  {fprintf(l_buffer,"%-14.13s: ",pid_ptr->id_name);/*WHR*/
  971.             ptb_ptr=pid_ptr->top_lnk;
  972.             lin_cnt=prf_cnt=0;
  973.             do
  974.                  {if(prf_cnt == MAX_REF)
  975.                   {prf_cnt=0;
  976.              /*** ptb_ptr = ptb_ptr->ref_cnt;  Microsoft C **/
  977.                   ptb_ptr = (struct rf_blk *)ptb_ptr->ref_cnt;
  978.                   }
  979.              if(ptb_ptr > MAX_REF)
  980.                  {if((pref=ptb_ptr->ref_item[prf_cnt++]) != 0)
  981.                           {fprintf(l_buffer,"%-4d  ",pref); /*WHR*/
  982.                          if (++lin_cnt == REFS_PER_LINE)
  983.                            {nl();
  984.                         fprintf(l_buffer,"%16s",": ");
  985.                         lin_cnt=0;
  986.                             }
  987.                               }
  988.                   }
  989.                   else
  990.                        pref=0;
  991.                  }
  992.             while (pref);
  993.             nl();
  994.                 }
  995.            while ((pid_ptr=pid_ptr->alpha_lnk) != NULL);
  996.            }
  997.           }
  998. }/*prnt_tbl.
  999. ---------------------------------------*/
  1000. /*   TOP OF PAGE AND PRINT THE HEADER */            /*SRJ*/
  1001.  
  1002. prt_hdr()
  1003.  
  1004. {
  1005. #ifdef    DOS
  1006. ffdr() ; /* do a formfeed if necessary */ 
  1007. fprintf(l_buffer,
  1008.   "\r%-10s [file d/t= %d/%02d/%02d  %d:%02d]   [clock d/t= %d %s %d  %d:%02d:%02d]   Page %d\n\n",
  1009.         gbl_fil,file_mo,file_d,file_y,file_h,file_mi,
  1010.     d,months[mo],y,h,mi,s,++pagno);        /*SRJ*/
  1011. #else     /* it's cpm or has no clocked files */
  1012. ffder(); /* print a form feed if necessary */
  1013. fprintf(l_buffer,
  1014.   "\r%-10s                            Page %d\n\n",gbl_fil,++pagno);        /*DAG*/
  1015. #endif    /* defed DOS or not */
  1016.  
  1017. paglin =3;
  1018. return;
  1019. }
  1020.  
  1021. /* FORMFEED to save a page */
  1022. ffder() /* print a form feed if necessary */
  1023. {
  1024.     if (pagno)     /* isn't the first page */
  1025.     fprintf(l_buffer,"\r\f\n");    
  1026. }
  1027. /*  NEW LINE */                            /*SRJ*/
  1028.  
  1029. nl()
  1030.  
  1031. {
  1032. #ifdef    DOS
  1033. fputc('\n',l_buffer);    /* output cr/lf */            /*SRJ*/
  1034. #else
  1035. aputc('\n',l_buffer);    /* output cr/lf */            /*SRJ*/
  1036. #endif    /* def DOS or not */
  1037.  
  1038. if (++paglin >= LINES_PER_PAGE)
  1039.     prt_hdr();
  1040. if(!prt_ref)
  1041.     {fprintf(l_buffer,"%4d ",++linum);          /*SRJ*/
  1042.     if(i_flg)                      /*SRJ*/
  1043.         fprintf(l_buffer," %4d: ",++edtnum);    /*SRJ*//*WHR*/
  1044.     }
  1045. /* print the status on the console */
  1046. if(o_flg)
  1047.     if(linum % 60 == 1)
  1048.         printf("\n<%d>\t",linum);
  1049.       else
  1050.         printf(".");
  1051. return;
  1052. }/*nl.
  1053. -------------------------------------------*/
  1054. /*============= end of file xc.c ==========================*/
  1055. return;
  1056. }/*nl.
  1057. -------------------------------------------*/
  1058. /*============= end of file xc