Пример #1
0
void
crossref(char *srcfile)
{
    unsigned int i;
    unsigned int length;	/* symbol length */
    unsigned int entry_no;	/* function level of the symbol */
    int token;                  /* current token */
    struct stat st;

    if (! ((stat(srcfile, &st) == 0)
	   && S_ISREG(st.st_mode))) {
	cannotopen(srcfile);
	errorsfound = YES;
	return;
    }
	
    entry_no = 0;
    /* open the source file */
    if ((yyin = myfopen(srcfile, "r")) == NULL) {
	cannotopen(srcfile);
	errorsfound = YES;
	return;
    }
    filename = srcfile;	/* save the file name for warning messages */
    putfilename(srcfile);	/* output the file name */
    dbputc('\n');
    dbputc('\n');

    /* read the source file */
    initscanner(srcfile);
    fcnoffset = macrooffset = 0;
    symbols = 0;
    if (symbol == NULL) {
	symbol = mymalloc(msymbols * sizeof(struct symbol));
    }
    for (;;) {
		
	/* get the next token */
	switch (token = yylex()) {
	default:
	    /* if requested, truncate C symbols */
	    length = last - first;
	    if (trun_syms == YES && length > 8 &&
		token != INCLUDE && token != NEWFILE) {
		length = 8;
		last = first + 8;
	    }
	    /* see if the token has a symbol */
	    if (length == 0) {
		savesymbol(token, entry_no);
		break;
	    }
	    /* update entry_no if see function entry */
	    if (token == FCNDEF) {
		entry_no++;
	    }
	    /* see if the symbol is already in the list */
	    for (i = 0; i < symbols; ++i) {
		if (length == symbol[i].length
		    && strncmp(my_yytext + first,
			       my_yytext + symbol[i].first,
			       length) == 0 
		    && entry_no == symbol[i].fcn_level
		    && token == symbol[i].type
		    ) {	/* could be a::a() */
		    break;
		}
	    }
	    if (i == symbols) {	/* if not already in list */
		savesymbol(token, entry_no);
	    }
	    break;

	case NEWLINE:	/* end of line containing symbols */
	    entry_no = 0;	/* reset entry_no for each line */
#ifdef USING_LEX
	    --yyleng; 	/* remove the newline */
#endif
	    putcrossref();	/* output the symbols and source line */
	    lineno = myylineno;	/* save the symbol line number */
#ifndef USING_LEX
	    /* HBB 20010425: replaced yyleng-- by this chunk: */
	    if (my_yytext)
		*my_yytext = '\0';
	    my_yyleng = 0;
#endif
	    break;
			
	case LEXERR:	/* Lexer error, abort further parsing of this file */
	case LEXEOF:	/* end of file; last line may not have \n */
			
			/* if there were symbols, output them and the source line */
	    if (symbols > 0) {
		putcrossref();
	    }
	    (void) fclose(yyin);	/* close the source file */

	    /* output the leading tab expected by the next call */
	    dbputc('\t');
	    return;
	}
    }
}
Пример #2
0
static void
build(void)
{
	int	i;
	FILE	*oldrefs;	/* old cross-reference file */
	time_t	reftime;	/* old crossref modification time */
	char	*file;			/* current file */
	char	*oldfile;		/* file in old cross-reference */
	char	newdir[PATHLEN + 1];	/* directory in new cross-reference */
	char	olddir[PATHLEN + 1];	/* directory in old cross-reference */
	char	oldname[PATHLEN + 1];	/* name in old cross-reference */
	int	oldnum;			/* number in old cross-ref */
	struct	stat statstruct;	/* file status */
	int	firstfile;		/* first source file in pass */
	int	lastfile;		/* last source file in pass */
	int	built = 0;		/* built crossref for these files */
	int	copied = 0;		/* copied crossref for these files */
	BOOL	interactive = YES;	/* output progress messages */

	/*
	 * normalize the current directory relative to the home directory so
	 * the cross-reference is not rebuilt when the user's login is moved
	 */
	(void) strcpy(newdir, currentdir);
	if (strcmp(currentdir, home) == 0) {
		(void) strcpy(newdir, "$HOME");
	} else if (strncmp(currentdir, home, strlen(home)) == 0) {
		(void) sprintf(newdir, "$HOME%s", currentdir + strlen(home));
	}
	/* sort the source file names (needed for rebuilding) */
	qsort((char *)srcfiles, (unsigned)nsrcfiles, sizeof (char *), compare);

	/*
	 * if there is an old cross-reference and its current directory
	 * matches or this is an unconditional build
	 */
	if ((oldrefs = vpfopen(reffile, "r")) != NULL && unconditional == NO &&
	    fscanf(oldrefs, "cscope %d %s", &fileversion, olddir) == 2 &&
	    (strcmp(olddir, currentdir) == 0 || /* remain compatible */
	    strcmp(olddir, newdir) == 0)) {

		/* get the cross-reference file's modification time */
		(void) fstat(fileno(oldrefs), &statstruct);
		reftime = statstruct.st_mtime;
		if (fileversion >= 8) {
			BOOL	oldcompress = YES;
			BOOL	oldinvertedindex = NO;
			BOOL	oldtruncatesyms = NO;
			int	c;

			/* see if there are options in the database */
			for (;;) {
				while ((c = getc(oldrefs)) == ' ') {
				}
				if (c != '-') {
					(void) ungetc(c, oldrefs);
					break;
				}
				switch (c = getc(oldrefs)) {
				case 'c':	/* ASCII characters only */
					oldcompress = NO;
					break;
				case 'q':	/* quick search */
					oldinvertedindex = YES;
					(void) fscanf(oldrefs,
					    "%ld", &totalterms);
					break;
				case 'T':
					/* truncate symbols to 8 characters */
					oldtruncatesyms = YES;
					break;
				}
			}
			/* check the old and new option settings */
			if (oldcompress != compress ||
			    oldtruncatesyms != truncatesyms) {
				(void) fprintf(stderr,
				    "cscope: -c or -T option mismatch between "
				    "command line and old symbol database\n");
				goto force;
			}
			if (oldinvertedindex != invertedindex) {
				(void) fprintf(stderr,
				    "cscope: -q option mismatch between "
				    "command line and old symbol database\n");
				if (invertedindex == NO) {
					removeindex();
				}
				goto outofdate;
			}
			/* seek to the trailer */
			if (fscanf(oldrefs, "%ld", &traileroffset) != 1 ||
			    fseek(oldrefs, traileroffset, 0) == -1) {
				(void) fprintf(stderr,
				    "cscope: incorrect symbol database file "
				    "format\n");
				goto force;
			}
		}
		/* if assuming that some files have changed */
		if (fileschanged == YES) {
			goto outofdate;
		}
		/* see if the view path is the same */
		if (fileversion >= 13 &&
		    samelist(oldrefs, vpdirs, vpndirs) == NO) {
			goto outofdate;
		}
		/* see if the directory lists are the same */
		if (samelist(oldrefs, srcdirs, nsrcdirs) == NO ||
		    samelist(oldrefs, incdirs, nincdirs) == NO ||
		    fscanf(oldrefs, "%d", &oldnum) != 1 ||
		    fileversion >= 9 && fscanf(oldrefs, "%*s") != 0) {
			/* skip the string space size */
			goto outofdate;
		}
		/*
		 * see if the list of source files is the same and
		 * none have been changed up to the included files
		 */
		for (i = 0; i < nsrcfiles; ++i) {
			if (fscanf(oldrefs, "%s", oldname) != 1 ||
			    strnotequal(oldname, srcfiles[i]) ||
			    vpstat(srcfiles[i], &statstruct) != 0 ||
			    statstruct.st_mtime > reftime) {
				goto outofdate;
			}
		}
		/* the old cross-reference is up-to-date */
		/* so get the list of included files */
		while (i++ < oldnum && fscanf(oldrefs, "%s", oldname) == 1) {
			addsrcfile(oldname);
		}
		(void) fclose(oldrefs);
		return;

outofdate:
		/* if the database format has changed, rebuild it all */
		if (fileversion != FILEVERSION) {
			(void) fprintf(stderr,
			    "cscope: converting to new symbol database file "
			    "format\n");
			goto force;
		}
		/* reopen the old cross-reference file for fast scanning */
		if ((symrefs = vpopen(reffile, O_RDONLY)) == -1) {
			cannotopen(reffile);
			myexit(1);
		}
		/* get the first file name in the old cross-reference */
		blocknumber = -1;
		(void) readblock();	/* read the first cross-ref block */
		(void) scanpast('\t');	/* skip the header */
		oldfile = getoldfile();
	} else {	/* force cross-referencing of all the source files */
force:
		reftime = 0;
		oldfile = NULL;
	}
	/* open the new cross-reference file */
	if ((newrefs = fopen(newreffile, "w")) == NULL) {
		cannotopen(newreffile);
		myexit(1);
	}
	if (invertedindex == YES && (postings = fopen(temp1, "w")) == NULL) {
		cannotopen(temp1);
		cannotindex();
	}
	(void) fprintf(stderr, "cscope: building symbol database\n");
	putheader(newdir);
	fileversion = FILEVERSION;
	if (buildonly == YES && !isatty(0)) {
		interactive = NO;
	} else {
		initprogress();
	}
	/* output the leading tab expected by crossref() */
	dbputc('\t');

	/*
	 * make passes through the source file list until the last level of
	 * included files is processed
	 */
	firstfile = 0;
	lastfile = nsrcfiles;
	if (invertedindex == YES) {
		srcoffset = mymalloc((nsrcfiles + 1) * sizeof (long));
	}
	for (;;) {

		/* get the next source file name */
		for (fileindex = firstfile; fileindex < lastfile; ++fileindex) {
			/* display the progress about every three seconds */
			if (interactive == YES && fileindex % 10 == 0) {
				if (copied == 0) {
					progress("%ld files built",
					    (long)built, 0L);
				} else {
					progress("%ld files built, %ld "
					    "files copied", (long)built,
					    (long)copied);
				}
			}
			/* if the old file has been deleted get the next one */
			file = srcfiles[fileindex];
			while (oldfile != NULL && strcmp(file, oldfile) > 0) {
				oldfile = getoldfile();
			}
			/*
			 * if there isn't an old database or this is
			 * a new file
			 */
			if (oldfile == NULL || strcmp(file, oldfile) < 0) {
				crossref(file);
				++built;
			} else if (vpstat(file, &statstruct) == 0 &&
			    statstruct.st_mtime > reftime) {
				/* if this file was modified */
				crossref(file);
				++built;

				/*
				 * skip its old crossref so modifying the last
				 * source file does not cause all included files
				 * to be built.  Unfortunately a new file that
				 * is alphabetically last will cause all
				 * included files to be built, but this is
				 * less likely
				 */
				oldfile = getoldfile();
			} else {	/* copy its cross-reference */
				putfilename(file);
				if (invertedindex == YES) {
					copyinverted();
				} else {
					copydata();
				}
				++copied;
				oldfile = getoldfile();
			}
		}
		/* see if any included files were found */
		if (lastfile == nsrcfiles) {
			break;
		}
		firstfile = lastfile;
		lastfile = nsrcfiles;
		if (invertedindex == YES) {
			srcoffset = myrealloc(srcoffset,
			    (nsrcfiles + 1) * sizeof (long));
		}
		/* sort the included file names */
		qsort((char *)&srcfiles[firstfile],
		    (unsigned)(lastfile - firstfile), sizeof (char *), compare);
	}
	/* add a null file name to the trailing tab */
	putfilename("");
	dbputc('\n');

	/* get the file trailer offset */

	traileroffset = dboffset;

	/*
	 * output the view path and source and include directory and
	 * file lists
	 */
	putlist(vpdirs, vpndirs);
	putlist(srcdirs, nsrcdirs);
	putlist(incdirs, nincdirs);
	putlist(srcfiles, nsrcfiles);
	if (fflush(newrefs) == EOF) {
		/* rewind doesn't check for write failure */
		cannotwrite(newreffile);
		/* NOTREACHED */
	}
	/* create the inverted index if requested */
	if (invertedindex == YES) {
		char	sortcommand[PATHLEN + 1];

		if (fflush(postings) == EOF) {
			cannotwrite(temp1);
			/* NOTREACHED */
		}
		(void) fstat(fileno(postings), &statstruct);
		(void) fprintf(stderr,
		    "cscope: building symbol index: temporary file size is "
		    "%ld bytes\n", statstruct.st_size);
		(void) fclose(postings);
	/*
	 * sort -T is broken until it is fixed we don't have too much choice
	 */
	/*
	 * (void) sprintf(sortcommand, "sort -y -T %s %s", tmpdir, temp1);
	 */
	(void) sprintf(sortcommand, "LC_ALL=C sort %s", temp1);
		if ((postings = popen(sortcommand, "r")) == NULL) {
			(void) fprintf(stderr,
			    "cscope: cannot open pipe to sort command\n");
			cannotindex();
		} else {
			if ((totalterms = invmake(newinvname, newinvpost,
			    postings)) > 0) {
				movefile(newinvname, invname);
				movefile(newinvpost, invpost);
			} else {
				cannotindex();
			}
			(void) pclose(postings);
		}
		(void) unlink(temp1);
		(void) free(srcoffset);
		(void) fprintf(stderr,
		    "cscope: index has %ld references to %ld symbols\n",
		    npostings, totalterms);
	}
	/* rewrite the header with the trailer offset and final option list */
	rewind(newrefs);
	putheader(newdir);
	(void) fclose(newrefs);

	/* close the old database file */
	if (symrefs >= 0) {
		(void) close(symrefs);
	}
	if (oldrefs != NULL) {
		(void) fclose(oldrefs);
	}
	/* replace it with the new database file */
	movefile(newreffile, reffile);
}