/*
 *   Copyright (C) 1988-2006 Lucent Technologies Inc. and others.
 *   All Rights Reserved.
 */

/*	cscope - interactive C symbol or text cross-reference
 *
 *	"ccalls" searching functions
 */

#include "global.h"

#if defined( __STDC__ ) || defined( __BORLANDC__ )
void	savepostingcalling(POSTING *p, char *srcline, char *lineno, char *macro, char *symbol, char *savep);
void	savepostingref(POSTING *p, char *srcline, char *lineno, char *symbol, char *savep);
void	saveinclude(char *file, char *srcline, char *lineno, char *incfile);
void	saveccalls(char *file, char *function, char *srcline, char *lineno, char *params);
void	savefcns(char *file, char *function, char *srcline, char *startline, char *endline);
void	saveref(char *file, char *function, char *srcline, char *lineno, char *symbol);
void	savesource(char *save);
void	saveline(char *s);
void	splitsource(char *line, char *source);
char	*scanback(char *savep);
char	*scanfwd(char *savep);
BOOL	scanposting(char *savep);
int	accept(char *s);
#else
void	savepostingcalling();
void	savepostingref();
void	saveinclude();
void	saveccalls();
void	savefcns();
void	saveref();
void	savesource();
void	saveline();
void	splitsource();
char	*scanback();
char	*scanfwd();
BOOL	scanposting();
int	accept();
#endif

/* find only preprocessor includes - used by ccalls only */

void
findincludes()
{
	char	file[PATHLEN + 1];	/* source file name */
	char	incfile[PATLEN + 1];	/* include file */
	char	srcline[PATLEN + 1];	/* source line */
	char	lineno[PATLEN + 1];	/* line number */
	register char	*s;

	if (invertedindex == YES) {
		POSTING	*p;
		
		findterm();
		while ((p = getposting()) != NULL) {
			if (p->type == INCLUDE) {
				if (dbseek(p->lineoffset) != -1 &&
				    scanpast('\t') != NULL) {
					while (p->type != *blockp &&
					       scanpast('\t') != NULL) ;
					skiprefchar();
					getstring(incfile);
					saveinclude(srcfiles[p->fileindex],srcline,lineno,incfile);
				}
			}
		}
		return;
	}
	/* find the next file name or function definition */
	while (scanpast('\t') != NULL) {
		switch (*blockp) {
			
		case NEWFILE:		/* save file name */
			skiprefchar();
			getstring(file);
			if (*file == '\0') {	/* if end of symbols */
				return;
			}
			fileprogress();
			break;
			
		case INCLUDE:		/* match function called to pattern */
			s = incfile;
			skiprefchar();
			getstring(s);

			/* see if this is a regular expression pattern */
			if (regexp != NULL) {
				if (caseless == YES) {
					s = strtolower(s);
				}
				if (*s != '\0' && regex(regexp, s) != NULL) {
					goto matched;
				}
			}
			/* match the symbol to the text pattern */
			else if (strequal(pattern, s)) {
		matched:
				/* save the include */
				saveinclude(file,srcline,lineno,incfile);
			}
		}
	}
}

/* find only preprocessor definitions - used by ccalls only */

void
finddefine()
{
	char	file[PATHLEN + 1];	/* source file name */
	char	function[PATLEN + 1];	/* function name */
	char	macro[PATLEN + 1];	/* macro name */
	char	lineno[PATLEN + 1];	/* line number */
	char	srcline[PATLEN + 1];	/* source line */
	register char	*s, *savep;

	if (invertedindex == YES) {
		POSTING	*p;
		
		findterm();
		while ((p = getposting()) != NULL) {
			switch (p->type) {
			case DEFINE:		/* could be a macro */
				if (dbseek(p->lineoffset) != -1 &&
				    scanpast('\t') != NULL) {
					while (p->type != *blockp &&
					       scanpast('\t') != NULL) ;
					skiprefchar();
					getstring(macro);
					savep = blockp;
					savepostingref(p,srcline,lineno,macro,savep);
					(void) scanback(savep);
					while (scanpast('\t') != NULL &&
					       p->type == *blockp) {
						skiprefchar();
						getstring(macro);
						savep = blockp;
						if (scanposting(savep) == NO) {
							savepostingref(p,srcline,lineno,macro,savep);
							(void) scanback(savep);
						} else break;
					}
				}
			}
		}
		return;
	}
	/* find the next file name or definition */
	*function = '\0';
	*macro = '\0';	/* a macro can be inside a function, but not vice versa */
	while (scanpast('\t') != NULL) {
		switch (*blockp) {
			
		case NEWFILE:
			skiprefchar();	/* save file name */
			getstring(file);
			if (*file == '\0') {	/* if end of symbols */
				return;
			}
			fileprogress();
			/* FALLTHROUGH */
			
		case FCNEND:		/* function end */
			*function = '\0';
			break;
			
		case FCNDEF:
			skiprefchar();	/* save function name */
			getstring(function);
			break;

		case DEFINE:		/* could be a macro */
			s = macro;
			/* save the name */
			skiprefchar();
			getstring(s);

			/* see if this is a regular expression pattern */
			if (regexp != NULL) {
				if (caseless == YES) {
					s = strtolower(s);
				}
				if (*s != '\0' && regex(regexp, s) != NULL) {
					goto matched;
				}
			}
			/* match the symbol to the text pattern */
			else if (strequal(pattern, s)) {
		matched:
				saveref(file,function,srcline,lineno,macro);
			}
		}
	}
}

/* find only type definitions - used by ccalls only */

