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; } } }
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); }