int invopen(INVCONTROL *invcntl, char *invname, char *invpost, int stat) { int read_index; if ((invcntl->invfile = vpfopen(invname, ((stat == 0) ? "rb" : "r+b"))) == NULL) { /* If db created without '-f', but now invoked with '-f cscope.out', * we need to check for 'cscope.in.out', rather than 'cscope.out.in': * I.e, hack around our own violation of the inverse db naming convention */ if (!invflipname(invname, INVNAME2, INVNAME)) { if ((invcntl->invfile = vpfopen(invname, ((stat == 0) ? "rb" : "r+b")))) goto openedinvname; invflipname(invname, INVNAME, INVNAME2); /* change back for err msg */ } /* more silliness: if you create the db with '-f cscope', then try to open * it without '-f cscope', you'll fail unless we check for 'cscope.out.in' * here. */ else if (!invflipname(invname, INVNAME, INVNAME2)) { if ((invcntl->invfile = vpfopen(invname, ((stat == 0) ? "rb" : "r+b")))) goto openedinvname; invflipname(invname, INVNAME2, INVNAME); /* change back for err msg */ } invcannotopen(invname); return(-1); } openedinvname: if (fread(&invcntl->param, sizeof(invcntl->param), 1, invcntl->invfile) == 0) { fprintf(stderr, "%s: empty inverted file\n", argv0); goto closeinv; } if (invcntl->param.version != FMTVERSION) { fprintf(stderr, "%s: cannot read old index format; use -U option to force database to rebuild\n", argv0); goto closeinv; } assert(invcntl->param.sizeblk == sizeof(t_logicalblk)); if (stat == 0 && invcntl->param.filestat == INVALONE) { fprintf(stderr, "%s: inverted file is locked\n", argv0); goto closeinv; } if ((invcntl->postfile = vpfopen(invpost, ((stat == 0) ? "rb" : "r+b"))) == NULL) { /* exact same naming convention hacks as above for invname */ if (!invflipname(invpost, INVPOST2, INVPOST)) { if ((invcntl->postfile = vpfopen(invpost, ((stat == 0) ? "rb" : "r+b")))) goto openedinvpost; invflipname(invpost, INVPOST, INVPOST2); /* change back for err msg */ } else if (!invflipname(invpost, INVPOST, INVPOST2)) { if ((invcntl->postfile = vpfopen(invpost,((stat == 0)?"rb":"r+b")))) goto openedinvpost; invflipname(invpost, INVPOST2, INVPOST); /* change back for err msg */ } invcannotopen(invpost); goto closeinv; } openedinvpost: /* allocate core for a logical block */ if ((invcntl->logblk = malloc((unsigned) invcntl->param.sizeblk)) == NULL) { invcannotalloc((unsigned) invcntl->param.sizeblk); goto closeboth; } /* allocate for and read in superfinger */ read_index = 1; invcntl->iindex = NULL; #if SHARE if (invcntl->param.share == 1) { key_t shm_key; struct shmid_ds shm_buf; int shm_id; /* see if the shared segment exists */ shm_key = ftok(invname, 2); shm_id = shmget(shm_key, 0, 0); /* Failure simply means (hopefully) that segment doesn't exists */ if (shm_id == -1) { /* Have to give general write permission due to AMdahl not having protected segments */ shm_id = shmget(shm_key, invcntl->param.supsize + sizeof(long), IPC_CREAT | 0666); if (shm_id == -1) perror("Could not create shared memory segment"); } else read_index = 0; if (shm_id != -1) { invcntl->iindex = shmat(shm_id, 0, ((read_index) ? 0 : SHM_RDONLY)); if (invcntl->iindex == (char *)ERR) { fprintf(stderr, "%s: shared memory link failed\n", argv0); invcntl->iindex = NULL; read_index = 1; } } } #endif if (invcntl->iindex == NULL) /* FIXME HBB: magic number alert (4) */ invcntl->iindex = malloc((unsigned) invcntl->param.supsize + 4 *sizeof(long)); if (invcntl->iindex == NULL) { invcannotalloc((unsigned) invcntl->param.supsize); free(invcntl->logblk); goto closeboth; } if (read_index) { fseek(invcntl->invfile, invcntl->param.startbyte, SEEK_SET); fread(invcntl->iindex, (int) invcntl->param.supsize, 1, invcntl->invfile); } invcntl->numblk = -1; if (boolready() == -1) { closeboth: fclose(invcntl->postfile); closeinv: fclose(invcntl->invfile); return(-1); } /* write back out the control block if anything changed */ invcntl->param.filestat = stat; if (stat > invcntl->param.filestat ) { rewind(invcntl->invfile); fwrite(&invcntl->param, sizeof(invcntl->param), 1, invcntl->invfile); } return(1); }
long invmake(char *invname, char *invpost, FILE *infile) { unsigned char *s; long num; int i; long fileindex = 0; /* initialze, to avoid warning */ unsigned postsize = POSTINC * sizeof(POSTING); unsigned long *intptr; char line[TERMMAX]; long tlong; PARAM param; POSTING posting; char temp[BLOCKSIZE]; #if STATS int j; unsigned maxtermlen = 0; #endif /* output file */ if ((outfile = vpfopen(invname, "w+b")) == NULL) { invcannotopen(invname); return(0); } indexfile = invname; fseek(outfile, BUFSIZ, SEEK_SET); /* posting file */ if ((fpost = vpfopen(invpost, "wb")) == NULL) { invcannotopen(invpost); return(0); } postingfile = invpost; nextpost = 0; /* get space for the postings list */ if ((POST = malloc(postsize)) == NULL) { invcannotalloc(postsize); return(0); } postptr = POST; /* get space for the superfinger (superindex) */ if ((SUPFING = malloc(supersize)) == NULL) { invcannotalloc(supersize); return(0); } supfing = SUPFING; /* FIXME HBB: magic number alert (40) */ supintsize = supersize / 40; /* also for the superfinger index */ if ((SUPINT = malloc(supintsize * sizeof(long))) == NULL) { invcannotalloc(supintsize * sizeof(long)); return(0); } supint = SUPINT; supint++; /* leave first term open for a count */ /* initialize using an empty term */ strcpy(thisterm, ""); *supint++ = 0; *supfing++ = ' '; *supfing++ = '\0'; nextsupfing = 2; #if DEBUG || STATS totpost = 0L; #endif totterm = 0L; numpost = 1; /* set up as though a block had come and gone, i.e., set up for new block */ /* 3 longs needed for: numinvitems, next block, and previous block */ amtused = 3 * sizeof(long); numinvitems = 0; numlogblk = 0; lastinblk = sizeof(t_logicalblk); /* now loop as long as more to read (till eof) */ while (fgets(line, TERMMAX, infile) != NULL) { #if DEBUG || STATS ++totpost; #endif s = strchr(line, SEP); if (s != NULL) { *s = '\0'; } else { continue; } #if STATS if ((i = strlen(line)) > maxtermlen) { maxtermlen = i; } #endif #if DEBUG printf("%ld: %s ", totpost, line); fflush(stdout); #endif if (strcmp(thisterm, line) == 0) { if (postptr + 10 > POST + postsize / sizeof(POSTING)) { i = postptr - POST; postsize += POSTINC * sizeof(POSTING); if ((POST = realloc(POST, postsize)) == NULL) { invcannotalloc(postsize); return(0); } postptr = i + POST; #if DEBUG printf("reallocated post space to %u, totpost=%ld\n", postsize, totpost); #endif } numpost++; } else { /* have a new term */ if (!invnewterm()) { return(0); } strcpy(thisterm, line); numpost = 1; postptr = POST; fileindex = 0; } /* get the new posting */ num = *++s - '!'; i = 1; do { num = BASE * num + *++s - '!'; } while (++i < PRECISION); posting.lineoffset = num; while (++fileindex < nsrcfiles && num > srcoffset[fileindex]) { ; } posting.fileindex = --fileindex; posting.type = *++s; ++s; if (*s != '\n') { num = *++s - '!'; while (*++s != '\n') { num = BASE * num + *s - '!'; } posting.fcnoffset = num; } else { posting.fcnoffset = 0; } *postptr++ = posting; #if DEBUG printf("%ld %ld %ld %ld\n", posting.fileindex, posting.fcnoffset, posting.lineoffset, posting.type); fflush(stdout); #endif } if (!invnewterm()) { return(0); } /* now clean up final block */ logicalblk.invblk[0] = numinvitems; /* loops pointer around to start */ logicalblk.invblk[1] = 0; logicalblk.invblk[2] = numlogblk - 1; if (fwrite(&logicalblk, sizeof(t_logicalblk), 1, outfile) == 0) { goto cannotwrite; } numlogblk++; /* write out block to save space. what in it doesn't matter */ if (fwrite(&logicalblk, sizeof(t_logicalblk), 1, outfile) == 0) { goto cannotwrite; } /* finish up the super finger */ *SUPINT = numlogblk; /* add to the offsets the size of the offset pointers */ intptr = (SUPINT + 1); i = (char *)supint - (char *)SUPINT; while (intptr < supint) *intptr++ += i; /* write out the offsets (1 for the N at start) and the super finger */ if (fwrite(SUPINT, sizeof(*SUPINT), numlogblk + 1, outfile) == 0 || fwrite(SUPFING, 1, supfing - SUPFING, outfile) == 0) { goto cannotwrite; } /* save the size for reference later */ nextsupfing = sizeof(long) + sizeof(long) * numlogblk + (supfing - SUPFING); /* make sure the file ends at a logical block boundary. This is necessary for invinsert to correctly create extended blocks */ i = nextsupfing % sizeof(t_logicalblk); /* write out junk to fill log blk */ if (fwrite(temp, sizeof(t_logicalblk) - i, 1, outfile) == 0 || fflush(outfile) == EOF) { /* rewind doesn't check for write failure */ goto cannotwrite; } /* write the control area */ rewind(outfile); param.version = FMTVERSION; param.filestat = 0; param.sizeblk = sizeof(t_logicalblk); param.startbyte = (numlogblk + 1) * sizeof(t_logicalblk) + BUFSIZ;; param.supsize = nextsupfing; param.cntlsize = BUFSIZ; param.share = 0; if (fwrite(¶m, sizeof(param), 1, outfile) == 0) { goto cannotwrite; } for (i = 0; i < 10; i++) /* for future use */ if (fwrite(&zerolong, sizeof(zerolong), 1, outfile) == 0) { goto cannotwrite; } /* make first block loop backwards to last block */ if (fflush(outfile) == EOF) { /* fseek doesn't check for write failure */ goto cannotwrite; } /* get to second word first block */ fseek(outfile, BUFSIZ + 2 * sizeof(long), SEEK_SET); tlong = numlogblk - 1; if (fwrite(&tlong, sizeof(tlong), 1, outfile) == 0 || fclose(outfile) == EOF) { cannotwrite: invcannotwrite(invname); return(0); } if (fclose(fpost) == EOF) { invcannotwrite(postingfile); return(0); } --totterm; /* don't count null term */ #if STATS printf("logical blocks = %d, postings = %ld, terms = %ld, max term length = %d\n", numlogblk, totpost, totterm, maxtermlen); if (showzipf) { printf("\n************* ZIPF curve ****************\n"); for (j = ZIPFSIZE; j > 1; j--) if (zipf[j]) break; for (i = 1; i < j; ++i) { printf("%3d -%6d ", i, zipf[i]); if (i % 6 == 0) putchar('\n'); } printf(">%d-%6d\n", ZIPFSIZE, zipf[0]); } #endif /* free all malloc'd memory */ free(POST); free(SUPFING); free(SUPINT); return(totterm); }
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); }
void makefilelist(void) { static BOOL firstbuild = YES; /* first time through */ FILE *names; /* name file pointer */ char dir[PATHLEN + 1]; char path[PATHLEN + 1]; struct stat statstruct; char *file; char *s; int i, j; /* if there are source file arguments */ if (fileargc > 0) { /* put them in a list that can be expanded */ for (i = 0; i < fileargc; ++i) { file = fileargv[i]; if (infilelist(file) == NO) { if (vpaccess(file, READ) == 0) { addsrcfile(file); } else { (void) fprintf(stderr, "cscope: cannot find file %s\n", file); errorsfound = YES; } } } return; } /* see if a file name file exists */ if (namefile == NULL && vpaccess(NAMEFILE, READ) == 0) { namefile = NAMEFILE; } /* if there is a file of source file names */ if (namefile != NULL) { if ((names = vpfopen(namefile, "r")) == NULL) { cannotopen(namefile); myexit(1); } /* get the names in the file */ while (fscanf(names, "%s", path) == 1) { if (*path == '-') { /* if an option */ i = path[1]; switch (i) { case 'q': /* quick search */ invertedindex = YES; break; case 'T': /* truncate symbols to 8 characters */ truncatesyms = YES; break; case 'I': /* #include file directory */ case 'p': /* file path components to */ /* display */ s = path + 2; /* for "-Ipath" */ if (*s == '\0') { /* if "-I path" */ (void) fscanf(names, "%s", path); s = path; } switch (i) { case 'I': /* #include file directory */ if (firstbuild == YES) { /* expand $ and ~ */ shellpath(dir, sizeof (dir), s); includedir(dir); } break; case 'p': /* file path components */ /* to display */ if (*s < '0' || *s > '9') { (void) fprintf(stderr, "cscope: -p option " "in file %s: " "missing or " "invalid numeric " "value\n", namefile); } dispcomponents = atoi(s); break; } break; default: (void) fprintf(stderr, "cscope: only -I, -p, and -T " "options can be in file %s\n", namefile); } } else if (vpaccess(path, READ) == 0) { addsrcfile(path); } else { (void) fprintf(stderr, "cscope: cannot find file %s\n", path); errorsfound = YES; } } (void) fclose(names); firstbuild = NO; return; } /* make a list of all the source files in the directories */ for (i = 0; i < nsrcdirs; ++i) { s = srcdirs[i]; getsrcfiles(s, s); if (*s != '/') { /* if it isn't a full path name */ /* compute its path from any higher view path nodes */ for (j = 1; j < vpndirs; ++j) { (void) sprintf(dir, "%s/%s", vpdirs[j], s); /* make sure it is a directory */ if (stat(compath(dir), &statstruct) == 0 && S_ISDIR(statstruct.st_mode)) { getsrcfiles(dir, s); } } } } }
int main(int argc, char **argv) { int envc; /* environment argument count */ char **envv; /* environment argument list */ FILE *names; /* name file pointer */ int oldnum; /* number in old cross-ref */ char path[PATHLEN + 1]; /* file path */ FILE *oldrefs; /* old cross-reference file */ char *s; int c, i; pid_t pid; /* save the command name for messages */ argv0 = basename(argv[0]); /* get the current directory for build() and line-oriented P command */ if (mygetwd(currentdir) == NULL) { (void) fprintf(stderr, "cscope: warning: cannot get current directory name\n"); (void) strcpy(currentdir, "<unknown>"); } /* initialize any view path; (saves time since currendir is known) */ vpinit(currentdir); dbvpndirs = vpndirs; /* number of directories in database view path */ /* directories (including current) in database view path */ dbvpdirs = vpdirs; /* the first source directory is the current directory */ sourcedir("."); /* read the environment */ editor = mygetenv("EDITOR", EDITOR); editor = mygetenv("VIEWER", editor); /* use viewer if set */ home = getenv("HOME"); shell = mygetenv("SHELL", SHELL); tmpdir = mygetenv("TMPDIR", TMPDIR); /* increment nesting depth */ cscopedepth = atoi(mygetenv("CSCOPEDEPTH", "0")); (void) sprintf(path, "CSCOPEDEPTH=%d", ++cscopedepth); (void) putenv(stralloc(path)); if ((s = getenv("CSCOPEOPTIONS")) != NULL) { /* parse the environment option string */ envc = 1; envv = mymalloc(sizeof (char *)); s = strtok(stralloc(s), OPTSEPS); while (s != NULL) { envv = myrealloc(envv, ++envc * sizeof (char *)); envv[envc - 1] = stralloc(s); s = strtok((char *)NULL, OPTSEPS); } /* set the environment options */ options(envc, envv); } /* set the command line options */ options(argc, argv); /* create the temporary file names */ pid = getpid(); (void) sprintf(temp1, "%s/cscope%d.1", tmpdir, (int)pid); (void) sprintf(temp2, "%s/cscope%d.2", tmpdir, (int)pid); /* if running in the foreground */ if (signal(SIGINT, SIG_IGN) != SIG_IGN) { /* cleanup on the interrupt and quit signals */ (void) signal(SIGINT, myexit); (void) signal(SIGQUIT, myexit); } /* cleanup on the hangup signal */ (void) signal(SIGHUP, myexit); /* if the database path is relative and it can't be created */ if (reffile[0] != '/' && access(".", WRITE) != 0) { /* if the database may not be up-to-date or can't be read */ (void) sprintf(path, "%s/%s", home, reffile); if (isuptodate == NO || access(reffile, READ) != 0) { /* put it in the home directory */ reffile = stralloc(path); (void) sprintf(path, "%s/%s", home, invname); invname = stralloc(path); (void) sprintf(path, "%s/%s", home, invpost); invpost = stralloc(path); (void) fprintf(stderr, "cscope: symbol database will be %s\n", reffile); } } /* if the cross-reference is to be considered up-to-date */ if (isuptodate == YES) { if ((oldrefs = vpfopen(reffile, "r")) == NULL) { cannotopen(reffile); exit(1); } /* * get the crossref file version but skip the current * directory */ if (fscanf(oldrefs, "cscope %d %*s", &fileversion) != 1) { (void) fprintf(stderr, "cscope: cannot read file version from file %s\n", reffile); exit(1); } if (fileversion >= 8) { /* override these command line options */ compress = YES; invertedindex = NO; /* see if there are options in the database */ for (;;) { /* no -q leaves multiple blanks */ while ((c = getc(oldrefs)) == ' ') { ; } if (c != '-') { (void) ungetc(c, oldrefs); break; } switch (c = getc(oldrefs)) { case 'c': /* ASCII characters only */ compress = NO; break; case 'q': /* quick search */ invertedindex = YES; (void) fscanf(oldrefs, "%ld", &totalterms); break; case 'T': /* truncate symbols to 8 characters */ dbtruncated = YES; truncatesyms = YES; break; } } initcompress(); /* seek to the trailer */ if (fscanf(oldrefs, "%ld", &traileroffset) != 1) { (void) fprintf(stderr, "cscope: cannot read trailer offset from " "file %s\n", reffile); exit(1); } if (fseek(oldrefs, traileroffset, 0) != 0) { (void) fprintf(stderr, "cscope: cannot seek to trailer in " "file %s\n", reffile); exit(1); } } /* * read the view path for use in converting relative paths to * full paths * * note: don't overwrite vp[n]dirs because this can cause * the wrong database index files to be found in the viewpath */ if (fileversion >= 13) { if (fscanf(oldrefs, "%d", &dbvpndirs) != 1) { (void) fprintf(stderr, "cscope: cannot read view path size from " "file %s\n", reffile); exit(1); } if (dbvpndirs > 0) { dbvpdirs = mymalloc( dbvpndirs * sizeof (char *)); for (i = 0; i < dbvpndirs; ++i) { if (fscanf(oldrefs, "%s", path) != 1) { (void) fprintf(stderr, "cscope: cannot read view " "path from file %s\n", reffile); exit(1); } dbvpdirs[i] = stralloc(path); } } } /* skip the source and include directory lists */ skiplist(oldrefs); skiplist(oldrefs); /* get the number of source files */ if (fscanf(oldrefs, "%d", &nsrcfiles) != 1) { (void) fprintf(stderr, "cscope: cannot read source file size from " "file %s\n", reffile); exit(1); } /* get the source file list */ srcfiles = mymalloc(nsrcfiles * sizeof (char *)); if (fileversion >= 9) { /* allocate the string space */ if (fscanf(oldrefs, "%d", &oldnum) != 1) { (void) fprintf(stderr, "cscope: cannot read string space size " "from file %s\n", reffile); exit(1); } s = mymalloc(oldnum); (void) getc(oldrefs); /* skip the newline */ /* read the strings */ if (fread(s, oldnum, 1, oldrefs) != 1) { (void) fprintf(stderr, "cscope: cannot read source file names " "from file %s\n", reffile); exit(1); } /* change newlines to nulls */ for (i = 0; i < nsrcfiles; ++i) { srcfiles[i] = s; for (++s; *s != '\n'; ++s) { ; } *s = '\0'; ++s; } /* if there is a file of source file names */ if (namefile != NULL && (names = vpfopen(namefile, "r")) != NULL || (names = vpfopen(NAMEFILE, "r")) != NULL) { /* read any -p option from it */ while (fscanf(names, "%s", path) == 1 && *path == '-') { i = path[1]; s = path + 2; /* for "-Ipath" */ if (*s == '\0') { /* if "-I path" */ (void) fscanf(names, "%s", path); s = path; } switch (i) { case 'p': /* file path components */ /* to display */ if (*s < '0' || *s > '9') { (void) fprintf(stderr, "cscope: -p option " "in file %s: " "missing or " "invalid numeric " "value\n", namefile); } dispcomponents = atoi(s); } } (void) fclose(names); } } else { for (i = 0; i < nsrcfiles; ++i) { if (fscanf(oldrefs, "%s", path) != 1) { (void) fprintf(stderr, "cscope: cannot read source file " "name from file %s\n", reffile); exit(1); } srcfiles[i] = stralloc(path); } } (void) fclose(oldrefs); } else { /* get source directories from the environment */ if ((s = getenv("SOURCEDIRS")) != NULL) { sourcedir(s); } /* make the source file list */ srcfiles = mymalloc(msrcfiles * sizeof (char *)); makefilelist(); if (nsrcfiles == 0) { (void) fprintf(stderr, "cscope: no source files found\n"); printusage(); exit(1); } /* get include directories from the environment */ if ((s = getenv("INCLUDEDIRS")) != NULL) { includedir(s); } /* add /usr/include to the #include directory list */ includedir("/usr/include"); /* initialize the C keyword table */ initsymtab(); /* create the file name(s) used for a new cross-reference */ (void) strcpy(path, reffile); s = basename(path); *s = '\0'; (void) strcat(path, "n"); ++s; (void) strcpy(s, basename(reffile)); newreffile = stralloc(path); (void) strcpy(s, basename(invname)); newinvname = stralloc(path); (void) strcpy(s, basename(invpost)); newinvpost = stralloc(path); /* build the cross-reference */ initcompress(); build(); if (buildonly == YES) { exit(0); } } opendatabase(); /* * removing a database will not release the disk space if a cscope * process has the file open, so a project may want unattended cscope * processes to exit overnight, including their subshells and editors */ if (noacttime) { (void) signal(SIGALRM, timedout); (void) alarm(noacttime); } /* * if using the line oriented user interface so cscope can be a * subprocess to emacs or samuel */ if (linemode == YES) { if (*pattern != '\0') { /* do any optional search */ if (search() == YES) { while ((c = getc(refsfound)) != EOF) { (void) putchar(c); } } } if (onesearch == YES) { myexit(0); } for (;;) { char buf[PATLEN + 2]; if (noacttime) { (void) alarm(noacttime); } (void) printf(">> "); (void) fflush(stdout); if (fgets(buf, sizeof (buf), stdin) == NULL) { myexit(0); } /* remove any trailing newline character */ if (*(s = buf + strlen(buf) - 1) == '\n') { *s = '\0'; } switch (*buf) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* samuel only */ field = *buf - '0'; (void) strcpy(pattern, buf + 1); (void) search(); (void) printf("cscope: %d lines\n", totallines); while ((c = getc(refsfound)) != EOF) { (void) putchar(c); } break; case 'c': /* toggle caseless mode */ case ctrl('C'): if (caseless == NO) { caseless = YES; } else { caseless = NO; } egrepcaseless(caseless); break; case 'r': /* rebuild database cscope style */ case ctrl('R'): freefilelist(); makefilelist(); /* FALLTHROUGH */ case 'R': /* rebuild database samuel style */ rebuild(); (void) putchar('\n'); break; case 'C': /* clear file names */ freefilelist(); (void) putchar('\n'); break; case 'F': /* add a file name */ (void) strcpy(path, buf + 1); if (infilelist(path) == NO && vpaccess(path, READ) == 0) { addsrcfile(path); } (void) putchar('\n'); break; case 'P': /* print the path to the files */ if (prependpath != NULL) { (void) puts(prependpath); } else { (void) puts(currentdir); } break; case 'q': /* quit */ case ctrl('D'): case ctrl('Z'): myexit(0); default: (void) fprintf(stderr, "cscope: unknown command '%s'\n", buf); break; } } /* NOTREACHED */ } /* pause before clearing the screen if there have been error messages */ if (errorsfound == YES) { errorsfound = NO; askforreturn(); } (void) signal(SIGINT, SIG_IGN); /* ignore interrupts */ (void) signal(SIGPIPE, SIG_IGN); /* | command can cause pipe signal */ /* initialize the curses display package */ (void) initscr(); /* initialize the screen */ setfield(); /* set the initial cursor position */ entercurses(); (void) keypad(stdscr, TRUE); /* enable the keypad */ dispinit(); /* initialize display parameters */ putmsg(""); /* clear any build progress message */ display(); /* display the version number and input fields */ /* do any optional search */ if (*pattern != '\0') { atfield(); /* move to the input field */ (void) command(ctrl('A')); /* search */ display(); /* update the display */ } else if (reflines != NULL) { /* read any symbol reference lines file */ (void) readrefs(reflines); display(); /* update the display */ } for (;;) { if (noacttime) { (void) alarm(noacttime); } atfield(); /* move to the input field */ /* exit if the quit command is entered */ if ((c = mygetch()) == EOF || c == ctrl('D') || c == ctrl('Z')) { break; } /* execute the commmand, updating the display if necessary */ if (command(c) == YES) { display(); } } /* cleanup and exit */ myexit(0); /* NOTREACHED */ return (0); }