void
findtypedef()
{
	char	file[PATHLEN + 1];	/* source file name */
	char	function[PATLEN + 1];	/* function name */
	char	symbol[PATLEN + 1];	/* symbol name */
	char	lineno[PATLEN + 1];	/* line number */
	char	srcline[PATLEN + 1];	/* source line */
	register char	*s, *savep;

	if (invertedindex == YES) {
		POSTING	*p;
		
		findterm();
		while ((p = getposting()) != NULL) {
			switch (p->type) {
			case TYPEDEF:
				if (dbseek(p->lineoffset) != -1 &&
				    scanpast('\t') != NULL) {
					while (p->type != *blockp &&
					       scanpast('\t') != NULL) ;
					skiprefchar();
					getstring(symbol);
					savep = blockp;
					savepostingref(p,srcline,lineno,symbol,savep);
					(void) scanback(savep);
					while (scanpast('\t') != NULL &&
					       p->type == *blockp) {
						skiprefchar();
						getstring(symbol);
						savep = blockp;
						if (scanposting(savep) == NO) {
							savepostingref(p,srcline,lineno,symbol,savep);
							(void) scanback(savep);
						} else break;
					}
				}
			}
		}
		return;
	}
	*function = '\0';
	/* find the next file name or definition */
	while (scanpast('\t') != NULL) {
		switch (*blockp) {
			
		case NEWFILE:
			skiprefchar();	/* save file name */
			getstring(file);
			if (*file == '\0') {	/* if end of symbols */
				return;
			}
			fileprogress();
			/* FALLTHROUGH */
			
		case FCNEND:		/* function end */
			*function = '\0';
			break;
			
		case FCNDEF:
			skiprefchar();	/* save function name */
			getstring(function);
			break;

		case TYPEDEF:
			s = symbol;
			/* save the name */
			skiprefchar();
			getstring(s);

			/* see if this is a regular expression pattern */
			if (regexp != NULL) {
				if (caseless == YES) {
					s = strtolower(s);
				}
				if (*s != '\0' && regex(regexp, s) != NULL) {
					goto matched;
				}
			}
			/* match the symbol to the text pattern */
			else if (strequal(pattern, s)) {
		matched:
				savep = blockp;
				saveref(file,function,srcline,lineno,symbol);
				(void) scanback(savep);
			}
		}
	}
}

/* find only global definitions - used by ccalls only */

void
findglobals()
{
	char	file[PATHLEN + 1];	/* source file name */
	char	function[PATLEN + 1];	/* function name */
	char	symbol[PATLEN + 1];	/* symbol name */
	char	lineno[PATLEN + 1];	/* line number */
	char	srcline[PATLEN + 1];	/* source line */
	register char	*s, *savep;

	if (invertedindex == YES) {
		POSTING	*p;
		
		findterm();
		while ((p = getposting()) != NULL) {
			switch (p->type) {
			case GLOBALDEF:		/* other global definition */
				if (dbseek(p->lineoffset) != -1 &&
				    scanpast('\t') != NULL) {
					while (p->type != *blockp &&
					       scanpast('\t') != NULL) ;
					skiprefchar();
					getstring(symbol);
					savep = blockp;
					savepostingref(p,srcline,lineno,symbol,savep);
					(void) scanback(savep);
					while (scanpast('\t') != NULL &&
					       p->type == *blockp) {
						skiprefchar();
						getstring(symbol);
						savep = blockp;
						if (scanposting(savep) == NO) {
							savepostingref(p,srcline,lineno,symbol,savep);
							(void) scanback(savep);
						} else break;
					}
				}
			}
		}
		return;
	}
	/* find the next file name or definition */
	*function = '\0';
	while (scanpast('\t') != NULL) {
		switch (*blockp) {
			
		case NEWFILE:
			skiprefchar();	/* save file name */
			getstring(file);
			if (*file == '\0') {	/* if end of symbols */
				return;
			}
			fileprogress();
			/* FALLTHROUGH */
			
		case FCNEND:		/* function end */
			*function = '\0';
			break;
			
		case FCNDEF:
			skiprefchar();	/* save function name */
			getstring(function);
			break;
			
		case GLOBALDEF:		/* other global definition */
			s = symbol;
			/* save the name */
			skiprefchar();
			getstring(s);

			/* see if this is a regular expression pattern */
			if (regexp != NULL) {
				if (caseless == YES) {
					s = strtolower(s);
				}
				if (*s != '\0' && regex(regexp, s) != NULL) {
					goto matched;
				}
			}
			/* match the symbol to the text pattern */
			else if (strequal(pattern, s)) {
		matched:
				savep = blockp;
				saveref(file,function,srcline,lineno,symbol);
				(void) scanback(savep);
			}
		}
	}
}

/* find only local definitions - used by ccalls only */

