Category : OS/2 Files
Archive   : OS2TOOLS.ZIP
Filename : CFLOW.C
HEADER: CUG000.00;
TITLE: Function Abstractor;
DATE: 04/19/1987;
DESCRIPTION: "Abstracts C function calls and declarations from a C
source and produces a listing of the program's calling
hierarchy."
VERSION: 3.0;
KEYWORDS: Flow Analysis, Flow Analyzer;
FILENAME: CFLOW.C;
SEE-ALSO: CFLOW.DOC;
COMPILERS: vanilla;
AUTHORS: W. C. Colley III, Mark Ellington;
*/
/*
** CFLOW.C : find module call structure of c program
** refer to cflow.doc for how to use
** Mark Ellington
** 05-27-84
**
** Ported to portable C. Required the following changes:
**
** 1) Stripped BDS C hooks.
** 2) Stripped C/80 hooks.
** 3) Allowed for presence/absence of header files "ctype.h"
** and "string.h".
** 4) Allowed for possible pre-definition of constants TRUE,
** FALSE, and EOF.
** 5) Made variable fptr type FILE * instead of int.
** 6) Added a #define for the max line length.
** 7) Made preprocessor directive rejection logic smarter.
** 8) Removed name conflict between our fgets() and the std
** library fgets() by changing ours to get_source_line().
** William C. Colley, III
** 04-19-87
*/
#include
/*
* Portability Note: The AZTEC C compilers handle the binary/text file
* dichotomy differently from most other compilers. Uncomment the following
* pair of #defines if you are running AZTEC C:
*/
/*
#define getc(f) agetc(f)
#define putc(c,f) aputc(c,f)
*/
/* Portability Note: If you do not have a header file "ctype.h",
uncomment the following #define so that the program will look for
library support. */
/* #define NO_CTYPE_H */
#ifdef NO_CTYPE_H
extern int isalnum();
#else
#include
#endif
/* Portability Note: If you do not have a header file "string.h",
uncomment the following #define so that the program will look for
library support. */
/* #define NO_STRING_H */
#ifdef NO_STRING_H
extern int strcmp();
#else
#include
#endif
/* Portability Note: A few compilers don't know the additional type
void. If yours is one of these, uncomment the following #define. */
/* #define void int */
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef EOF
#define EOF -1
#endif
#define LINE_LENGTH 256 /* Max line length program can handle. */
FILE *fptr; /* input file pointer */
int level; /* keep track of level of open "{"s */
char name[LINE_LENGTH]; /* module name buffer */
char ins[LINE_LENGTH]; /* source input line buffer */
int curchar; /* current character in input line
buffer array subscript */
/* Fixed bug that makes _ characters lop off the beginning of function
names. WCC3. */
int isal_num(c)
int c;
{
return isalnum(c) || c == '_';
}
int main(argc,argv)
int argc;
char *argv[];
{
void modules();
printf("\nCFLOW --> function declarations and calls in C source");
printf("\n by Mark Ellington");
if (argc != 2) {
printf("\nUsage: cflow [infilename.ext] ");
return TRUE;
}
if (!(fptr = fopen(argv[1],"r"))) {
printf("\nCan't open %s\n",argv[1]);
return TRUE;
}
printf("\nSource file: %s",argv[1]);
modules();
fclose(fptr); return FALSE;
}
void modules() /* find function declarations and calls */
{
int j;
char c;
int incom; /* comment flag */
int decl; /* module declaration line flag */
int lastlin; /* last line of file flag */
int quoted; /* within " quotes */
int header; /* within function header (before 1st '{') */
int comment(), get_source_line(), modname(), skipline();
void comout(), lookbak(), quotes();
incom = lastlin = quoted = header = FALSE; level = 0;
do {
lastlin = get_source_line(); /* read a line of source */
decl = FALSE; /* assume nothing */
curchar = 0;
/* read for significant characters */
while (curchar < LINE_LENGTH) {
if (skipline()) break;
quotes(); /* skip single quoted character */
incom = comment(incom); /* true if in comment */
c = ins[curchar];
/* read for significant characters */
if (!incom) {
/* skip double quoted strings */
if (c == '"') quoted = !quoted;
if (!quoted)
switch(c) {
case '{' : level++; header = FALSE;
break;
case '}' : level--;
break;
/* "(" always follows function call */
/* or declaration */
case '(' : if (!isalnum(ins[curchar-1]))
break;
lookbak(curchar);
if (!(j = modname())) break;
else decl = TRUE;
if (j == 2) header = TRUE;
break;
default : break;
}
}
++curchar; /* next character */
}
/* display argument declarations */
comout(ins);
if (header && !decl) printf("%s",ins);
} while (lastlin); /* = 0 if last line */
}
/* skip this line ? */
int skipline()
{
char c;
int i;
if (!(c = ins[curchar])) return TRUE; /* end of line */
if (c == '#') { /* skip preprocessor directives */
for (i = curchar; i--; )
if (ins[i] != ' ' && ins[i] != '\t') return FALSE;
return TRUE;
}
return FALSE; /* don't skip */
}
/* skip characters quoted (for instance '}' would throw off level count) */
void quotes()
{
int flowchar();
if (flowchar(ins[curchar]) && /* test critical chars only */
ins[curchar+1] == '\'' && /* next char single quote? */
curchar+2 < LINE_LENGTH) /* don't pass end of string */
curchar = curchar + 2; /* skip past quote */
}
/* return TRUE if entering comment, FALSE if exiting */
int comment(incom)
int incom;
{
if (ins[curchar] == '/') {
if (ins[curchar+1] == '*') return TRUE;
if (curchar > 0 && ins[curchar-1] == '*') return FALSE;
}
return incom; /* unchanged */
}
/* look back from position n in string. called with n indicating '('.
determine function name */
void lookbak(n)
int n;
{
int i;
void comout();
while (!isal_num(ins[n]) && n) --n;
/* find leading blank */
while (isal_num(ins[n-1]) && n) --n;
/* save name */
/* include variable declarations if module declaration */
i = 0;
if (level == 0) /* full line if declaration */
while (ins[n]) name[i++] = ins[n++];
else /* function call within function */
while (isal_num(ins[n])) name[i++] = ins[n++];
name[i] = '\0';
comout(name); /* remove comment from name string */
}
/* terminate string at comment */
void comout(s)
char *s;
{
char c;
while (c = *s++)
if (c == '/')
if (*s == '*') {
*(s - 1) = '\n';
*s = '\0';
break;
}
}
/* display module name with indentation according to { level */
/* returns 0 if not module, 1 if call within module, 2 if */
/* module declaration */
int modname()
{
int j, unreserved();
void comout();
if (unreserved()) { /* test if builtin like while */
if (level == 0) {
comout(ins);
printf("\n\n\n**\n%s",ins);
return 2;
}
else {
printf("\n");
for (j=0; j < level; ++j)
putchar('\t');
printf("%s()",name);
return 1;
}
}
return 0;
}
/* test for names that are operators not functions */
int unreserved()
{
return strcmp(name,"return") &&
strcmp(name,"if") &&
strcmp(name,"while") &&
strcmp(name,"for") &&
strcmp(name,"switch");
}
/* test if character is one that program tracks */
int flowchar(c)
char c;
{
return c == '{' || c == '}' || c == '\"';
}
/* read a line of source */
int get_source_line()
{
char *s;
int ch;
s = ins;
while ((ch = getc(fptr)) != EOF) {
if ((*s++ = ch) == '\n') {
*s = '\0';
return TRUE;
}
}
*s = '\0';
return FALSE;
}
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/