home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_300
/
329_02
/
xcxref.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-06-11
|
51KB
|
1,761 lines
/***********************************************************
XCXREF - A 'C' Concordance Utility
Version 1.0 xc - January, 1982
Version 1.0 xcxref - May, 1990
Copyright (c) 1982 by Philip N. Hisley
Philip N. Hisley
548H Jamestown Court
Edgewood, Maryland 21040
(301) 679-4606
Released for non-commercial distribution only
Converted to IBM/PC CI/C86 by David N. Smith, May/June 1983
with enhancements and Lattice compiler support in December 1983.
David N. Smith
44 Ole Musket Lane
Danbury, CT 06810
(203) 748-5934
CompuServe: 73145,153
Changes Copyright (c) 1983 by David N. Smith
Permission granted to copy for non-commercial purposes.
Version v1.0 XCXREF - May, 1990.
Program functions extended, hence the name change.
Martin D. Winnick
5301 El Arbol Drive
Carlsbad, CA 92008
(619) 431-0485
CompuServe: 71665,456
May 1990
Changes Copyright (c) 1990 by Martin D. Winnick
Permission granted to copy for non-commercial use only.
See the accompanying xcxref.doc file for program history and
all change details.
Abstract:
'XCXREF' is a cross-reference utility for 'C' programs.
Its will handle nested #include files and properly process
nested comments.
Option flags control the following features:
Usage: xcxref <filename> <flag(s)>
Flags: -e = Write program data to log file
-g = Ignore missing files
-i = Enable #include processing
-l = Generate listing only - no xref
-o <outfile> = Write output to named file
-p = Write output to line printer LPT1
-r = Cross-reference 'C' reserved words
-s = Write output to video screen
-w width = Width of output page; default = 78
max = 150
Flags MUST FOLLOW all input file names
***********************************************************/
#include "bios.h"
#include "ctype.h"
#include "direct.h"
#include "dos.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "time.h"
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define ERROR -1
#define FF 0x0C /* formfeed */
#define FOREVER for(;;)
#define LINES_PER_PAGE 60
#define LPT1 0 /* defines LPT1 */
#define MAX_ALPHA 53 /* maximum alpha chain heads */
#define MAX_LEN 31 /* maximum identifier length */
#define MAX_REF 5 /* maximum refs per ref-block */
#define MAX_REFS_LINE 10 /* maximum refs per line */
#define MAX_WRD 5000 /* maximum number of identifiers (749) */
#define MAXCOL 78 /* right margin for listing line */
#define MAXLINE 150 /* maximum print line length. */
#define MINCOL 30 /* minimum value for -w option */
struct alpha_hdr
{
struct id_blk *alpha_top;
struct id_blk *alpha_lst;
};
struct id_blk
{
char id_name[MAX_LEN];
struct id_blk *alpha_lnk;
struct rf_blk *top_lnk;
struct rf_blk *lst_lnk;
};
struct rf_blk
{
int ref_item[MAX_REF];
int ref_cnt;
struct rf_blk *next_rfb;
};
struct alpha_hdr alpha_vector[MAX_ALPHA];
struct dosdate_t dt;
struct id_blk *id_vector[MAX_WRD];
int al_count = 0; /* number of alpha links */
int edtnum = 0; /* edit line number */
int file_level = 0; /* file level */
int hash_hits = 0; /* number of conflict hits */
int id_cnt = 0; /* number of unique identifiers */
int id_count = 0; /* number of id structs alloc. */
int linum = 0; /* line number */
int paglin = 0; /* page line counter */
int pagno = 0; /* page number */
int rf_count = 0; /* number of rf structs alloc. */
short base_row = 0; /* basic data display video row */
short maxcol = MAXCOL; /* right column for listing */
short maxrefs = MAX_REFS_LINE; /* max references per line */
short vline = 10; /* work data display video column */
short do_echo = TRUE;
short do_includes = FALSE;
short do_lprint = FALSE;
short do_numbrs = TRUE;
short do_outfile = FALSE;
short do_res_wds = FALSE;
short do_screen = FALSE;
short file_queue = FALSE;
short ignore = FALSE;
short infl_open = FALSE;
short lf_open = FALSE;
short list_only = FALSE;
short log_on = FALSE;
short prt_ref = FALSE;
short qfl_open = FALSE;
short qfirst = TRUE;
char current_file[_MAX_PATH] = { '\0' };
char glbl_file[_MAX_PATH] = { '\0' };
char list_file[_MAX_PATH] = { '\0' };
char log_file[] = { "XCXREF.LOG" };
char work_name[_MAX_PATH] = { '\0' };
/* Working file name components */
char wdrive[_MAX_DRIVE] = { '\0' };
char wdir[_MAX_DIR] = { '\0' };
char wfname[_MAX_FNAME] = { '\0' };
char wext[_MAX_EXT] = { '\0' };
/* Current default directory components */
char ddrive[_MAX_DRIVE] = { '\0' };
char ddir[_MAX_DIR] = { '\0' };
/* Alternate path name components */
char adrive1[_MAX_DRIVE] = { '\0' };
char adir1[_MAX_DIR] = { '\0' };
char adrive2[_MAX_DRIVE] = { '\0' };
char adir2[_MAX_DIR] = { '\0' };
char adrive3[_MAX_DRIVE] = { '\0' };
char adir3[_MAX_DIR] = { '\0' };
char adrive4[_MAX_DRIVE] = { '\0' };
char adir4[_MAX_DIR] = { '\0' };
char xfname[_MAX_FNAME] = { '\0' };
char xext[_MAX_EXT] = { '\0' };
char b22[] = { " " };
char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
char emsgs[71] = { '\0' };
char pdate[] = { "Thu 05/10/90" };
char prt_line[256] = { '\0' };
char version[] = { "v1.0" };
char xcx_name[] = { "XCXREF ... " };
char xname[] = { "XCXREF.LST" };
FILE *f_list_file; /* list file */
FILE *lgfile; /* program data log file */
FILE *ofile; /* general open file */
/* function prototypes */
struct rf_blk *add_rf(struct rf_blk *adr_ptr, int adr_ref);
struct id_blk *alloc_id(char *aid_token);
struct rf_blk *alloc_rf(int arf_ref);
void chain_alpha(struct id_blk *ca_ptr, char *ca_token);
int check_for_resword(char *c_token);
void clr_scrn(short crow, short nrows);
void do_prints(int pparm);
void do_print_xrefs(void);
void echo(char c);
void echochar(char c);
int get_file_char(FILE *cfile, int *f_eof);
int get_fqueue(char *qfn);
void get_include_fileid(char *token, FILE *ifile, short parm);
int get_token(FILE *gfile, char *g_token, int *g_toklen, int *g_eoflg, char x_chr);
void list_err(int parm);
void logit(short parm);
void lprintr(char *buffer);
void new_line(void);
int openlist(char *lname);
FILE *open_rfile(void);
void pause(clock_t mcount);
void pexit(int xparm);
void print_header(void);
int proc_file(int incnum);
void put_token(char *p_token, int p_ref);
char read_file_char(FILE *rfile, int *r_eoflg, char rd_flg);
void set_csr(short vrow, short vcol);
void use_err(void);
/*************************************************************************/
int main(int p_argc, char **p_argv)
{
char *arg, **argv;
int argc, i, ret;
argc = p_argc;
argv = p_argv;
if (argc < 2)
{
printf("\nThere are no option arguments.\n");
use_err();
}
while (--argc != 0)
{
if (*(arg = *++argv) == '-')
{
switch(*++arg)
{
/* log program data to a disk log file. */
case 'e':
case 'E': if ((lgfile = fopen(log_file, "w")) != NULL)
{
log_on = TRUE;
break;
}
else
{
sprintf(emsgs, "\nCannot open XCXREF log file...%s\n", log_file);
pexit(0);
}
/* Ignore missing files. */
case 'g':
case 'G': ignore = TRUE;
break;
/* enable processing of #include */
case 'i':
case 'I': do_includes = TRUE;
break;
/* xref reserved words also. */
case 'r':
case 'R': do_res_wds = TRUE;
break;
/* Program listing only - no xref. */
case 'l':
case 'L': list_only = TRUE;
break;
/* write the xref to the disk file named. */
case 'o':
case 'O': do_outfile = TRUE;
if ((--argc == 0) || (*++argv[0] == '-'))
{
printf("\nInvalid -o option argument.\n");
use_err();
}
if ((openlist(*++argv)) == 0)
{
printf("\n%s %s\n", xcx_name, version);
vline += 2;
}
else
{ pexit(1); }
break;
/* write xref to the line printer. */
case 'p':
case 'P': do_lprint = TRUE;
break;
/* write xref to the video screen. */
case 's':
case 'S': do_screen = TRUE;
break;
/* set page width. */
case 'w':
case 'W': if (--argc == 0)
{
("\nInvalid -w option argument.\n");
use_err();
}
i = atoi(*++argv);
if (i <= MINCOL || i >= MAXLINE)
{
printf("\nInvalid -w option argument.\n");
use_err();
}
maxcol = i;
break;
default: printf("\nUnrecognizable option argument.\n");
use_err();
}
}
}
if (!do_outfile && !do_lprint && !do_screen)
{
printf("\nAt least one output destination must be selected.\n");
use_err();
}
/* Get current system date from dos. */
_dos_getdate(&dt);
sprintf(pdate, "%s %u/%02u/%02u", days[dt.dayofweek],
dt.month, dt.day, dt.year - 1900);
/* Get currently logged directory. */
getcwd(current_file, _MAX_DIR);
strcat(current_file, "\\");
_splitpath(current_file, ddrive, ddir, xfname, xext);
/* display program header */
clr_scrn(0, 25);
set_csr(vline++, 0);
printf("%s %s\n", xcx_name, pdate);
vline++;
prt_ref = FALSE;
for (linum = 0; linum < MAX_WRD; linum++)
{ id_vector[linum] = NULL; }
for (linum = 0; linum < MAX_ALPHA; linum++)
{ alpha_vector[linum].alpha_top = alpha_vector[linum].alpha_lst = NULL; }
linum = 0;
argc = p_argc;
argc--;
argv = p_argv;
while (argc--)
{
if (!file_queue)
{
/* Get program names from the command line. */
strcpy(glbl_file, *++argv);
/* Separate file name into components. */
_splitpath(glbl_file, wdrive, wdir, wfname, wext);
}
else
{
/* Get the program names from the list file. */
/* maintain arg count to preserve while loop */
argc++;
if ((ret = get_fqueue(glbl_file)) == -1)
{ pexit(2); }
/* If this is false then at eof of list file, */
/* go back to command line. */
if (!file_queue)
{
argc--;
continue;
}
}
/* If the first character of a file name is an @ */
/* it is a reference to a list of file names in a */
/* list file. Get the program names, and paths */
/* from that file. */
/* NOTE: The first character of any file name in */
/* a list file CANNOT be an @. */
/* This @filename may be mixed with program names */
/* on the command line. When it is encountered */
/* XCXREF will get all program names from the */
/* file. It will return to the command line on */
/* its eof; however, any alternate paths set will */
/* be retained but may be overridden. */
if (glbl_file[0] == '@')
{
/* maintain arg count to preserve while loop */
argc++;
file_queue = TRUE;
/* delete the leading '@' */
strcpy(glbl_file, &glbl_file[1]);
strcpy(wfname, &wfname[1]);
continue;
}
/* No more program names; this is an option; */
/* we are all done. */
if (glbl_file[0] == '-')
{ break; }
/* This is where all the work will be done. */
if ((ret = proc_file(0)) == -1)
{
/* If this flag is TRUE then ignore a not-found */
/* source file and just go to the next one. */
if (!ignore)
{ pexit(3); }
}
} /* end while(argc...) */
/* Process the cross reference. */
if (!list_only)
{
glbl_file[0] = '\0';
do_print_xrefs();
printf("\nAllowable Symbols: %d\n", MAX_WRD);
printf("Unique Symbols: %d\n", id_cnt);
}
if (do_outfile)
{
new_line();
fprintf(f_list_file, "\nAllowable Symbols: %d\n", MAX_WRD);
fprintf(f_list_file, "Unique Symbols: %d\n", id_cnt);
fclose(f_list_file);
lf_open = FALSE;
}
if (log_on)
{
logit(999);
fclose(lgfile);
}
} /* exit xcxref program. */
/*************************************************************************/
FILE *open_rfile()
/* The file_name is in the q????? component variables and */
/* must be put together into the work_name variable. */
/* IF */
/* wdir is already set then only that pathname will be */
/* tried. If not found then will exit without trying any */
/* alternate pathnames. */
/* ELSE ... */
/* The drive and path in ddir, etc., will be tried. */
/* If the file is not found there alternate path 1-4 will */
/* be tried next. If not in any of those a not-found will */
/* be returned to the caller. Further disposition will be */
/* up to the caller. */
{
short i = 0; /* retry control */
int ret = TRUE; /* set return as 'found' */
FOREVER
{
/* if wdir is already set then do not */
/* do any of the alternate directory searches. */
if (wdir[0] != '\0')
{ i = 99; }
switch (i++)
{
/* Default directory */
case 0: strcpy(wdrive, ddrive);
strcpy(wdir, ddir);
break;
/* Alternate 1 directory */
case 1: if (adrive1[0] != '\0')
{
strcpy(wdrive, adrive1);
strcpy(wdir, adir1);
break;
}
else
{ continue; }
/* Alternate 2 directory */
case 2: if (adrive2[0] != '\0')
{
strcpy(wdrive, adrive2);
strcpy(wdir, adir2);
break;
}
else
{ continue; }
/* Alternate 3 directory */
case 3: if (adrive3[0] != '\0')
{
strcpy(wdrive, adrive3);
strcpy(wdir, adir3);
break;
}
else
{ continue; }
/* Alternate 4 directory */
case 4: if (adrive4[0] != '\0')
{
strcpy(wdrive, adrive4);
strcpy(wdir, adir4);
break;
}
else
{ continue; }
/* Path already set */
case 99: break;
/* not found in any path */
/* ignore error return. */
default: ret = FALSE;
break;
} /* end switch (++path...) */
/* File not found exit. */
if (!ret)
{ break; }
/* Put all file name components together. */
_makepath(work_name, wdrive, wdir, wfname, wext);
/* Try to open file. If not able then try next path. */
if ((ofile = fopen(work_name, "r")) != NULL)
{ break; }
/* Clear so switch will work. */
wdir[0] = '\0';
} /* end FOREVER... */
/* Save only .c file names for page header. */
if (strncmp(wext, ".h", 2) != 0)
{ strcpy(current_file, work_name); }
return(ofile);
}
/*************************************************************************/
int proc_file(int incnum)
/* The file_name is in the q????? component variables and */
/* must be put together into the work_name variable. */
/* - incnum; prev. included line number (returned to caller) */
{
FILE *infile; /* input file */
char token[MAX_LEN]; /* token buffer */
int eof_flg; /* end-of-file indicator */
int tok_len; /* token length */
int i, ret, iret;
/* Reset edit line counter. */
edtnum = 0;
if ((infile = open_rfile()) == NULL)
{
sprintf(emsgs, "\nUnable to open input file: %s\n", work_name);
printf(emsgs);
vline += 2;
logit(101);
return(-1); /* caller may ignore error */
}
infl_open = TRUE;
if (file_level++ == 0)
{ print_header(); }
eof_flg = FALSE;
do
{
if (get_token(infile, token, &tok_len, &eof_flg, 0x254))
{
if (check_for_resword(token))
{
if (strcmp(token, "#include") == 0)
{
do_echo = FALSE;
get_include_fileid(token, infile, FALSE);
do_echo = TRUE;
if (!do_includes)
{ continue; }
else
{
/* Process #include file. */
new_line();
/* Separate #include name into components. */
_splitpath(token, wdrive, wdir, wfname, wext);
/* if file not found then ignore the #include file. */
if ((iret = proc_file(edtnum)) == -1)
{ ; }
} /* end else ... */
} /* end if (strcmp...) */
put_token (token, linum);
} /* end if (check_for...) */
} /* end if (get_token...) */
} while (!eof_flg);
file_level -= 1;
fclose(infile);
infl_open = FALSE;
return(incnum);
}
/*************************************************************************/
/* Get the program names from the external list file. */
int get_fqueue(char *qfn)
{
char token[MAX_LEN]; /* token buffer */
char q_p; /* work q_path number */
int qeof_flg; /* end-of-file indicator */
int tok_len; /* token length */
FILE *qfile; /* program name input file */
/* On the first entry open the external list file. */
/* Then on this and subsequent calls return a name */
/* from the file or set file_queue to FALSE to */
/* indicate end of list and continue from command */
/* line. */
if (qfirst)
{
if ((qfile = fopen(qfn, "r")) == NULL)
{
sprintf(emsgs, "\nCannot open external program list file: %s\n", qfn);
vline += 2;
printf(emsgs);
logit(102);
return(-1);
}
qfl_open = TRUE;
qeof_flg = qfirst = FALSE;
} /* end if (qfirst.. ) */
/* Now get names from the list file. */
/* #qpath are optional paths, if any. Save in path 1-4. */
/* Save only the drive and dir/path, throw away any fn.ext, */
/* each is expected as '#qpathn <dr:\path\path\>'; the 'n' */
/* may be 1 - 4. */
/* There must be a space before the '<' and the actual path */
/* must be enclosed in the "<>" brackets. */
/* These may be anywhere in the file. They will become */
/* effective when encountered. */
/* To clear an alternate path enter as #qpathn <> */
do
{
do_echo = FALSE;
if (get_token(qfile, token, &tok_len, &qeof_flg, '.'))
{
if (strncmp(token, "#qpath", 6) == 0)
{
/* Save the path number. */
q_p = token[6];
/* Now go get the path. */
get_include_fileid(token, qfile, TRUE);
switch(q_p)
{
/* qpath1 */
case 49: _splitpath(token, adrive1, adir1, xfname, xext);
break;
/* qpath2 */
case 50: _splitpath(token, adrive2, adir2, xfname, xext);
break;
/* qpath3 */
case 51: _splitpath(token, adrive3, adir3, xfname, xext);
break;
/* qpath4 */
case 52: _splitpath(token, adrive4, adir4, xfname, xext);
break;
default: break; /* max of 4 alternate paths */
} /* end switch (path... ) */
continue;
} /* end if(strncmp...) */
/* if the token is not a qpath and not eof then assume */
/* it is a filename in the form of nnnnnnnn.ext */
/* If it has a full path it will override any now set. */
/* - decompose into separate variables and exit. */
_splitpath(token, wdrive, wdir, wfname, wext);
break;
} /* end if(get_token...) */
} while (!qeof_flg);
if (qeof_flg)
{
fclose(qfile);
qfl_open = file_queue = FALSE;
}
do_echo = TRUE;
return(0);
}
/*************************************************************************/
void get_include_fileid(char *token, FILE *ifile, short parm)
{
char c, term;
while ((term = getc(ifile)) == ' ')
{ echo(term); }
echo(term);
if (term == '<' )
{ term = '>'; }
/* Terminator is > or " */
if ((term != '>') && (term != '"'))
{
sprintf(emsgs, "\nError scanning #INCLUDE fileid: %c\n", term);
pexit(4);
}
do
{
if ((c = getc(ifile)) != ' ')
{
*token++ = c;
echo(c);
}
else
{ echo(c); }
} while (c != term);
*--token = '\0';
/* necessary only for list file paths. */
if (parm)
{
if (token[strlen(token)-1] != '\\')
{ strcat(token, "\\"); }
}
}
/*************************************************************************/
/*
'getoken' returns the next valid identifier or
reserved word from a given file along with the
character length of the token and an end-of-file
indicator.
*/
int get_token(FILE *gfile, char *g_token, int *g_toklen, int *g_eoflg, char x_chr)
{
int c,
ret = TRUE;
char *h_token;
char tmpchr;
h_token = g_token;
FOREVER
{
*g_toklen = 0;
g_token = h_token;
/*
Scan and discard characters until an alphabetic or
'_' (underscore) character is encountered or an end-of-file
condition occurs
*/
while ((!isalpha(*g_token = read_file_char(gfile, g_eoflg, x_chr))) &&
!*g_eoflg &&
*g_token != '_' &&
*g_token != '0' &&
*g_token != '#');
if (*g_eoflg)
{
ret = FALSE;
break;
}
*g_toklen += 1;
/*
Scan and collect identified alphanumeric token until
a non-alphanumeric character is encountered or an
end-of-file condition occurs
*/
tmpchr = x_chr;
while ((isalpha(c = read_file_char (gfile, g_eoflg, x_chr)) ||
isdigit(c) ||
c == '_' ||
c == tmpchr) &&
!*g_eoflg)
{
if (*g_toklen < MAX_LEN)
{
*++g_token = c;
*g_toklen += 1;
}
} /* end while ((isalpha... ) */
/*
Check to see if a numeric hex or octal constant has
been encountered ... if so dump it and try again
*/
if (*h_token == '0')
{ continue; }
/* NULL terminate the token */
*++g_token = NULL;
/* Screen out all #token strings except #include */
/* and special #qpathn from qpath list. */
if (*h_token == '#')
{
if ((strcmp(h_token, "#include") == 0) ||
(strncmp(h_token, "#qpath", 6) == 0))
{ break; }
else
{ continue; }
}
break;
}
return (TRUE);
}
/*************************************************************************/
int get_file_char(FILE *cfile, int *f_eof)
{
int fc;
if ((fc = fgetc(cfile)) == EOF)
{
*f_eof = TRUE;
fc = NULL;
}
else
{ *f_eof = FALSE; }
return(fc);
}
/*************************************************************************/
char read_file_char(FILE *rfile, int *r_eoflg, char rd_flg)
/*
'read_file_char' returns the next valid character in a file
and an end-of-file indicator. A valid character is defined
as any which does not appear in either a commented or a
quoted string ... 'read_file_char' will correctly handle
comment tokens which appear within a quoted string.
*/
{
int c;
int double_quotes; /* double quoted string flag */
int single_quotes; /* single quoted string flag */
int comment_start; /* comment start flag */
int comment_end; /* comment end flag */
int nesting_level; /* comment nesting level */
int transparent; /* transparency flag */
double_quotes = single_quotes = comment_start = FALSE;
comment_end = transparent = FALSE;
nesting_level = 0;
FOREVER
{
/* Fetch character from file */
c = get_file_char(rfile, r_eoflg);
if (*r_eoflg)
{ break; } /* EOF encountered */
if (c == '\n')
{ new_line(); }
else
{ echo(c); }
if (rd_flg == 0x254)
{ break; }
if (transparent)
{
transparent = !transparent;
continue;
}
if (c == '\\')
{
transparent = TRUE;
continue;
}
/*
If the character is not part of a quoted string
check for and process commented strings...
nested comments are handled correctly but unbalanced
comments are not ... it is assumed that the syntax of
the program being xref'd is correct.
*/
if (!double_quotes && !single_quotes)
{
/* test for end of a comment block. */
if (c == '*' && nesting_level && !comment_start)
{
comment_end = TRUE;
continue;
}
/* end of a comment */
if (c == '/' && comment_end)
{
nesting_level -= 1;
comment_end = FALSE;
continue;
}
comment_end = FALSE;
if (c == '/')
{
comment_start = TRUE;
continue;
}
if (c == '*' && comment_start)
{
nesting_level += 1;
comment_start = FALSE;
continue;
}
/* if nesting_level > 0 then we are in a comment block; */
/* throw away characters until nesting_level is zero. */
comment_start = FALSE;
if (nesting_level)
{ continue; }
}
/* Check for and process quoted strings */
if ( c == '"' && !single_quotes)
{
/* toggle quote flag */
double_quotes = !double_quotes;
continue;
}
if (double_quotes)
{ continue; }
if (c == '\'')
{
/* toggle quote flag */
single_quotes = !single_quotes;
continue;
}
if (single_quotes)
{ continue; }
/* Valid character ... exit function. */
break;
} /* end FOREVER */
return (c);
}
/*************************************************************************/
int check_for_resword(char *c_token)
{
char u_token[MAX_LEN];
int ret,
i = 0;
if (do_res_wds)
{ return(TRUE); }
do
{
u_token[i] = toupper(c_token[i]);
} while (c_token[i++] != NULL);
ret = TRUE;
switch(u_token[0])
{
case 'A': if (strcmp(u_token,"AUTO") == 0)
{ ret = FALSE; }
break;
case 'B': if (strcmp(u_token,"BREAK") == 0)
{ ret = FALSE; }
break;
case 'C': if ((strcmp(u_token,"CASE") == 0) ||
(strcmp(u_token,"CHAR") == 0) ||
(strcmp(u_token,"CONST") == 0) ||
(strcmp(u_token,"CONTINUE") == 0))
{ ret = FALSE; }
break;
case 'D': if ((strcmp(u_token,"DEFAULT") == 0) ||
(strcmp(u_token,"DO") == 0) ||
(strcmp(u_token,"DOUBLE") == 0))
{ ret = FALSE; }
break;
case 'E': if ((strcmp(u_token,"ELSE") == 0) ||
(strcmp(u_token,"ENTRY") == 0) ||
(strcmp(u_token,"ENUM") == 0) ||
(strcmp(u_token,"EXTERN") == 0))
{ ret = FALSE; }
break;
case 'F': if ((strcmp(u_token,"FLOAT") == 0) ||
(strcmp(u_token,"FOR") == 0))
{ ret = FALSE; }
break;
case 'G': if (strcmp(u_token,"GOTO") == 0)
{ ret = FALSE; }
break;
case 'I': if ((strcmp(u_token,"IF") == 0) ||
(strcmp(u_token,"INT") == 0))
{ ret = FALSE; }
break;
case 'L': if (strcmp(u_token,"LONG") == 0)
{ ret = FALSE; }
break;
case 'R': if ((strcmp(u_token,"REGISTER")== 0) ||
(strcmp(u_token,"RETURN") == 0))
{ ret = FALSE; }
break;
case 'S': if ((strcmp(u_token,"SHORT") == 0) ||
(strcmp(u_token,"SIGNED") == 0) ||
(strcmp(u_token,"SIZEOF") == 0) ||
(strcmp(u_token,"STATIC") == 0) ||
(strcmp(u_token,"STRUCT") == 0) ||
(strcmp(u_token,"SWITCH") == 0))
{ ret = FALSE; }
break;
case 'T': if (strcmp(u_token,"TYPEDEF") == 0)
{ ret = FALSE; }
break;
case 'U': if ((strcmp(u_token,"UNION") == 0) ||
(strcmp(u_token,"UNSIGNED")== 0))
{ ret = FALSE; }
break;
case 'V': if ((strcmp(u_token,"VOID") == 0) ||
(strcmp(u_token,"VOLATILE")== 0))
{ ret = FALSE; }
break;
case 'W': if (strcmp(u_token,"WHILE") == 0)
{ ret = FALSE; }
break;
}
return(ret);
}
/*************************************************************************/
/* Install parsed token and line reference in linked structure */
void put_token(char *p_token, int p_ref)
{
int hash_index, i,
found = FALSE,
j = 0,
d = 1;
struct id_blk *idptr;
struct rf_blk *rfptr;
if (list_only)
{ return; }
/* Hashing algorithm is far from */
/* optimal but is adequate for a */
/* memory-bound index vector! */
for (i = 0; p_token[i] != NULL; i++)
{ j = j * 10 + p_token[i]; }
hash_index = abs(j) % MAX_WRD;
do
{
if ((idptr = id_vector[hash_index]) == NULL)
{
id_cnt++;
idptr = id_vector[hash_index] = alloc_id(p_token);
chain_alpha(idptr, p_token);
idptr->top_lnk = idptr->lst_lnk = alloc_rf(p_ref);
found = TRUE;
}
else
if(strncmp(p_token, idptr->id_name, MAX_LEN) == 0)
{
idptr->lst_lnk = add_rf(idptr->lst_lnk, p_ref);
found = TRUE;
}
else
{
hash_index += d;
d += 2;
hash_hits++;
if (hash_index >= MAX_WRD)
hash_index -= MAX_WRD;
if (d >= MAX_WRD)
{
sprintf(emsgs, "\nSymbol table overflow\n");
pexit(5);
}
}
} while (!found);
}
/*************************************************************************/
void chain_alpha(struct id_blk *ca_ptr, char *ca_token)
{
char c;
struct id_blk *cur_ptr;
struct id_blk *lst_ptr;
if ((c = ca_token[0]) == '_')
{ c = 0; }
else
if (isupper(c))
{ c = 1 + ((c-'A')*2); }
else
{ c = 2 + ((c-'a')*2); }
FOREVER
{
if (alpha_vector[c].alpha_top == NULL)
{
alpha_vector[c].alpha_top = alpha_vector[c].alpha_lst = ca_ptr;
ca_ptr->alpha_lnk = NULL;
break;
}
/*
check to see if new id_blk should be inserted between
the alpha_vector header block and the first id_blk in
the current alpha chain
*/
if (strncmp(alpha_vector[c].alpha_top->id_name, ca_token, MAX_LEN) > 0)
{
ca_ptr->alpha_lnk = alpha_vector[c].alpha_top;
alpha_vector[c].alpha_top = ca_ptr;
break;
}
if (strncmp(alpha_vector[c].alpha_lst->id_name, ca_token, MAX_LEN) < 0)
{
alpha_vector[c].alpha_lst->alpha_lnk = ca_ptr;
ca_ptr->alpha_lnk = NULL;
alpha_vector[c].alpha_lst = ca_ptr;
break;
}
cur_ptr = alpha_vector[c].alpha_top;
while (strncmp(cur_ptr->id_name, ca_token, MAX_LEN) < 0)
{
lst_ptr = cur_ptr;
cur_ptr = lst_ptr->alpha_lnk;
}
lst_ptr->alpha_lnk = ca_ptr;
ca_ptr->alpha_lnk = cur_ptr;
break;
}
al_count++;
}
/*************************************************************************/
struct id_blk *alloc_id(char *aid_token)
{
int i = 0;
struct id_blk *aid_ptr;
if ((aid_ptr = malloc(sizeof(struct id_blk))) == NULL)
{
sprintf(emsgs, "\nUnable to allocate identifier block\n");
pexit(6);
}
do
{
aid_ptr->id_name[i] = aid_token[i];
} while ((aid_token[i++] != NULL) && (i < MAX_LEN));
id_count++;
return(aid_ptr);
}
/*************************************************************************/
struct rf_blk *alloc_rf(int arf_ref)
{
short i;
struct rf_blk *arf_ptr;
if ((arf_ptr = malloc(sizeof(struct rf_blk))) == NULL)
{
sprintf(emsgs, "\nUnable to allocate reference block\n");
pexit(7);
}
arf_ptr->ref_item[0] = arf_ref;
arf_ptr->ref_cnt = 1;
arf_ptr->next_rfb = NULL;
for (i = 1; i < MAX_REF; i++)
{ arf_ptr->ref_item[i] = NULL; }
rf_count++;
return(arf_ptr);
}
/*************************************************************************/
struct rf_blk *add_rf(struct rf_blk *adr_ptr, int adr_ref)
{
struct rf_blk *tmp_ptr;
tmp_ptr = adr_ptr;
if (adr_ptr->ref_cnt == MAX_REF)
{ tmp_ptr = adr_ptr->next_rfb = alloc_rf(adr_ref); }
else
{ adr_ptr->ref_item[adr_ptr->ref_cnt++] = adr_ref; }
return (tmp_ptr);
}
/*************************************************************************/
/*
build cross reference print lines.
when a line is full then write to:
the screen,
a file,
the line printer;
depending on program options selected.
*/
void do_print_xrefs()
{
int prf_cnt, ptb_cnt, i, line_cnt;
int pref = TRUE;
char wk_line[21] = { '\0' };
char work[21] = { '\0' };
struct id_blk *pid_ptr;
struct rf_blk *ptb_ptr;
printf ("\nWriting Cross Reference Table... Please Wait...\n");
do_numbrs = FALSE;
print_header();
for (i = 0; i < MAX_ALPHA; i++)
{
if ((pid_ptr = alpha_vector[i].alpha_top) != NULL)
{
do
{
/* Place reference variable in print line */
prt_line[0] = '\0';
sprintf(prt_line, "%-20.19s: ", pid_ptr->id_name);
ptb_ptr = pid_ptr->top_lnk;
line_cnt = prf_cnt = 0;
do
{
if (prf_cnt == MAX_REF)
{
prf_cnt = 0;
ptb_cnt = ptb_ptr->ref_cnt;
ptb_ptr = ptb_ptr->next_rfb;
}
/* if (ptb_cnt > MAX_REF) */
if (ptb_ptr != NULL)
{
if ((pref = ptb_ptr->ref_item[prf_cnt++]) != 0)
{
sprintf(wk_line, "%4d ", pref);
strcat(prt_line, wk_line);
/* if the number of references or the next reference */
/* line number may exceed the print line capacity */
/* then print the line and start another. */
if ((strlen(prt_line) + (strlen(itoa(linum, work, 10))) > maxcol) ||
(++line_cnt == maxrefs))
{
/* print file line, screen line, etc. */
do_prints(FALSE);
new_line();
sprintf(prt_line, b22);
line_cnt = 0;
}
} /* end if ((pref... ) */
} /* end if (ptb->ptr...) */
else
{
pref = 0;
/* print file line, screen line, etc. */
do_prints(FALSE);
}
} while (pref);
do_prints(FALSE);
new_line();
} while ((pid_ptr = pid_ptr->alpha_lnk) != NULL);
}
} /* end for(i... */
echo('\n');
echo(FF);
}
/*************************************************************************/
void do_prints(int pparm)
{
if (prt_line[0] != '\0')
{
/* print file line, screen line, etc. */
if (do_outfile)
{
if ((fprintf(f_list_file, prt_line)) == ERROR)
{ list_err(3); }
}
if (do_screen)
{ printf(prt_line); }
else
{
if (pparm)
{
if (linum % 60 == 1) /* sixty dots per line. */
{
if (vline >= 24) /* if at bottom line of screen; */
{
clr_scrn(base_row+1, 24); /* clear screen and position at line 2. */
vline++;
}
set_csr(vline++, 0);
printf("\n<%d> ", linum);
}
printf(".");
fflush(stdout);
}
}
if (do_lprint)
{ lprintr(prt_line); }
/* Clear the print line. */
prt_line[0] = '\0';
}
}
/*************************************************************************/
void print_header()
{
if (pagno++ != 0)
{
echo('\n');
echo(FF);
}
/* _makepath(current_file, wdrive, wdir, wfname, wext); */
sprintf(prt_line, "%s %s %s %s Page %d", xcx_name, glbl_file, current_file, pdate, pagno);
/* print file line, screen line, etc. */
if (do_screen)
{
clr_scrn(base_row, 25);
set_csr(vline++, 0);
}
do_prints(FALSE);
echo('\n');
paglin = 3;
new_line(); /* number first line on next page. */
}
/*************************************************************************/
void new_line()
{
echo('\n');
if (++paglin >= LINES_PER_PAGE)
{ print_header(); }
else
{
/* no line numbers when doing xref table. */
if (do_numbrs)
{
if (!prt_ref)
{
sprintf(prt_line, "%-4d %4d: ", ++linum, ++edtnum);
if (do_screen)
{
if (vline >= 24)
{
clr_scrn(base_row+1, 24);
vline++;
}
set_csr(vline++, 0);
}
do_prints(TRUE);
} /* end if (!prt_ref...) */
} /* end if (nparm...) */
} /* end else ... */
}
/*************************************************************************/
void echo(char c)
{
static int col = 11;
short i;
if(do_echo)
{
echochar(c);
if (c == '\n' )
{ col = 11; }
else if (++col > maxcol )
{
col = 11;
paglin++;
echochar('\n');
for (i = 1; i <= 11; i++)
{ echochar(' '); }
}
} /* end if(do_echo ... */
}
void echochar(char c)
{
if (do_outfile)
{
if ((fprintf(f_list_file, "%c", c)) == ERROR)
{ list_err(1); }
}
if (do_screen)
{ printf("%c", c); }
if (do_lprint)
{
prt_line[0] = c;
prt_line[1] = '\0';
lprintr(prt_line);
}
}
/*************************************************************************/
/* Print using direct call to the system BIOS, */
void lprintr(char *buffer)
{
char *p;
int key;
union REGS inregs, outregs;
/*
Check for printer available and ready.
Fail if any error bit is on or if a selected operation bit is off.
*/
FOREVER
{
inregs.h.ah = 0x2; /* get printer status. */
inregs.x.dx = LPT1;
int86( 0x17, &inregs, &outregs );
if ((outregs.h.ah & 0x29) || /* 1 = out-of-paper, i/o-error, time-out */
!(outregs.h.ah & 0x80) || /* 1 = not-busy */
!(outregs.h.ah & 0x10) ) /* 1 = selected */
{
/* Compensate for slow printer response... */
/* Wait one second and then try printer again. */
pause((clock_t) 1000);
inregs.h.ah = 0x2;
inregs.x.dx = LPT1;
int86( 0x17, &inregs, &outregs );
if ((outregs.h.ah & 0x29) ||
!(outregs.h.ah & 0x80) ||
!(outregs.h.ah & 0x10))
{
fflush(stdin); /* Clear keyboard buffer. */
printf("\nPrinter not ready...\n");
printf("\nPress 'Q' to quit - XREF will not be printed\n");
/* Cannot redirect if a list file already assigned. */
if (list_file[0] == '\0')
{ printf(" 'D' to redirect to 'XCXREF.LST' disk file\n"); }
printf(" 'R' to retry the printer.\n");
key = getche();
switch(toupper(key))
{
/* Redirect printer output to XCXREF.LST file */
/* and close printer. */
case 'D': if (list_file[0] == '\0')
{
if ((openlist(xname)) == 0)
{
do_lprint = FALSE;
return;
}
else
{ logit(103); }
}
break;
/* Quit - close printer. */
case 'Q': do_lprint = FALSE;
return;
/* Retry printer. */
case 'R': break;
/* Retry printer. */
default: break;
} /* end switch ... */
} /* end if ((outregs... ) */
}
/* Printer is ready. */
break;
} /* end FOREVER... */
/* Output a string to the printer using DOS function 0x5. */
for (p = buffer; *p != 0; p++)
{ bdos(0x05, *p, 0); }
/* Clear print line buffer. */
buffer[0] = '\0';
}
/*************************************************************************/
/* Position the cursor using direct call to the system BIOS, */
/* vrow 0, vcol 0 == upper left. */
void set_csr(short vrow, short vcol)
{
union REGS inregs, outregs;
inregs.h.dh = vrow; /* set row register. */
inregs.h.dl = vcol; /* set col register. */
inregs.x.bx = 0; /* page number */
inregs.h.ah = 2; /* bios position cursor */
int86(0x10, &inregs, &outregs);
}
/*************************************************************************/
/* Clear the screen using direct call to the system BIOS, */
/* Be CAREFUL, no validation of row/col is done. */
/* Use crow = 0 and */
/* nrows = 25 to clear the entire screen. */
void clr_scrn(short crow, short nrows)
{
union REGS inregs, outregs;
inregs.h.ch = crow; /* upper left corner row */
inregs.h.cl = 0; /* col */
inregs.h.dh = crow + nrows; /* lower right corner row */
inregs.h.dl = 79; /* col */
if (crow == 0 && nrows == 25)
{ inregs.h.al = 0; } /* indicates entire screen */
else
{ inregs.h.al = nrows; }
inregs.h.ah = 6; /* scroll page up */
inregs.x.bx = 0; /* page number */
int86(0x10, &inregs, &outregs);
vline = base_row;
}
/*************************************************************************/
/* Pause for a specified number of microseconds. */
void pause(clock_t mcount)
{
clock_t mtime;
mtime = mcount + clock();
while (mtime > clock());
}
/*************************************************************************/
int openlist(char *lname)
{
if ((f_list_file = fopen(lname, "w")) == NULL)
{
sprintf(emsgs, "\nUnable to create XCXREF list file - %s\n", lname);
printf(emsgs);
vline += 2;
return(-1);
}
lf_open = TRUE;
strcpy(list_file, lname);
return(0);
}
/*************************************************************************/
void list_err(int parm)
{
sprintf(emsgs, "\nWrite error <%d> on XCXREF list output file - %s\n", parm, list_file);
pexit(8);
}
/*************************************************************************/
void use_err()
{
printf("%s %s\n\n", xcx_name, version);
printf("\nXCXREF: Invalid parameter specification\n\n");
printf("Usage: xcxref <filename>... <flag(s)>\n\n");
printf("Flags: -e = Write program data to log file\n");
printf(" -g = Ignore missing files\n");
printf(" -i = Enable #include processing\n");
printf(" -l = Generate listing only - no xref\n");
printf(" -o <outfile> = Write output to named file\n");
printf(" -p = Write output to line printer LPT1\n");
printf(" -r = Cross-reference reserved words\n");
printf(" -s = Write output to video screen\n");
printf(" -w width = Width of output page; default = 78\n");
printf(" maximum = 150\n");
printf("Flags MUST FOLLOW all input file names");
pexit(99);
}
/*************************************************************************/
/* Display program data only if flag is on. */
void logit(short parm)
{
if (log_on)
{
fprintf(lgfile, emsgs);
emsgs[0] = '\0';
fprintf(lgfile, "XCXREF program data...ID# %d\n", parm);
fprintf(lgfile, "sizesof id_blk = %d; rf_blk = %d; alpha_hdr = %d\n",
(sizeof(struct id_blk)), (sizeof(struct rf_blk)), (sizeof(struct alpha_hdr)));
fprintf(lgfile, "id_blk count - %d; rf_blk count %d\n", id_count, rf_count);
fprintf(lgfile, "Line nbr - %d; Edit line nbr - %d\n", linum, edtnum);
fprintf(lgfile, "Page nbr - %d; Unique id cnt - %d; Alpha cnt - %d\n", pagno, id_cnt, al_count);
fprintf(lgfile, "Nbr of conflict hits - %d; File level - %d\n", hash_hits, file_level);
fprintf(lgfile, "Page line counter - %d; Right col margin - %d\n", paglin, maxcol);
fprintf(lgfile, "Active file - %s\n", current_file);
fprintf(lgfile, "List file - %s\n", list_file);
fprintf(lgfile, "Gbl file - %s\n", glbl_file);
fprintf(lgfile, "wdrive:dir:fname.ext %s%s%s%s\n", wdrive, wdir, wfname, wext);
fprintf(lgfile, "adrive1:dir1 %s%s\n", adrive1, adir1);
fprintf(lgfile, "adrive2:dir2 %s%s\n", adrive2, adir2);
fprintf(lgfile, "adrive3:dir3 %s%s\n", adrive3, adir3);
fprintf(lgfile, "adrive4:dir4 %s%s\n", adrive4, adir4);
fprintf(lgfile,"qfl_open %d; lf_open %d; infl_open %d; do_res_wds %d; ignore %d\n",
qfl_open, lf_open, infl_open, do_res_wds, ignore);
fprintf(lgfile,"do_outfile %d; do_screen %d; list_only %d; do_includes %d; log_on %d\n",
do_outfile, do_screen, list_only, do_includes, log_on);
fprintf(lgfile,"do_lprint %d; do_numbrs %d; qfirst %d; file_queue %d\n",
do_lprint, do_numbrs, qfirst, file_queue);
}
}
/*************************************************************************/
/* Error exit from program */
void pexit(int xparm)
{
printf(emsgs);
/* Write console message and log data. */
if (xparm < 100)
{ logit(xparm); }
/* if log on print any partial xref table. */
if (log_on)
{
do_print_xrefs();
logit(100);
fclose(lgfile);
}
/*
if (infl_open)
{ fclose(infile); }
*/
if (lf_open)
{ fclose(f_list_file); }
exit(xparm);
}