Beispiel #1
0
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);
}
Beispiel #2
0
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(&param, 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);
}
Beispiel #3
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);
}
Beispiel #4
0
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);
				}
			}
		}
	}
}
Beispiel #5
0
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);
}