void
findlocals()
{
	char	file[PATHLEN + 1];	/* source file name */
	char	function[PATLEN + 1];	/* function name */
	char	symbol[PATLEN + 1];	/* symbol name */
	char	lineno[PATLEN + 1];	/* line number */
	char	srcline[PATLEN + 1];	/* source line */
	register char	*s, *savep;

	if (invertedindex == YES) {
		POSTING	*p;
		
		findterm();
		while ((p = getposting()) != NULL) {
			switch (p->type) {
			case LOCALDEF:		/* other local definition */
				if (dbseek(p->lineoffset) != -1 &&
				    scanpast('\t') != NULL) {
					while (p->type != *blockp &&
					       scanpast('\t') != NULL) ;
					skiprefchar();
					getstring(symbol);
					savep = blockp;
					savepostingref(p,srcline,lineno,symbol,savep);
					(void) scanback(savep);
					while (scanpast('\t') != NULL &&
					       p->type == *blockp) {
						skiprefchar();
						getstring(symbol);
						savep = blockp;
						if (scanposting(savep) == NO) {
							savepostingref(p,srcline,lineno,symbol,savep);
							(void) scanback(savep);
						} else break;
					}
				}
			}
		}
		return;
	}
	/* find the next file name or definition */
	*function = '\0';
	while (scanpast('\t') != NULL) {
		switch (*blockp) {
			
		case NEWFILE:
			skiprefchar();	/* save file name */
			getstring(file);
			if (*file == '\0') {	/* if end of symbols */
				return;
			}
			fileprogress();
			/* FALLTHROUGH */
			
		case FCNEND:		/* function end */
			*function = '\0';
			break;
			
		case FCNDEF:
			skiprefchar();	/* save function name */
			getstring(function);
			break;

		case LOCALDEF:		/* other local definition */
			s = symbol;
			/* save the name */
			skiprefchar();
			getstring(s);

			/* see if this is a regular expression pattern */
			if (regexp != NULL) {
				if (caseless == YES) {
					s = strtolower(s);
				}
				if (*s != '\0' && regex(regexp, s) != NULL) {
					goto matched;
				}
			}
			/* match the symbol to the text pattern */
			else if (strequal(pattern, s)) {
		matched:
				savep = blockp;
				saveref(file,function,srcline,lineno,symbol);
				(void) scanback(savep);
			}
		}
	}
}

/* find only structure definitions - used by ccalls only */

void
findstructures()
{
	char	file[PATHLEN + 1];	/* source file name */
	char	function[PATLEN + 1];	/* function name */
	char	structure[PATLEN + 1];	/* structure name */
	char	member[PATLEN + 1];	/* member name */
	char	symbol[PATHLEN + 1];	/* symbol name */
	char	lineno[PATLEN + 1];	/* line number */
	char	srcline[PATLEN + 1];	/* source line */
	register char	*s, *savep;
	BOOL	scandone,scanstart;

	if (invertedindex == YES) {
		POSTING	*p;
		
		findterm();
		*structure = '\0';
		*member = '\0';
		while ((p = getposting()) != NULL) {
			switch (p->type) {
			case MEMBERDEF:
			case STRUCTDEF:
				if (dbseek(p->lineoffset) != -1 &&
				    scanpast('\t') != NULL) {
					while (p->type != *blockp &&
					       scanpast('\t') != NULL) ;
					skiprefchar();
					switch (p->type) {
					case MEMBERDEF:
						getstring(member);
						break;
					case STRUCTDEF:
						getstring(structure);
						*member = '\0';
						break;
					}
					if (*structure != '\0' && *member != '\0') {
						(void) sprintf(symbol,"%s %s",structure,member);
						savep = blockp;
						savepostingref(p,srcline,lineno,symbol,savep);
						(void) scanback(savep);
					}
					if (p->type == STRUCTDEF) break;
					scandone = NO;
					scanstart = NO;
					while (scanpast('\t') != NULL) {
						skiprefchar();
						switch (p->type) {
						case MEMBERDEF:
							if (p->type == *blockp)
								scanstart = YES;
							getstring(member);
							break;
						case STRUCTDEF:
							if (p->type == *blockp)
								scanstart = YES;
							getstring(structure);
							*member = '\0';
							break;
						default:
							if (scanstart == YES)
								scandone = YES;
							break;
						}
						if (scandone == NO && *structure != '\0' && *member != '\0') {
							(void) sprintf(symbol,"%s %s",structure,member);
							savep = blockp;
							if (scanposting(savep) == NO) {
								savepostingref(p,srcline,lineno,symbol,savep);
								(void) scanback(savep);
							} else scandone = YES;
						}
						if (scandone == YES) break;
					}
				}
			}
		}
		return;
	}
	/* find the next file name or definition */
	*function = '\0';
	*structure = '\0';
	*member = '\0';
	while (scanpast('\t') != NULL) {
		switch (*blockp) {
			
		case NEWFILE:
			skiprefchar();	/* save file name */
			getstring(file);
			if (*file == '\0') {	/* if end of symbols */
				return;
			}
			fileprogress();
			/* FALLTHROUGH */
			
		case FCNEND:		/* function end */
			*function = '\0';
			break;
			
		case FCNDEF:		/* function name */
			skiprefchar();	/* save function name */
			getstring(function);
			break;

		case MEMBERDEF:
			s = member;
			goto def;

		case STRUCTDEF:
			s = structure;
			*member = '\0';
		def:
			/* save the name */
			skiprefchar();
			getstring(s);

			/* see if this is a regular expression pattern */
			if (regexp != NULL) {
				if (caseless == YES) {
					s = strtolower(s);
				}
				if (*s != '\0' && regex(regexp, s) != NULL) {
					goto matched;
				}
			}
			/* match the symbol to the text pattern */
			else if (strequal(pattern, s)) {
		matched:
				if (*structure != '\0' && *member != '\0') {
					(void) sprintf(symbol,"%s %s",structure,member);
					savep = blockp;
					saveref(file,function,srcline,lineno,symbol);
					(void) scanback(savep);
				}
			}
		}
	}
}

/* find only parameters - used by ccalls only */

