
/*
**   CFLOW.C : find module call structure of c program
**   refer to cflow.doc for how to use
**	
**		 copyright 1984 by Mark Ellington
**
**     released for public domain use only
**     
*/

#define TRUE	1
#define	FALSE	0
#define	ERROR	-1
#define	EOF	-1	

#include printf.c
#include b:cflolib.c80   /* not needed with BDS? */ 

int fptr;       /* input file pointer */ 
int level;      /* keep track of level of open "{"s */
char name[100]; /* module name buffer */

char ins[100];  /* source input line buffer */
int curchar;	/* current character in input line buffer
		   array subscript */ 	

main(argc,argv)
int argc; char *argv[];
{

	printf("\nCFLOW --> \n");

	if (argc != 2) {
		printf("\nusage: cflow [infilename.ext] "); 
                exit();
	}

	if ((fptr = fopen(argv[1],"r")) == FALSE) {
		printf("\nCan't open %s\n",argv[1]);
		exit();
	}

	printf("\nSource file: %s",argv[1]);

	modules(); 

	fclose(fptr);
}


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 '{') */

	incom = lastlin = quoted  = header = FALSE;

	level = 0;

	do {

		lastlin = fgets();    /* read a line of source */
		
		decl = FALSE;  /* assume nothing */
		curchar = 0;
		while (curchar < 100) {/* read for significant characters */

			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 == '\042') quoted = !quoted;
				
				if (!quoted) {
			
				    switch(c) { 

					case '{' :	
						level++;
						header = FALSE;
						break;

					case '}' :	
						level--;
						break;	

					/* "(" always follows function call */
            				/* or declaration */
			
					case '(' :	

					if (!ischar(ins[curchar-1])) 
						break;
					lookbak(curchar);
					j = modname();
					if (!j) 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 ? */

skipline()
{
char c;
	c = ins[curchar];

	if (c == '\0') return(TRUE);	/* end of line */

	else if (c == '#')    		/* skip macro defs */
		if (curchar < 5)	/* at beginning of line */
			if (!strcmp("define",&ins[curchar+1])) 
				return(TRUE); 

	else return(FALSE);    		/* no */

}


/* skip characters quoted (for instance '}' would throw off level count */

quotes()
{  
	if (flowchar(ins[curchar]))	    /* test critical chars only */
	    if (ins[curchar+1] == '\047')   /* next char single quote? */
		if (curchar+2 < 100)	    /* don't pass end of string */
			curchar = curchar + 2; /* skip past quote */
}


/* return TRUE if entering comment, FALSE if exiting */

comment(incom)
int incom;
{
	if (ins[curchar] == '/') {
		if (ins[curchar+1] == '*') 
			if (curchar + 1 < 100)	/* stay within string */ 
				return(TRUE);
		else if (ins[curchar-1] == '*')
			if (curchar - 1 >= 0)   /* stay within string */
				return(FALSE);
	}
	else return(incom);  /* unchanged */
}


/* look back from position n in string.  called with n indicating '('.
   determine function name  */

lookbak(n)
int n;
{
	int i;

	while (!ischar(ins[n])) {
		if (n == 0) break;
		--n;
	}

	/* find leading blank */
	while (ischar(ins[n-1])) {
		if (n == 0) break;
		--n;
	}

	/* save name */
	/* include variable declarations if module declaration */

	i = 0;
	if (level == 0) {
		while (ins[n]) 		    /* full line if declaration */
			name[i++] = ins[n++];
	}
	else {
		while (ischar(ins[n]))      /* function call within function */
			name[i++] = ins[n++];
	}

	name[i] = '\0';

	comout(name);	/* remove comment from name string */
		
}


/* terminate string at comment */

comout(s)
char *s;
{
char c;	
	
	while(c = *s++) 
		if (c == '/')
			if (*s == '*') {
				--s;
				*s++ = '\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  */

modname()
{
	int j;

	if (unreserved()) {		/* test if builtin like while */
	    	if (level == 0) {
			printf("\n\n\n");
			printf("**\n");
			comout(ins);
			printf("%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 */

unreserved()
{

	if (!strcmp(name,"return")) return(0);
	else if (!strcmp(name,"if")) return(0);
	else if (!strcmp(name,"while")) return(0);
	else if (!strcmp(name,"for")) return(0);
	else if (!strcmp(name,"switch")) return(0);

	else return(1);

}


/* test if character is one that program tracks */

flowchar(c)
char c;
{
	if (c == '{' || c == '}' || c == '\"') return(TRUE);
	else return(FALSE);
} 
	


/* test for character */

ischar(c)
char c;
{
	if (isalpha(c) || isdigit(c)) return(TRUE);
	else return(FALSE);
}


/* read a line of source */

fgets()
{
	char ch, *s;
	s = ins;
	while ((ch = getc(fptr)) != EOF) {
		*s++ = ch;
		if (ch == '\n') {
			*s = '\0';
			return(TRUE);
		}
	}
	*s = '\0';
	return(FALSE);

}	
	



