/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* cscope - interactive C symbol cross-reference
*
* build cross-reference file
*/
#include "global.h"
/* convert long to a string */
#define ltobase(value) n = value; \
s = buf + (sizeof (buf) - 1); \
*s = '\0'; \
digits = 1; \
while (n >= BASE) { \
++digits; \
i = n; \
n /= BASE; \
*--s = i - n * BASE + '!'; \
} \
*--s = n + '!';
#define SYMBOLINC 20 /* symbol list size increment */
#define FREAD "r" /* fopen for reading */
long dboffset; /* new database offset */
BOOL errorsfound; /* prompt before clearing messages */
long fileindex; /* source file name index */
long lineoffset; /* source line database offset */
long npostings; /* number of postings */
int nsrcoffset; /* number of file name database offsets */
long *srcoffset; /* source file name database offsets */
int symbols; /* number of symbols */
static char *filename; /* file name for warning messages */
static long fcnoffset; /* function name database offset */
static long macrooffset; /* macro name database offset */
static int msymbols = SYMBOLINC; /* maximum number of symbols */
static struct symbol { /* symbol data */
int type; /* type */
int first; /* index of first character in text */
int last; /* index of last+1 character in text */
int length; /* symbol length */
} *symbol;
static void putcrossref(void);
void
crossref(char *srcfile)
{
int i;
int length; /* symbol length */
int token; /* current token */
/* open the source file */
if ((yyin = vpfopen(srcfile, FREAD)) == 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 (truncatesyms && length > 8 &&
token != INCLUDE && token != NEWFILE) {
length = 8;
last = first + 8;
}
/* see if the token has a symbol */
if (length == 0) {
savesymbol(token);
break;
}
/* see if the symbol is already in the list */
for (i = 0; i < symbols; ++i) {
if (length == symbol[i].length &&
strncmp(yytext + first, yytext +
symbol[i].first, length) == 0 &&
(token == IDENT ||
token == symbol[i].type)) {
first = yyleng;
break;
}
}
if (i == symbols) { /* if not already in list */
savesymbol(token);
}
break;
case NEWLINE: /* end of line containing symbols */
--yyleng; /* remove the newline */
putcrossref(); /* output the symbols and source line */
lineno = yylineno; /* save the symbol line number */
break;
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;
}
}
}
/* save the symbol in the list */
void
savesymbol(int token)
{
/* make sure there is room for the symbol */
if (symbols == msymbols) {
msymbols += SYMBOLINC;
symbol = (struct symbol *)myrealloc(symbol,
msymbols * sizeof (struct symbol));
}
/* save the symbol */
symbol[symbols].type = token;
symbol[symbols].first = first;
symbol[symbols].last = last;
symbol[symbols].length = last - first;
++symbols;
first = yyleng;
}
/* output the file name */
void
putfilename(char *srcfile)
{
/* check for file system out of space */
/* note: dbputc is not used to avoid lint complaint */
if (putc(NEWFILE, newrefs) == EOF) {
cannotwrite(newreffile);
/* NOTREACHED */
}
++dboffset;
if (invertedindex) {
srcoffset[nsrcoffset++] = dboffset;
}
dbfputs(srcfile);
fcnoffset = macrooffset = 0;
}
/* output the symbols and source line */
static void
putcrossref(void)
{
int i, j;
unsigned c;
BOOL blank = NO; /* output blank */
BOOL newline = NO; /* output newline */
int symput = 0; /* symbols output */
int type;
/* output the source line */
lineoffset = dboffset;
dbfprintf(newrefs, "%d ", lineno);
for (i = 0; i < yyleng; ++i) {
/* change a tab to a blank and compress blanks */
if ((c = yytext[i]) == ' ' || c == '\t') {
blank = YES;
}
/* look for the start of a symbol */
else if (symput < symbols && i == symbol[symput].first) {
/* check for compressed blanks */
if (blank) {
blank = NO;
if (newline) {
dbputc('\n');
}
dbputc(' ');
}
dbputc('\n'); /* symbols start on a new line */
/* output any symbol type */
if ((type = symbol[symput].type) != IDENT) {
dbputc('\t');
dbputc(type);
} else {
type = ' ';
}
/* output the symbol */
j = symbol[symput].last;
c = yytext[j];
yytext[j] = '\0';
if (invertedindex) {
putposting(yytext + i, type);
}
putstring(yytext + i);
newline = YES;
yytext[j] = (char)c;
i = j - 1;
++symput;
} else {
if (newline) {
newline = NO;
dbputc('\n');
}
/* check for compressed blanks */
if (blank) {
if (dicode2[c]) {
c = (0200 - 2) + dicode1[' '] +
dicode2[c];
} else {
dbputc(' ');
}
} else if (dicode1[c] &&
(j = dicode2[(unsigned)yytext[i + 1]]) != 0 &&
symput < symbols && i + 1 != symbol[symput].first) {
/* compress digraphs */
c = (0200 - 2) + dicode1[c] + j;
++i;
}
/*
* if the last line of the file is a '}' without a
* newline, the lex EOF code overwrites it with a 0
*/
if (c) {
dbputc((int)c);
} else {
dbputc(' ');
}
blank = NO;
/* skip compressed characters */
if (c < ' ') {
++i;
/* skip blanks before a preprocesor keyword */
/*
* note: don't use isspace() because \f and \v
* are used for keywords
*/
while ((j = yytext[i]) == ' ' || j == '\t') {
++i;
}
/* skip the rest of the keyword */
while (isalpha(yytext[i])) {
++i;
}
/* skip space after certain keywords */
if (keyword[c].delim != '\0') {
while ((j = yytext[i]) == ' ' ||
j == '\t') {
++i;
}
}
/* skip a '(' after certain keywords */
if (keyword[c].delim == '(' &&
yytext[i] == '(') {
++i;
}
--i; /* compensate for ++i in for() */
}
}
}
/* ignore trailing blanks */
dbputc('\n');
dbputc('\n');
/* output any #define end marker */
/*
* note: must not be part of #define so putsource() doesn't discard it
* so findcalledbysub() can find it and return
*/
if (symput < symbols && symbol[symput].type == DEFINEEND) {
dbputc('\t');
dbputc(DEFINEEND);
dbputc('\n');
dbputc('\n'); /* mark beginning of next source line */
macrooffset = 0;
}
symbols = 0;
}
/* output the inverted index posting */
void
putposting(char *term, int type)
{
long i, n;
char *s;
int digits; /* digits output */
long offset; /* function/macro database offset */
char buf[11]; /* number buffer */
/* get the function or macro name offset */
offset = fcnoffset;
if (macrooffset != 0) {
offset = macrooffset;
}
/* then update them to avoid negative relative name offset */
switch (type) {
case DEFINE:
macrooffset = dboffset;
break;
case DEFINEEND:
macrooffset = 0;
return; /* null term */
case FCNDEF:
fcnoffset = dboffset;
break;
case FCNEND:
fcnoffset = 0;
return; /* null term */
}
/* ignore a null term caused by a enum/struct/union without a tag */
if (*term == '\0') {
return;
}
/* skip any #include secondary type char (< or ") */
if (type == INCLUDE) {
++term;
}
/*
* output the posting, which should be as small as possible to reduce
* the temp file size and sort time
*/
(void) fputs(term, postings);
(void) putc(' ', postings);
/*
* the line offset is padded so postings for the same term will sort
* in ascending line offset order to order the references as they
* appear withing a source file
*/
ltobase(lineoffset);
for (i = PRECISION - digits; i > 0; --i) {
(void) putc('!', postings);
}
do {
(void) putc(*s, postings);
} while (*++s != '\0');
/* postings are also sorted by type */
(void) putc(type, postings);
/* function or macro name offset */
if (offset > 0) {
(void) putc(' ', postings);
ltobase(offset);
do {
(void) putc(*s, postings);
} while (*++s != '\0');
}
if (putc('\n', postings) == EOF) {
cannotwrite(temp1);
/* NOTREACHED */
}
++npostings;
}
/* put the string into the new database */
void
putstring(char *s)
{
unsigned c;
int i;
/* compress digraphs */
for (i = 0; (c = s[i]) != '\0'; ++i) {
if (dicode1[c] && dicode2[(unsigned)s[i + 1]]) {
c = (0200 - 2) + dicode1[c] +
dicode2[(unsigned)s[i + 1]];
++i;
}
dbputc((int)c);
}
}
/* print a warning message with the file name and line number */
void
warning(text)
char *text;
{
extern int yylineno;
(void) fprintf(stderr, "cscope: \"%s\", line %d: warning: %s\n",
filename, yylineno, text);
errorsfound = YES;
}