void
findparameters()
{
	char	file[PATHLEN + 1];	/* source file name */
	char	function[PATLEN + 1];	/* function name */
	char	passed[PATLEN + 1];	/* passed parameter name */
	char	lineno[PATLEN + 1];	/* line number */
	char	srcline[PATLEN + 1];	/* source line */
	register char	*s, *savep;

	if (invertedindex == YES) {
		POSTING	*p;
		
		findterm();
		while ((p = getposting()) != NULL) {
			switch (p->type) {
			case PARAMETER:		/* initial value */
				if (dbseek(p->lineoffset) != -1 &&
				    scanpast('\t') != NULL) {
					while (p->type != *blockp &&
					       scanpast('\t') != NULL) ;
					skiprefchar();
					getstring(passed);
					savep = blockp;
					savepostingref(p,srcline,lineno,passed,savep);
					(void) scanback(savep);
					while (scanpast('\t') != NULL &&
					       p->type == *blockp) {
						skiprefchar();
						getstring(passed);
						savep = blockp;
						if (scanposting(savep) == NO) {
							savepostingref(p,srcline,lineno,passed,savep);
							(void) scanback(savep);
						} else break;
					}
				}
			}
		}
		return;
	}
	/* find the next file name or definition */
	*function = '\0';
	*passed = '\0';
	while (scanpast('\t') != NULL) {
		switch (*blockp) {
			
		case NEWFILE:
			skiprefchar();	/* save file name */
			getstring(file);
			if (*file == '\0') {	/* if end of symbols */
				return;
			}
			fileprogress();
			/* FALLTHROUGH */
			
		case FCNEND:		/* function end */
			*function = '\0';
			break;
			
		case FCNDEF:		/* function name */
			skiprefchar();	/* save function name */
			getstring(function);
			break;

		case PARAMETER:		/* initial value */
			s = passed;
			skiprefchar();
			getstring(s);

			/* see if this is a regular expression pattern */
			if (regexp != NULL) {
				if (caseless == YES) {
					s = strtolower(s);
				}
				if (*s != '\0' && regex(regexp, s) != NULL) {
					goto matched;
				}
			}
			/* match the symbol to the text pattern */
			else if (strequal(pattern, s)) {
		matched:
				savep = blockp;
				saveref(file,function,srcline,lineno,passed);
				(void) scanback(savep);
			}
		}
	}
}

/* find calling functions - used by ccalls only */

void
findccalling()
{
	char	file[PATHLEN + 1];	/* source file name */
	char	function[PATLEN + 1];	/* function name */
	char	called[PATLEN + 1];	/* called name */
	char	macro[PATHLEN + 1];	/* macro name */
	char	symbol[PATHLEN + 1];	/* symbol name */
	char	lineno[PATLEN + 1];	/* line number */
	char	srcline[PATLEN + 1];	/* source line */
	register char	*s, *savep;
	BOOL	scandone,scanstart;

	if (invertedindex == YES) {
		POSTING	*p;
		
		findterm();
		while ((p = getposting()) != NULL) {
			switch (p->type) {
			case DEFINE:
			case FCNCALL:
				if (dbseek(p->lineoffset) != -1) {
					scandone = NO;
					scanstart = NO;
					*macro = '\0';
					*called = '\0';
					while (scanpast('\t') != NULL) {
						switch (*blockp) {
						case DEFINE:
							if (p->type == *blockp)
								scanstart = YES;
							skiprefchar();
							getstring(macro);
							break;
						case FCNCALL:
							if (p->type == *blockp)
								scanstart = YES;
							skiprefchar();
							getstring(called);
							break;
						default:
							if (scanstart == YES)
								scandone = YES;
							break;
						}
						if (scandone == NO && *called != '\0') {
							savep = blockp;
							if (scanposting(savep) == NO) { 
								savepostingcalling(p,srcline,lineno,macro,called,savep);
								(void) scanback(savep);
							} else {
								scandone = YES;
							}
							*macro = '\0';
							*called = '\0';
						}
						if (scandone == YES) break;
					}
				}
			}
		}
		return;
	}
	/* find the next file name or definition */
	*function = '\0';
	*called = '\0';
	*macro = '\0';	/* a macro can be inside a function, but not vice versa */
	while (scanpast('\t') != NULL) {
		switch (*blockp) {
			
		case NEWFILE:
			skiprefchar();	/* save file name */
			getstring(file);
			if (*file == '\0') {	/* if end of symbols */
				return;
			}
			fileprogress();
			/* FALLTHROUGH */
			
		case FCNEND:		/* function end */
			*function = '\0';
			break;
			
		case FCNDEF:		/* function name */
			skiprefchar();	/* save function name */
			getstring(function);
			break;

		case DEFINE:		/* could be a macro */
			if (fileversion >= 10) {
				s = macro;
			}
			else {
				s = symbol;
			}
			skiprefchar();	/* save macro name */
			getstring(s);
			break;

		case DEFINEEND:
			*macro = '\0';
			break;

		case FCNCALL:		/* function call */
			s = called;
			skiprefchar();	/* save function call */
			getstring(s);

			/* see if this is a regular expression pattern */
			if (regexp != NULL) {
				if (caseless == YES) {
					s = strtolower(s);
				}
				if (*s != '\0' && regex(regexp, s) != NULL) {
					goto matched;
				}
			}
			/* match the symbol to the text pattern */
			else if (strequal(pattern, s)) {
		matched:
				savep = blockp;
				if (*macro != '\0') {
					if (systemcalls == NO || 
					    (accept(macro) && accept(called))) {
						saveref(file,macro,srcline,lineno,called);
					}
				} else if (*function != '\0') {
					if (systemcalls == NO || 
					    (accept(function) && accept(called))) {
						saveref(file,function,srcline,lineno,called);
					}
				}
				(void) scanback(savep);
			}
		}
	}
}

/* find functions and parameters  - used by ccalls only */

