home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 September
/
Simtel20_Sept92.cdr
/
msdos
/
c
/
c_flow.arc
/
CFLOW.C
next >
Wrap
Text File
|
1985-06-24
|
27KB
|
1,205 lines
/*
** CFLOW.C : find module call structure of c program
** refer to cflow.doc for how to use
**
** Mark Ellington
** 05-27-84
**
** Converted to MS-DOS 2 and C86, adding the following features:
**
** 1. filename wildcard support
** 2. -l flag to include line numbers in output
** 3. -f flag to include file names in output
** 4. #include support (with -h flag, same as C86 V2.20H)
** 5. -x flag to generate input for CFLOWX
** 6. #define macro() support
** 7. -t flag to change to '\t' for indentation
** 8. -s flag to allow specification of number of indentation spaces
** (default is 4 spaces)
**
** Larry Steeger
** 06-12-85
*/
#include <stdio.h> /* C86 header */
#define VOID int
/* external functions */
extern VOID abort();
extern char *alloc();
extern VOID exit();
extern int fclose();
extern unsigned char *filewdir();
extern FILE *fopen();
extern VOID fprintf();
extern int fputs();
extern VOID free();
extern int isalnum();
extern int isdigit();
extern int isspace();
extern char *lower();
extern char *makefile();
extern char *makefnam();
extern char *makepath();
extern char *realloc();
extern VOID setmem();
extern VOID sprintf();
extern char *strcat();
extern unsigned char *strchr();
extern char *strcpy();
extern unsigned strlen();
extern int strncmp();
extern char *strncpy();
extern int tolower();
#include "cflowx.h" /* CFLOW/CFLOWX header */
#define VERSION 85
#define RELEASE 06
#define MODIFIC 20
#define outinfo(S) fputs(S,stdout)
/* display CFLOW logo */
outlogo()
{
outinfo("\nCFLOW --> function declarations and calls in C source");
outinfo("\nby Mark Ellington");
fprintf(stdout,
"\n[V%02d.%02d.%02d for C86 by Lawrence R. Steeger]\n",
VERSION, RELEASE, MODIFIC
);
}
/* CFLOW usage help */
outhelp()
{
outinfo("\n usage: cflow ");
outinfo("[-[lft]|[x]] [-hsystem[,project]] ");
outinfo("[input1[..inputn]] [>output]\n");
outinfo("\n flags: -hsystem[,project]");
outinfo("\n #include drive/pathname specification");
outinfo("\n (usage: C86 V2.20H)");
outinfo("\n -l include line numbers in output");
outinfo("\n -f include file names in output");
outinfo("\n -sn number of indentation spaces");
outinfo("\n -t tabs rather than spaces for indentation");
outinfo("\n -x generate input for CFLOWX\n");
outinfo("\ndefaults: cflow -s4 [input] >stdout");
}
typedef struct _cflow { /* recursive execution structure */
struct _cflow *_chain; /* previous CFLOW structure */
int _fnmbr, /* current file name index */
_level, /* level of open "{"s or #includes */
_prevchar, /* previous character in input buffer */
_curchar, /* current character in input buffer
** array subscript
*/
_curline, /* current line in input dataset */
_define, /* #define flag */
_defdcl; /* name declaration offset */
unsigned char _delimit, /* #include file name delimiter */
*_defname,/* defined name buffer */
*_name, /* module name buffer */
*_ins, /* source input line buffer */
*_fname, /* source file name buffer */
*_fpname; /* source file/pathname buffer */
FILE *_fptr; /* input file pointer */
} CFLOW;
/* useability macros for CFLOW structure elements */
#define chain cflowp->_chain
#define fnmbr cflowp->_fnmbr
#define level cflowp->_level
#define prevchar cflowp->_prevchar
#define curchar cflowp->_curchar
#define curline cflowp->_curline
#define define cflowp->_define
#define defdcl cflowp->_defdcl
#define delimit cflowp->_delimit
#define defname cflowp->_defname
#define name cflowp->_name
#define ins cflowp->_ins
#define fname cflowp->_fname
#define fpname cflowp->_fpname
#define fptr cflowp->_fptr
/* runtime flags */
static int hflag = FALSE, /* -h #include drive/pathname */
lflag = FALSE, /* -l show line numbers */
fflag = FALSE, /* -f show file names */
sflag = FALSE, /* -s space indentation count */
tflag = FALSE, /* -t tab indentation flag */
xflag = FALSE; /* -x generate CFLOWX input */
static int fnumber = 0, /* C source file counter */
flevel = 0, /* C source file level */
mnumber = 0; /* C source file main counter */
static unsigned char *filepath = NULL, /* default file/path name */
*hsystem = NULL, /* -hsystem specification */
*hproject = NULL, /* -h,project specification */
*tab = " "; /* -t indentation */
static unsigned char newLine[] = {"\n"};
static CFLOW *cflowp = NULL; /* current CFLOW execution ptr */
/* mainline */
main(argc,argv)
int argc;
unsigned char * argv[];
{
unsigned char *fp,
*pp; /* temporary file/path pointer */
int fcount, /* C source file counter */
i,
j;
if (argc < 2) { /* display CFLOW help */
outlogo();
outhelp();
exit(1);
}
cflowp = alloc(sizeof(CFLOW)); /* 1st execution structure */
name = alloc(MAXBUF); /* module name buffer */
ins = alloc(MAXBUF); /* input line buffer */
fname = alloc(MAXPATH); /* current file name */
fpname = alloc(MAXPATH); /* current file/path name */
filepath = alloc(1); /* dummy file/path name */
*filepath = EOS;
for (i=1; i < argc; i++) { /* process all flags */
if (*argv[i] == '-') {
flags(argv[i]);
for (j = i--, --argc; j < argc; j++)
argv[j] = argv[j+1];
}
}
if (!xflag) outlogo(); /* display CFLOW logo */
if (hsystem != NULL) /* display -h system prefix */
if (*hsystem)
output(HDRSYST, hsystem);
if (hproject != NULL) /* display -h project prefix */
if (*hproject)
output(HDRPROJ, hproject);
for (i=1; i < argc; i++) { /* process all files */
if (*argv[i]) {
fnmbr = mnumber++;
strcpy(fname, argv[i]); /* get file name */
lower(fname);
free(filepath); /* get file/path name */
filepath = makepath(fname);
if ((strchr(fname, '*') != NULL) /* wildcards */
|| (strchr(fname, '?') != NULL)) {
/* process all matching file names */
fcount = 0;
while ((fp = filewdir(argv[i],0x00)) != NULL) {
if (!fcount) {
pp = makepath(fname);
output(WILDPTH, pp);
free(pp);
pp = makefile(fname);
output(WILDNME, pp);
free(pp);
}
++fcount;
lower(fp);
strcpy(fname,fp);
makefnam(fp, filepath, fpname);
flevel = level = 0;
modules();
free(fp);
}
if (!fcount) output(WILDNF, fname);
}
else { /* no wildcards */
strcpy(fpname, fname);
strcpy(fname, (pp=makefile(fname)));
free(pp);
flevel = level = 0;
modules();
}
}
}
exit(0);
}
/* process command line flags */
int flags(flag)
unsigned char *flag;
{
unsigned char *hp;
int i;
for (i=1; i < strlen(flag); i++)
switch (tolower(flag[i])) {
case 'h': /* -h header specifications */
hflag = TRUE;
i++;
if (hsystem != NULL)
free(hsystem);
if ((hp = strchr(&flag[i], ',')) != NULL)
*hp++ = EOS;
hsystem = alloc((strlen(&flag[i]) + 1));
strcpy(hsystem, lower(&flag[i]));
if (hp) {
if (hproject != NULL)
free(hproject);
hproject = alloc((strlen(hp) + 1));
strcpy(hproject, lower(hp));
}
i=strlen(flag); /* force break in for loop */
break;
case 'l': /* -l include line numbers */
lflag = TRUE;
break;
case 'f': /* -f include file names */
fflag = TRUE;
break;
case 's': /* -s spaces for indentation */
if (tflag) {
fprintf(stdout,
"\n-s is mutually exclusive with -t");
outhelp();
exit(1);
}
if (!isdigit(flag[i+1])) { /* -s only ! */
/* note: -s implies default */
sflag = strlen(tab);
break;
}
sflag = 0;
while (isdigit(flag[++i]))
sflag = (sflag * 10) + ((int)flag[i] - '0');
--i;
if (sflag) {
tab = alloc(sflag + 1);
setmem(tab, sflag, ' ');
break;
}
/* note: -s0 implies -t */
case 't': /* -t tabs for indentation */
if (sflag) {
fprintf(stdout,
"\n-t is mutually exclusive with -s");
outhelp();
exit(1);
}
tflag = TRUE;
tab = "\t";
break;
case 'x': /* -x generate CFLOWX file */
xflag = TRUE;
break;
default:
fprintf(stdout, "\nUnknown flag: \"%c\"", flag[i]);
outhelp();
exit(1);
}
flag[0] = EOS; /* clear flag */
}
/* find function declarations and calls */
modules()
{
int breakc, /* comment/quotes break character */
decl, /* module declaration line flag */
header, /* in function header (before 1st '{') */
j, /* loop index */
lastlin, /* last line of file flag */
modname(); /* module name extractor */
unsigned char c, /* current input character */
*pp; /* temporary path name pointer */
fnmbr = fnumber++; /* set & increment C source file number */
/* the following switch() provides -h flag support
** as documented for the C86 V2.20H -h flag.
*/
switch (delimit) { /* #include/command line file opens */
case '"': /* #include "filename" */
if (*filepath) {
fpname =
alloc((strlen(filepath) + strlen(fname) + 1));
strcpy(fpname, filepath);
strcat(fpname, fname);
}
else {
fpname = alloc((strlen(fname) + 1));
strcpy(fpname, fname);
}
if ((fptr = fopen(fpname, "r+")) != NULL) break;
free(fpname);
case '>': /* #include <filename> */
if (hproject != NULL) {
if (*hproject) {
fpname =
alloc((strlen(hproject) + strlen(fname) + 1));
strcpy(fpname, hproject);
strcat(fpname, fname);
if ((fptr=fopen(fpname,"r+")) != NULL) break;
free(fpname);
}
}
if (hsystem != NULL) {
if (*hsystem) {
fpname =
alloc((strlen(hsystem) + strlen(fname) + 1));
strcpy(fpname, hsystem);
strcat(fpname, fname);
if ((fptr=fopen(fpname,"r+")) != NULL) break;
free(fpname);
}
}
if (hflag || delimit != '"') {
output(FILEERR, fname);
return;
}
/* #include "filename" without -h */
fpname = alloc((strlen(fname) + 1));
strcpy(fpname, fname);
default: /* command line filename */
if ((fptr = fopen(fpname, "r+")) == NULL) {
output(FILEERR, fpname);
return;
}
break;
}
/* initialize flags/tokens */
breakc = prevchar = lastlin = header = FALSE;
curline = 0; /* 1st character in buffer */
/* identify C source/#include file name */
pp = makepath(fpname); /* get path name */
output(FILEPTH, pp); /* show C source path name */
output(FILENME, fname); /* show C source file name */
free(pp); /* free path name */
do {
if (lastlin = fgets()) /* read a line of source */
++curline;
define = decl = FALSE; /* assume nothing */
curchar = 0; /* start of line */
defname = NULL; /* clear defined name pointer */
if (prevchar != '\\') /* reset previous if not \ */
prevchar = FALSE;
while (ins[curchar]) { /* process all characters */
if (breakc) { /* comment/quote in progress */
if (skipold(&breakc))
break;
}
switch (ins[curchar]) {
case '\"': /* start quoted string */
case '\'': /* start quoted constant */
case '/' : /* start comment ? */
skipnew(&breakc);
break;
case '#': /* pre-processor tokens */
if (includes()) /* #include */
break;
if (defines()) /* #define */
break;
goto notsupp; /* unsupported */
case '{': /* compound statement start */
level++;
header = FALSE;
break;
case '}': /* compound statement end */
level--;
if (level < 0) { /* nest error */
output(NESTERR, fpname);
level = 0;
}
break;
case '(': /* function/macro call/declare */
if (define) { /* #define macro() */
if (!lookmac(curchar))
goto notfunc;
macname(); /* macro name */
break;
}
if (!lookmod(curchar)) /* module name */
goto notfunc;
j = modname();
if (!j) goto notfunc; /* not function */
decl = TRUE; /* function */
if (j == 2) /* declaration */
header = TRUE;
break;
notsupp:
notfunc:
default: /* all other characters */
break;
}
if (ins[curchar]) prevchar = (int)ins[curchar++];
}
if (header && !decl && !breakc && !define) {
/* function declaration argument declarations */
comout(ins);
if (ins[0]) output(FUNCARG, ins);
}
if (defname != NULL) free(defname);
} while (lastlin); /* = FALSE if last line */
fclose(fptr);
if (!delimit) output(NOFUNC, newLine);
return;
}
/* process in progress comments and quoted character or strings */
int skipold(breakc)
int *breakc;
{
while (ins[curchar] && *breakc) { /* !EOS & break in progress */
switch (ins[curchar]) {
case '\\': /* escape sequence */
if (ins[(curchar+1)])
++curchar; /* skip a character */
break;
case '\'': /* end quoted character */
if (*breakc != '\'') goto notbreak;
*breakc = FALSE;
break;
case '"': /* end quoted string */
if (*breakc != '"') goto notbreak;
*breakc = FALSE;
break;
case '*': /* end comment ? */
if (*breakc != '/') goto notbreak;
if (ins[(curchar+1)] == '/') {
++curchar;
*breakc = FALSE;
break;
}
notbreak:
default: /* other characters */
break;
}
if (ins[curchar]) prevchar = (int)ins[curchar++];
}
return (*breakc);
}
/* start new comment or quoted character/string process */
int skipnew(breakc)
int *breakc;
{
switch (ins[curchar]) { /* not EOS */
case '/': /* start comment ? */
if (ins[++curchar] != '*') {
break;
}
*breakc = '/'; /* comment started */
if (ins[curchar]) prevchar = (int)ins[curchar];
break;
case '\'': /* start quoted constant */
case '"': /* start quoted string */
*breakc = (int)ins[curchar];
break;
default: /* unknown ? */
break;
}
return (*breakc);
}
/* process #include */
includes()
{
unsigned char delim, *fp;
int filecur, fnamel;
CFLOW *cflows;
filecur = curchar;
if (strncmp("#include", &ins[filecur], 8) != 0)
return (FALSE); /* not #include */
for (filecur += 8; ins[filecur]; filecur++)
if (!isspace(ins[filecur])) break;
if (!ins[filecur]) return (FALSE); /* #include.. only ?! */
delim = ins[filecur++]; /* file name delimiter */
if (delim != '\"' && delim != '<')
return (FALSE); /* #include.. what ?! */
if (delim == '<') delim = '>'; /* #include <...> */
if ((fp = strchr(&ins[filecur], delim)) == NULL)
return (FALSE); /* #include.. what ?! */
if ((fnamel = (fp - &ins[filecur])) == 0)
return (FALSE); /* #include.. what ?! */
fp = alloc(++fnamel);
lower(strncpy(fp, &ins[filecur], (fnamel-1)));
filecur += fnamel; /* skip file name + 1 */
cflows = cflowp; /* current CFLOW ptr */
cflowp = alloc(sizeof(CFLOW)); /* allocate new CFLOW */
chain = cflows; /* build new CFLOW */
name = alloc(MAXBUF);
ins = alloc(MAXBUF);
fname = fp;
if ((strchr(fp, ':') != NULL) /* no -h if drive/path used */
|| (strchr(fp, '\\') != NULL)) {
delimit = 1; /* include with drive/path */
fpname = alloc((strlen(fp) + 1));
strcpy(fpname, fp); /* fpname = fname */
fname = makefile(fname);
free(fp);
}
else {
delimit = delim;
fpname = NULL; /* dynamic fpname at open */
}
fnmbr = cflows->_fnmbr + 1;
flevel++;
level = 0;
modules(); /* recursive call */
--flevel;
cflows = chain; /* dechain CFLOW structure */
free(name);
free(ins);
free(fname);
if (fpname != NULL) free(fpname);
free((char *)cflowp);
cflowp = cflows; /* restore previous CFLOW */
curchar = filecur; /* update buffer index */
}
/* process #defines */
int defines()
{
if (strncmp("define", &ins[(curchar+1)], 6) != 0) {
define = 0;
return (FALSE); /* not #define */
}
define = 1; /* #define 1st level */
curchar += 6; /* skip #define */
return (TRUE); /* #define found */
}
/* look back from position n in string. called with n indicating '('.
determine macro name.
*/
int lookmac(n)
int n;
{
int i;
i = 0;
if (n) { /* ignore white space */
--n;
while (isspace(ins[n])) --n;
}
if (isalnum(ins[n])) { /* find beginning of macro name */
while (n && isalnum(ins[n-1])) --n;
/* save name
include definition if macro declaration
*/
if (define < 2) defdcl = n; /* macro name offset */
while (isalnum(ins[n])) /* macro definition */
name[i++] = ins[n++];
}
name[i] = EOS;
if (i) {
comout(name); /* remove any comment from name string */
if (define < 2) { /* save macro name */
defname = alloc((strlen(name) + 1));
strcpy(defname, name);
}
return (TRUE); /* macro name found */
}
else
return (FALSE); /* macro name not found */
}
/* look back from position n in string. called with n indicating '('.
determine function name.
*/
int lookmod(n)
int n;
{
int i, j, k;
i = 0;
if (n) { /* ignore white space */
--n;
while (isspace(ins[n])) --n;
}
if (isalnum(ins[n])) { /* find beginning of name */
while (n && isalnum(ins[n-1])) --n;
/* save name
include variable declarations if module declaration
*/
if (level == 0) { /* function declaration */
defdcl = n;
j = 0;
while (ins[j]) /* copy full definition */
name[i++] = ins[j++];
defname = alloc((strlen(&ins[defdcl]) + 1));
j = defdcl;
k = 0;
while (isalnum(ins[j])) /* copy name only */
defname[k++] = ins[j++];
defname[k] = EOS;
}
else /* function call */
while (isalnum(ins[n]))
name[i++] = ins[n++];
}
name[i] = EOS;
if (i) {
comout(name); /* remove any comment from name string */
return (TRUE); /* module name found */
}
else
return (FALSE); /* module name not found */
}
/* terminate string at comment, stripping trailing white space */
comout(s)
unsigned char *s;
{
unsigned char c;
while (c = *s++) {
if (c == '\n') {
*--s = EOS;
break;
}
if (c == '/')
if (*s == '*') {
*--s = EOS;
break;
}
}
for (--s; isspace(*s);) *s-- = EOS;
if (*s == '{') {
*s = EOS;
for (--s; isspace(*s);) *s-- = EOS;
}
}
/* display macro name */
macname()
{
char *cp;
if (define < 2) { /* macro start */
define++; /* update macro level */
}
else {
output(MACNME, defname); /* macro name */
cp = alloc((strlen(&ins[defdcl]) + 1));
strcpy(cp, &ins[defdcl]);
comout(cp);
output(MACDCL, cp); /* macro definition */
output(MACEQU, name); /* macro operand */
free(cp);
}
}
/* display module name with indentation according to { level
returns 0 if not module,
1 if call within module,
2 if module declaration
*/
modname()
{
char *cp;
int i, result;
if (unreserved() && !external()) { /* builtin/extern entries */
if (level == 0) {
output(FUNCNME, defname);/* module name */
output(FUNCDCL, name); /* module function */
return (2);
}
else {
output(FUNCREF, name); /* module reference */
return (1);
}
}
return (0);
}
/* generate output based upon type of data and execution flags */
output(type, string, operand)
int type;
unsigned char *string, *operand;
{
char *cptype;
unsigned char outbuf[MAXBUF],
*filter();
int j, slevel;
slevel = level; /* save current level */
switch (type) { /* generate output strings */
case NOFUNC:
if (strchr(string, '%') != NULL) {
sprintf(outbuf, string, operand);
cptype = outbuf;
}
else cptype = string;
break;
case FUNCREF:
strcpy(outbuf, tab);
for (j=0; j < level; ++j)
strcat(outbuf, tab);
sprintf(&outbuf[strlen(outbuf)], "%s()", string);
cptype = outbuf;
break;
case FUNCARG:
cptype = " * %s";
string = filter(string);
break;
case FUNCDCL:
cptype = "** %s";
string = filter(string);
break;
case MACEQU:
cptype = " = %s()";
string = filter(string);
break;
case MACDCL:
cptype = "== %s";
string = filter(string);
break;
case FILENME:
if (flevel) {
cptype = " C Include: %s";
level = flevel;
}
else cptype = " C Source: %s";
break;
case FILEPTH:
if (*string)
if (flevel) {
cptype = "C Include Drive/Path: %s";
level = flevel;
}
else cptype = " C Source Drive/Path: %s";
else cptype = "";
break;
case HDRSYST:
cptype = " C System Header: %s";
break;
case HDRPROJ:
cptype = " C Project Header: %s";
break;
case WILDPTH:
if (*string)
cptype = " WildCard Drive/Path: %s";
else cptype = "";
break;
case WILDNME:
cptype = " WildCard Files: %s";
break;
case WILDNF:
cptype = " No Files Matching: %s";
break;
case FILEERR:
if (flevel)
cptype = "Can't Open C Include: %s";
else cptype = " Can't Open C Source: %s";
break;
case NESTERR:
cptype = " {..} Nesting Error: %s";
break;
case MACNME:
case FUNCNME:
break;
default:
fprintf(stderr,
"\noutput(%d): internal error\n", type);
exit(1);
}
if (!xflag) {
switch (type) { /* perform spacing for types */
case FUNCDCL: /* function declaration */
case MACDCL: /* macro declaration */
case WILDPTH: /* wildcard path name */
case FILEPTH: /* file pathname */
fputs(newLine, stdout);
if (!*cptype) break;
case WILDNME: /* wildcard specification */
case FILENME: /* C source file name */
case FUNCARG: /* function argument */
case FUNCREF: /* function reference */
case MACEQU: /* macro equate */
case NESTERR: /* nesting error */
case FILEERR: /* file error */
case HDRSYST: /* -h system prefix */
case HDRPROJ: /* -h project prefix */
case WILDNF: /* no files match wildcard */
fputs(newLine, stdout);
break;
case MACNME: /* macro name */
case FUNCNME: /* function name */
return;
case NOFUNC: /* non-function output */
default:
break;
}
if (*cptype) {
outhdr(type); /* generate line header */
fprintf(stdout, cptype, string); /* output line */
}
}
else { /* generate CFLOWX output */
if (type) {
if (type == FILEERR) {
output(FILEPTH, "", "");
strcpy(outbuf, "* ");
strcat(outbuf, string);
output(FILENME, outbuf, "");
level = slevel;
return;
}
if (type == WILDNF) {
output(WILDPTH, "", "");
strcpy(outbuf, "# ");
strcat(outbuf, string);
output(WILDNME, outbuf, "");
level = slevel;
return;
}
fprintf(stdout,
cxref(MAXFLDS),
type,
fnmbr,
level,
curline,
string
);
}
}
level = slevel; /* restore current level */
}
/* output line heading */
outhdr(type)
int type;
{
if (type && curline) {
if (fflag) fprintf(stdout, "%s ", fpname);
if (lflag) fprintf(stdout, "%5d: ", curline);
}
}
/* C string filter for extraneous white space */
unsigned char *filter(string)
unsigned char *string;
{
int j;
while (isspace(*string)) ++string;
for (j=0; string[j]; j++)
if (isspace(string[j])) string[j] = ' ';
for (j=0; string[j] && string[(j+1)] != EOS; j++) {
if (string[j] == ' ' && string[(j+1)] == ' ') {
strcpy(&string[j], &string[(j+1)]);
continue;
}
if (string[j] == ' ' && string[(j+1)] == '(') {
strcpy(&string[j], &string[(j+1)]);
continue;
}
if (string[j] == ',' && string[(j+1)] == ' ') {
strcpy(&string[(j+1)], &string[(j+2)]);
continue;
}
if (string[j] == '*' && string[(j+1)] == ' ')
strcpy(&string[(j+1)], &string[(j+2)]);
}
return (string);
}
/* test for C reserved words */
unreserved()
{
if (strncmp(name, "return", 6) == 0
&& !iscname(name[6])) return (FALSE);
else if (strncmp(name, "if", 2) == 0
&& !iscname(name[2])) return (FALSE);
else if (strncmp(name, "while", 5) == 0
&& !iscname(name[5])) return (FALSE);
else if (strncmp(name, "for", 3) == 0
&& !iscname(name[3])) return (FALSE);
else if (strncmp(name, "switch", 6) == 0
&& !iscname(name[6])) return (FALSE);
else if (strncmp(name, "sizeof", 6) == 0
&& !iscname(name[6])) return (FALSE);
else return (TRUE);
}
/* detect "extern" function definitions outside of all functions */
external()
{
char *cp;
int i, rc;
if (level) return (FALSE); /* within a function */
for (i=0; ins[i]; i++) if (isalnum(ins[i])) break;
if (ins[i]) {
if (strncmp(&ins[i], "extern", 6) == 0
&& !iscname(ins[6])) return (TRUE);
if (strncmp(&ins[i], "typedef", 7) == 0
&& !iscname(ins[7])) return (TRUE);
}
cp = alloc(strlen(ins));
strcpy(cp, ins);
comout(cp);
if (*cp)
if (cp[(strlen(cp)-1)] != ')') {
free(cp);
return (TRUE);
}
free(cp);
return (FALSE);
}
/* read a line of source */
int fgets()
{
unsigned char *s;
int ch, count;
s = ins;
count = 0;
while ((ch = getc(fptr)) != EOF) {
buflim(count, MAXBUF);
*s++ = (unsigned char)ch;
++count;
if (ch == '\n') {
buflim(count, MAXBUF);
*s = EOS;
return (TRUE); /* not EOF */
}
}
buflim(count, MAXBUF);
*s = EOS;
return (FALSE); /* EOF */
}
/* test if buffer limit reached */
int buflim(current, limit)
int current, limit;
{
if (current == limit) {
fprintf(stderr,
"\nfgets(): line %d in %s has more than %d characters",
curline, fpname, MAXBUF);
exit(1);
}
}
/* determine if character is valid in a C name or label */
int iscname(c)
unsigned char c;
{
if (isalnum(c)) return (TRUE); /* a-z and A-Z are valid */
switch (c) { /* plus 4 special characters */
case '_':
case '@':
case '$':
case '#':
return (TRUE);
default:
return (FALSE);
}
}
/* end of cflow.c */
e