void
findccalls()
{
	char	file[PATHLEN + 1];	/* source file name */
	char	function[PATLEN + 1];	/* function name */
	char	params[PATLEN + 1];	/* parameters */
	char	lineno[PATLEN + 1];	/* line number */
	char	srcline[PATLEN + 1];	/* source line */
	register char *s;

	if (invertedindex == YES) {
		POSTING	*p;
		
		findterm();
		while ((p = getposting()) != NULL) {
			switch (p->type) {
			case FCNDEF:
				*params = '\0';
				if (dbseek(p->lineoffset) != -1 &&
				    scanpast('\t') != NULL) {
					while (p->type != *blockp &&
					       scanpast('\t') != NULL) ;
					skiprefchar();
					getstring(function);
					saveccalls(srcfiles[p->fileindex],function,srcline,lineno,params);
				}
			}
		}
		return;
	}
	/* find the next file name or definition */
	*function = '\0';
	*params = '\0';
	while (scanpast('\t') != NULL) {
		switch (*blockp) {
			
		case NEWFILE:
			skiprefchar();	/* save file name */
			getstring(file);
			if (*file == '\0') {	/* if end of symbols */
				return;
			}
			fileprogress();
			/* FALLTHROUGH */
			
		case FCNEND:		/* function end */
			*function = '\0';
			break;
			
		case FCNDEF:		/* function name */
			s = function;
			skiprefchar();	/* save function name */
			getstring(s);

			*params = '\0';

			/* see if this is a regular expression pattern */
			if (regexp != NULL) {
				if (caseless == YES) {
					s = strtolower(s);
				}
				if (*s != '\0' && regex(regexp, s) != NULL) {
					goto matched;
				}
			}
			/* match the symbol to the text pattern */
			else if (strequal(pattern, s)) {
		matched:
				saveccalls(file,function,srcline,lineno,params);
			}
		}
	}
}

/* find all regular expression function definitions (used by ccalls and cdb only) */

void
findregexpfcns()
{
	char	file[PATHLEN + 1];	/* source file name */
	char	savefcn[PATLEN + 1];	/* saved function name */
	char	function[PATLEN + 1];	/* function name */
	char	startline[PATLEN + 1];	/* start line */
	char	endline[PATLEN + 1];	/* end line */
	char	srcline[PATLEN + 1];	/* source line */
	BOOL	infcn;			/* avoid #ifdefs around functions */
	register char *s;

	if (invertedindex == YES) {
		POSTING	*p;
		
		findterm();
		*function = '\0';
		infcn = NO;
		while ((p = getposting()) != NULL) {
			switch (p->type) {
			case FCNDEF:
			case CLASSDEF:
				if (dbseek(p->lineoffset) != -1 &&
				    scanpast('\t') != NULL) {
					while (p->type != *blockp &&
					       scanpast('\t') != NULL) ;
					skiprefchar();
					getstring(function);
					if (infcn == NO) {
						infcn = YES;
						(void) strcpy(savefcn,function);
						savesource(srcline);
						splitsource(startline,srcline);
					}
					while (scanpast('\t') != NULL ) {
						if (*blockp == FCNEND ||
						    *blockp == NEWFILE) break;
					}
					if (*blockp == FCNEND) {
						infcn = NO;
						if (*function != '\0') {
							savefcns(srcfiles[p->fileindex],savefcn,srcline,startline,endline);
							*function = '\0';
						}
					}
				}
			}
		}
		return;
	}
	infcn = NO;
	*function = '\0';
	/* find the next file name or definition */
	while (scanpast('\t') != NULL) {
		switch (*blockp) {
			
		case NEWFILE:
			infcn = NO;
			skiprefchar();	/* save file name */
			getstring(file);
			if (*file == '\0') {	/* if end of symbols */
				return;
			}
			fileprogress();
			break;

		case FCNDEF:
		case CLASSDEF:
			skiprefchar();	/* save function name */
			s = function;
			getstring(s);

			/* see if this is a regular expression pattern */
			if (regexp != NULL) {
				if (caseless == YES) {
					s = strtolower(s);
				}
				if (*s == '\0' || regex(regexp, s) == NULL) {
					*function = '\0';
					break;
				}
			}
			/* match the symbol to the text pattern */
			else if (!strequal(pattern, s)) {
				*function = '\0';
				break;
			}

			if (infcn == NO) {
				infcn = YES;
				(void) strcpy(savefcn,function);

				/* save the source line */
				savesource(srcline);

				/* split srcline into startline */
				splitsource(startline,srcline);
			}
			break;

		case FCNEND:		/* function end */
			infcn = NO;
			if (*function != '\0') {
				savefcns(file,savefcn,srcline,startline,endline);
				*function = '\0';
			}
			break;

		}
	}
}

/* save the posting calling reference into the file */

void
savepostingcalling(p,srcline,lineno,macro,symbol,savep)
POSTING	*p;
char	*srcline;
char	*lineno;
char	*macro;
char	*symbol;
char	*savep;
{
	static	char	function[PATLEN + 1];	/* function name */

	if (p->fcnoffset == 0) {
		*function = '\0';
	}
	else if (p->fcnoffset != lastfcnoffset) {
		if (dbseek(p->fcnoffset) != -1) {
			getstring(function);
			lastfcnoffset = p->fcnoffset;
		}
	}
	if (dbseek(p->lineoffset) != -1) {
		/* scan forward to savep */
		(void) scanfwd(savep);
		if (*macro != '\0') {
			if (systemcalls == NO ||
			    (accept(macro) && accept(symbol))) {
				saveref(srcfiles[p->fileindex], macro, srcline, lineno, symbol);
			}
		} else if (*function != '\0') {
			if (systemcalls == NO ||
			    (accept(function) && accept(symbol))) {
				saveref(srcfiles[p->fileindex], function, srcline, lineno, symbol);
			}
		}
	}
}

/* save the posting reference into the file */

void
savepostingref(p,srcline,lineno,symbol,savep)
POSTING	*p;
char	*srcline;
char	*lineno;
char	*symbol;
char	*savep;
{
	static	char	function[PATLEN + 1];	/* function name */

	if (p->fcnoffset == 0) {
		*function = '\0';
	}
	else if (p->fcnoffset != lastfcnoffset) {
		if (dbseek(p->fcnoffset) != -1) {
			getstring(function);
			lastfcnoffset = p->fcnoffset;
		}
	}
	if (dbseek(p->lineoffset) != -1) {
		/* scan forward to savep */
		(void) scanfwd(savep);
		saveref(srcfiles[p->fileindex], function, srcline, lineno, symbol);
	}
}

/* save the include into the file */

void
saveinclude(file, srcline, lineno, incfile)
char	*file;
char	*srcline;
char	*lineno;
char	*incfile;
{
	register char *s;

	/* save the source line */
	savesource(srcline);

	/* split srcline into lineno */
	splitsource(lineno,srcline);

	s = "/usr/include/";

	if (strncmp(file, s, strlen(s)) == 0) {
		/* output the relative file name */
		(void) fprintf(refsfound, "%s <global> ", filepath(file+strlen(s)));
	} else {
		/* output the file name */
		(void) fprintf(refsfound, "%s <global> ", filepath(file));
	}

	s = incfile;
	if ((*s == '"') || (*s == '<')) ++s;

	/* output the rest of the source line */
	(void) fprintf(refsfound, "%d %s %s\n", atoi(lineno), s, srcline); 
}

/* save the calls into the file */

void
saveccalls(file, function, srcline, lineno, params)
char	*file;
char	*function;
char	*srcline;
char	*lineno;
char	*params;
{
	char	templine[PATLEN + 1];	/* source line */
	char	templineno[PATLEN + 1];	/* line number */
	int	lastlinelen;
	register char	*s, *t;

	lastlinelen = 0;
	do {
		/* save the source line */
		savesource(templine);

		/* split srcline into lineno */
		splitsource(templineno,templine);

		if (lastlinelen == 0) {
			(void) strcpy(srcline,templine);
			(void) strcpy(lineno,templineno);
		} else {
			/* Add in close bracket */
			/* Assumes only one parameter */
			templine[strlen(templine)+1] = '\0';
			templine[strlen(templine)] = ')';
		}

		/* read function parameters */
		s = templine;
		t = params + strlen(params);
		if (lastlinelen == 0) {
			while (*s != '(') s++;
		}
		do {
			/* eliminate blanks and append params */
			if (*s != ' ' && *s != '\t') {
				*t = *s;
				++t;
				*t = '\0';
			}
			++s;
		} while (strchr(params,')') == (char *)0 &&
		         s - templine <= strlen(templine));

		if (strchr(params,')') == (char *)0) {
			lastlinelen = 1;
		} else {
			lastlinelen = 0;
		}
	} while (lastlinelen == 1);

	if (params[strlen(params)] != ')') {
		params[strlen(params)+2] = '\0';
		params[strlen(params)+1] = ')';
	}

	/* output the file name */
	(void) fprintf(nonglobalrefs, "%s ", filepath(file));

	/* output the function name */
	(void) fprintf(nonglobalrefs, "%s ", function);

	/* output the start line */
	(void) fprintf(nonglobalrefs, "%d ", atoi(lineno));

	/* output the parameters */
	(void) fprintf(nonglobalrefs, "%s%s ", function, params);

	/* output the rest of the source line */
	(void) fprintf(nonglobalrefs, "%s\n", srcline);
}

/* save the functions into the file */

void
savefcns(file, function, srcline, startline, endline)
char	*file;
char	*function;
char	*srcline;
char	*startline;
char	*endline;
{
	/* output the file name */
	(void) fprintf(nonglobalrefs, "%s ", filepath(file));

	/* output the function name */
	(void) fprintf(nonglobalrefs, "%s ", function);

	/* output the start line */
	(void) fprintf(nonglobalrefs, "%d ", atoi(startline));

	/* save the source line */
	savesource(endline);

	/* output the end line */
	(void) fprintf(nonglobalrefs, "%d ", atoi(endline));

	/* output the rest of the source line */
	(void) fprintf(nonglobalrefs, "%s\n", srcline);
}

/* save the reference into the file */

void
saveref(file, function, srcline, lineno, symbol)
char	*file;
char	*function;
char	*srcline;
char	*lineno;
char	*symbol;
{
	FILE	*output;

	/* put global references first */
	if (*function == '\0') {
		function = "<global>";
		output = refsfound;
	}
	else {
		output = nonglobalrefs;
	}
	if (fprintf(output, "%s %s ", filepath(file), function) == EOF) {
		cannotwrite(temp1);
		/* NOTREACHED */
	}
	/* save the source line */
	savesource(srcline);
	/* split srcline into lineno */
	splitsource(lineno,srcline);
	/* output the rest of the source line */
	if (fprintf(output, "%d %s %s\n", atoi(lineno), symbol, srcline) == EOF) {
		cannotwrite(temp1);
		/* NOTREACHED */
	}
}

/* save the source line */

void
savesource(save)
char	*save;
{
	register char	*cp, nextc = '\0';

	/* scan back to the beginning of the source line */
	cp = blockp;
	nextc = '\0';
	while (*cp != '\n' || nextc != '\n') {
		nextc = *cp;
		if (--cp < block) {
			
			/* read the previous block */
			(void) dbseek((blocknumber - 1) * BUFSIZ);
			cp = &block[BUFSIZ - 1];
		}
	}
	/* there must be a double newline followed by a line number */
	blockp = cp;
	setmark(' ');	/* so getrefchar doesn't skip the last block char */
	if (*blockp != '\n' || getrefchar() != '\n' ||
	    !isdigit(getrefchar()) && fileversion >= 12) {
		putmsg("Internal error: cannot get source line from database");
		myexit(1);
	}

	/* save source line for later */
	cp = save;
	/* until a double newline is found */
	do {
		/* skip a symbol type */
		if (*blockp == '\t') {
			skiprefchar();
			skiprefchar();
		}
		saveline(cp);
		cp = save + strlen(save);
	} while (blockp != NULL && getrefchar() != '\n');
}

/* save the rest of the cross-reference line into the file */

void
saveline(s)
register char	*s;
{
	register char	*cp;
	register unsigned c;
	register struct	keystruct *p;
	register char	*t;
	
	setmark('\n');
	cp = blockp;
	do {
		while ((c = *cp) != '\n') {
			
			/* check for a compressed digraph */
			if (c & 0200) {
				c &= 0177;
				*s++ = dichar1[c / 8];
				*s++ = dichar2[c & 7];
			}
			/* check for a compressed keyword */
			else if (c < ' ') {
#ifdef MULTILINGUAL
				p = keyword(c);
#else
				p = &keyword[c];
#endif
				t = p->text;
				while (*t != '\0') {
					*s++ = *t++;
				}
				if (p->delim != '\0') {
					*s++ = ' ';
				}
				if (p->delim == '(') {
					*s++ = '(';
				}
			}
			else {
				*s++ = c;
			}
			++cp;
		}
	} while (*(cp + 1) == '\0' && (cp = readblock()) != NULL);
	blockp = cp;
	*s = '\0';
}

/* split the source line */

void
splitsource(line,source)
char	*line,*source;
{
	register char	*s,*t;

	s = source;
	t = line;
	while (*s >= '0' && *s <= '9') {
		*t = *s;
		s++;
		t++;
	}
	*t = '\0';
	s++;

	/* shift source left */
	t = source;
	while (s < source + strlen(source)) {
		*t = *s;
		s++;
		t++;
	}
	*t = '\0';
}

/* scan back to the start of the line */

char
*scanback(savep)
register char *savep;
{
	register char *s;

	/* Because savesource skips the rest of the line, scan back to savep */
	s = blockp;
	if (s < savep) {

		/* read the previous block */
		(void) dbseek((blocknumber - 1) * BUFSIZ);
		s = &block[BUFSIZ - 1];
	}
	while (s > savep) --s;
	blockp = s;
	return(blockp);
}

/* scan forward from the start of the line */

char
*scanfwd(savep)
register char *savep;
{
	register char *s;

	/* Because savepostingcalling goes back to the start of the line, scan forward to savep */
	s = blockp;
	if (s > savep) {

		/* read the next block */
		(void) dbseek((blocknumber + 1) * BUFSIZ);
		s = &block[0];
	}
	while (s < savep) ++s;
	blockp = s;
	return(blockp);
}

/* scan to next posting */

BOOL scanposting(savep)
char *savep;
{
	POSTING *p;

	p = peekposting();

	if (savep > (block + p->lineoffset % BUFSIZ)) {
		return(YES);
	} else if (blocknumber > (p->lineoffset / BUFSIZ)) {
		return(YES);
	} else {
		return(NO);
	}
}

int accept(s)
char *s;
{
	int code;
	int i;

	/* unix system calls and subroutines */
	static char *unixcalls[] =
		{
		"_exit",
		"_tolower",
		"_toupper",
		"a64l",
		"abort",
		"abs",
		"access",
		"acct",
		"acos",
		"advfs",
		"alarm",
		"asctime",
		"asin",
		"assert",
		"atan",
		"atan2",
		"atof",
		"atoi",
		"atol",
		"brk",
		"bsearch",
		"calloc",
		"ceil",
		"chdir",
		"chmod",
		"chown",
		"chroot",
		"clearerr",
		"clock",
		"close",
		"cos",
		"cosh",
		"creat",
		"crypt",
		"ctermid",
		"ctime",
		"curses",
		"cuserid",
		"ddim",
		"dial",
		"dim",
		"dkbreak",
		"dkdial",
		"dkenviron",
		"dkeof",
		"dkerr",
		"dkmgr",
		"dkminor",
		"dknamer",
		"dksplice",
		"dkxstdio",
		"dprod",
		"drand48",
		"dup",
		"ecvt",
		"edata",
		"encrypt",
		"end",
		"endgrent",
		"endpwent",
		"endutent",
		"erand48",
		"erf",
		"erfc",
		"errno",
		"etext",
		"execl",
		"execle",
		"execlp",
		"execv",
		"execve",
		"execvp",
		"exit",
		"exp",
		"fabs",
		"fclose",
		"fcntl",
		"fcvt",
		"fdopen",
		"feof",
		"ferror",
		"fflush",
		"fgetc",
		"fgetgrent",
		"fgetpwent",
		"fgets",
		"fileno",
		"floor",
		"fmod",
		"fopen",
		"fork",
		"fprintf",
		"fputc",
		"fputs",
		"fread",
		"free",
		"freopen",
		"frexp",
		"fscanf",
		"fseek",
		"fstat",
		"fstatfs",
		"ftell",
		"ftok",
		"ftw",
		"fwrite",
		"gamma",
		"gcvt",
		"getc",
		"getchar",
		"getcwd",
		"getdents",
		"getegid",
		"getenv",
		"geteuid",
		"getgid",
		"getgrent",
		"getgrgid",
		"getgrnam",
		"getlogin",
		"getmsg",
		"getopt",
		"getpass",
		"getpgrp",
		"getpid",
		"getppid",
		"getpw",
		"getpwent",
		"getpwnam",
		"getpwuid",
		"gets",
		"getuid",
		"getutent",
		"getutid",
		"getutline",
		"getw",
		"gmtime",
		"gsignal",
		"hcreate",
		"hdestroy",
		"hsearch",
		"hypot",
		"iargc",
		"idim",
		"ioctl",
		"irand",
		"isalnum",
		"isalpha",
		"isascii",
		"isatty",
		"iscntrl",
		"isdigit",
		"isgraph",
		"islower",
		"isprint",
		"ispunct",
		"isspace",
		"isupper",
		"isxdigit",
		"j0",
		"j1",
		"jn",
		"jrand48",
		"kill",
		"l3tol",
		"l64a",
		"lcong48",
		"ldaclose",
		"ldahread",
		"ldaopen",
		"ldclose",
		"ldexp",
		"ldfhread",
		"ldgetname",
		"ldlinit",
		"ldlitem",
		"ldlread",
		"ldlseek",
		"ldnlseek",
		"ldnrseek",
		"ldnshread",
		"ldnsseek",
		"ldohseek",
		"ldopen",
		"ldrseek",
		"ldshread",
		"ldsseek",
		"ldtbindex",
		"ldtbread",
		"ldtbseek",
		"lfind",
		"lge",
		"lgt",
		"link",
		"lle",
		"llt",
		"localtime",
		"lockf",
		"log",
		"log10",
		"logname",
		"longjmp",
		"lrand48",
		"lsearch",
		"lseek",
		"ltol3",
		"mallinfo",
		"malloc",
		"mallopt",
		"maphost",
		"matherr",
		"memccpy",
		"memchr",
		"memcmp",
		"memcpy",
		"memset",
		"mkdir",
		"mknod",
		"mktemp",
		"modf",
		"monitor",
		"mount",
		"mrand48",
		"msgctl",
		"msgget",
		"nice",
		"nlist",
		"nrand48",
		"open",
		"pause",
		"pclose",
		"perror",
		"pipe",
		"plock",
		"plot",
		"popen",
		"pow",
		"ppremote",
		"printf",
		"profil",
		"ptrace",
		"putc",
		"putchar",
		"putenv",
		"putmsg",
		"putpwent",
		"puts",
		"pututline",
		"putw",
		"qsort",
		"rand",
		"read",
		"realloc",
		"regcmp",
		"regex",
		"rewind",
		"rexecl",
		"rexecv",
		"rfstart",
		"rmdir",
		"sbrk",
		"scanf",
		"seed48",
		"semctl",
		"semget",
		"semop",
		"setbuf",
		"setgid",
		"setgrent",
		"setjmp",
		"setkey",
		"setpgrp",
		"setpwent",
		"setuid",
		"setutent",
		"setvbuf",
		"sgetl",
		"shmctl",
		"shmget",
		"sighold",
		"sigignore",
		"signal",
		"sigpause",
		"sigrelse",
		"sigset",
		"sin",
		"sinh",
		"sleep",
		"sprintf",
		"sputl",
		"sqrt",
		"srand",
		"srand48",
		"sscanf",
		"ssignal",
		"stat",
		"statfs",
		"stdio",
		"stdipc",
		"stime",
		"strcat",
		"strchr",
		"strcmp",
		"strcpy",
		"strcspn",
		"strlen",
		"strncat",
		"strncmp",
		"strncpy",
		"strpbrk",
		"strrchr",
		"strspn",
		"strtod",
		"strtok",
		"strtol",
		"swab",
		"sync",
		"sys_errlist",
		"sys_nerr",
		"sysfs",
		"system",
		"t_accept",
		"t_alloc",
		"t_bind",
		"t_close",
		"t_connect",
		"t_error",
		"t_free",
		"t_getinfo",
		"t_getstate",
		"t_listen",
		"t_look",
		"t_open",
		"t_optmgmt",
		"t_rcv",
		"t_rcvconnect",
		"t_rcvdis",
		"t_rcvrel",
		"t_rcvudata",
		"t_rcvuderr",
		"t_snd",
		"t_snddis",
		"t_sndrel",
		"t_sndudata",
		"t_sync",
		"t_unbind",
		"tan",
		"tanh",
		"tdelete",
		"tempnam",
		"tfind",
		"time",
		"times",
		"tmpfile",
		"tmpnam",
		"toascii",
		"tolower",
		"toupper",
		"tsearch",
		"ttyname",
		"ttyslot",
		"twalk",
		"tzset",
		"ulimit",
		"umask",
		"umount",
		"uname",
		"undial",
		"ungetc",
		"unlink",
		"ustat",
		"utime",
		"utmpname",
		"vfprintf",
		"vprintf",
		"vsprintf",
		"wait",
		"write",
		"y0",
		"y1",
		"yn",
		""
		};

	code = 1;

	/* for each UNIX subroutine or system call */

	for(i = 0; strlen(unixcalls[i]); ++i)
		{
		/* if function name matches */
		if(strcmp(s, unixcalls[i]) == 0)
			{
			code = 0;
			break;
			}
		}

	return(code);
}
