#include <unistd.h>
#include <stdio.h>
#include <libgen.h>
#include "global.h"
#include "vp.h"
char block[BUFSIZ + 2];
int blocklen;
char blockmark;
long blocknumber;
char *blockp;
char lastfilepath[PATHLEN + 1];
static char cpattern[PATLEN + 1];
static long lastfcnoffset;
static long postingsfound;
static char *regexp;
static POSTING *postingp;
static long searchcount;
static long starttime;
static POSTING *getposting(void);
static void putsource(FILE *output);
static void putref(char *file, char *function);
static void findcalledbysub(char *file);
static void findterm(void);
static void fileprogress(void);
static void putpostingref(POSTING *p);
static void putline(FILE *output);
static char *strtolower(char *s);
static char *filepath(char *file);
void
findsymbol(void)
{
char file[PATHLEN + 1];
char function[PATLEN + 1];
char macro[PATLEN + 1];
char symbol[PATLEN + 1];
char *cp;
char c;
char *s;
if (invertedindex == YES) {
long lastline = 0;
POSTING *p;
findterm();
while ((p = getposting()) != NULL) {
if (p->type != INCLUDE && p->lineoffset != lastline) {
putpostingref(p);
lastline = p->lineoffset;
}
}
return;
}
(void) scanpast('\t');
skiprefchar();
getstring(file);
*function = '\0';
*macro = '\0';
cp = blockp;
for (;;) {
setmark('\n');
do {
while (*cp != '\n') {
++cp;
}
} while (*(cp + 1) == '\0' && (cp = readblock()) != NULL);
if (cp != NULL && *(++cp + 1) == '\0') {
cp = readblock();
}
if (cp == NULL) {
break;
}
if (*cp == '\t') {
blockp = cp;
switch (getrefchar()) {
case NEWFILE:
skiprefchar();
getstring(file);
if (*file == '\0') {
return;
}
fileprogress();
case FCNEND:
*function = '\0';
goto notmatched;
case FCNDEF:
s = function;
break;
case DEFINE:
if (fileversion >= 10) {
s = macro;
} else {
s = symbol;
}
break;
case DEFINEEND:
*macro = '\0';
goto notmatched;
case INCLUDE:
goto notmatched;
default:
s = symbol;
}
skiprefchar();
getstring(s);
if (regexp != NULL) {
if (caseless == YES) {
s = strtolower(s);
}
if (*s != '\0' && regex(regexp, s) != NULL) {
goto matched;
}
}
else if (strequal(pattern, s)) {
goto matched;
}
goto notmatched;
}
if (regexp != NULL) {
c = *cp;
if (c & 0200) {
c = dichar1[(c & 0177) / 8];
}
if (isalpha(c) || c == '_') {
blockp = cp;
getstring(symbol);
s = symbol;
if (caseless == YES) {
s = strtolower(s);
}
if (regex(regexp, s) != NULL) {
goto matched;
}
goto notmatched;
}
}
else if (*cp == cpattern[0]) {
blockp = cp;
if (matchrest()) {
s = NULL;
matched:
if (*macro != '\0' && s != macro) {
putref(file, macro);
} else if (s != function) {
putref(file, function);
} else {
putref(file, "");
}
if (blockp == NULL) {
return;
}
}
notmatched:
cp = blockp;
}
}
blockp = cp;
}
void
finddef(void)
{
char file[PATHLEN + 1];
char function[PATLEN + 1];
char macro[PATLEN + 1];
char symbol[PATLEN + 1];
char *s;
if (invertedindex == YES) {
POSTING *p;
findterm();
while ((p = getposting()) != NULL) {
switch (p->type) {
case DEFINE:
case FCNDEF:
case CLASSDEF:
case ENUMDEF:
case MEMBERDEF:
case STRUCTDEF:
case TYPEDEF:
case UNIONDEF:
case GLOBALDEF:
case LOCALDEF:
case PARAMETER:
putpostingref(p);
}
}
return;
}
*function = '\0';
*macro = '\0';
while (scanpast('\t') != NULL) {
switch (*blockp) {
case NEWFILE:
skiprefchar();
getstring(file);
if (*file == '\0') {
return;
}
fileprogress();
case FCNEND:
*function = '\0';
break;
case FCNDEF:
s = function;
goto def;
case DEFINE:
if (fileversion >= 10) {
s = macro;
} else {
s = symbol;
}
goto def;
case DEFINEEND:
*macro = '\0';
break;
case CLASSDEF:
case ENUMDEF:
case MEMBERDEF:
case STRUCTDEF:
case TYPEDEF:
case UNIONDEF:
case GLOBALDEF:
case LOCALDEF:
case PARAMETER:
s = symbol;
def:
skiprefchar();
getstring(s);
if (regexp != NULL) {
if (caseless == YES) {
s = strtolower(s);
}
if (*s != '\0' && regex(regexp, s) != NULL) {
goto matched;
}
} else if (strequal(pattern, s)) {
matched:
if (*macro != '\0' && s != macro) {
putref(file, macro);
} else if (s != function) {
putref(file, function);
} else {
putref(file, "");
}
}
}
}
}
void
findallfcns(void)
{
char file[PATHLEN + 1];
char function[PATLEN + 1];
while (scanpast('\t') != NULL) {
switch (*blockp) {
case NEWFILE:
skiprefchar();
getstring(file);
if (*file == '\0') {
return;
}
fileprogress();
break;
case FCNDEF:
case CLASSDEF:
skiprefchar();
getstring(function);
putref(file, function);
break;
}
}
}
void
findcalledby(void)
{
char file[PATHLEN + 1];
if (invertedindex == YES) {
POSTING *p;
findterm();
while ((p = getposting()) != NULL) {
switch (p->type) {
case DEFINE:
case FCNDEF:
if (dbseek(p->lineoffset) != -1 &&
scanpast('\t') != NULL) {
findcalledbysub(srcfiles[p->fileindex]);
}
}
}
return;
}
while (scanpast('\t') != NULL) {
switch (*blockp) {
case NEWFILE:
skiprefchar();
getstring(file);
if (*file == '\0') {
return;
}
fileprogress();
break;
case DEFINE:
if (fileversion < 10) {
break;
}
case FCNDEF:
skiprefchar();
if (match()) {
findcalledbysub(file);
}
break;
}
}
}
static void
findcalledbysub(char *file)
{
while (scanpast('\t') != NULL) {
switch (*blockp) {
case DEFINE:
if (fileversion >= 10) {
while (scanpast('\t') != NULL &&
*blockp != DEFINEEND)
;
}
break;
case FCNCALL:
(void) fprintf(refsfound, "%s ", filepath(file));
skiprefchar();
putline(refsfound);
(void) putc(' ', refsfound);
putsource(refsfound);
break;
case DEFINEEND:
case FCNEND:
case FCNDEF:
case NEWFILE:
return;
}
}
}
void
findcalling(void)
{
char file[PATHLEN + 1];
char function[PATLEN + 1];
char macro[PATLEN + 1];
if (invertedindex == YES) {
POSTING *p;
findterm();
while ((p = getposting()) != NULL) {
if (p->type == FCNCALL) {
putpostingref(p);
}
}
return;
}
*macro = '\0';
while (scanpast('\t') != NULL) {
switch (*blockp) {
case NEWFILE:
skiprefchar();
getstring(file);
if (*file == '\0') {
return;
}
fileprogress();
case FCNEND:
*function = '\0';
break;
case DEFINE:
if (fileversion >= 10) {
skiprefchar();
getstring(macro);
}
break;
case DEFINEEND:
*macro = '\0';
break;
case FCNDEF:
skiprefchar();
getstring(function);
break;
case FCNCALL:
skiprefchar();
if (match()) {
if (*macro != '\0') {
putref(file, macro);
} else {
putref(file, function);
}
}
}
}
}
void
findassignments(void)
{
char file[PATHLEN + 1];
char function[PATLEN + 1];
char macro[PATLEN + 1];
if (fileversion < 13) {
putmsg("Database built with cscope version < 13 does not "
"have assignment information");
(void) sleep(3);
return;
}
#if CTRACE
ctroff();
#endif
if (invertedindex == YES) {
POSTING *p;
findterm();
while ((p = getposting()) != NULL) {
switch (p->type) {
case ASSIGNMENT:
case GLOBALDEF:
case LOCALDEF:
case PARAMETER:
putpostingref(p);
}
}
return;
}
*macro = '\0';
while (scanpast('\t') != NULL) {
switch (*blockp) {
case NEWFILE:
skiprefchar();
getstring(file);
if (*file == '\0') {
return;
}
fileprogress();
case FCNEND:
*function = '\0';
break;
case DEFINE:
if (fileversion >= 10) {
skiprefchar();
getstring(macro);
}
break;
case DEFINEEND:
*macro = '\0';
break;
case FCNDEF:
skiprefchar();
getstring(function);
break;
case ASSIGNMENT:
case GLOBALDEF:
case LOCALDEF:
case PARAMETER:
skiprefchar();
if (match()) {
if (*macro != '\0') {
putref(file, macro);
} else {
putref(file, function);
}
}
}
}
}
char *
findgreppat(void)
{
char egreppat[2 * PATLEN];
char *cp, *pp;
cp = egreppat;
for (pp = pattern; *pp != '\0'; ++pp) {
if (strchr("+?|()", *pp) != NULL) {
*cp++ = '\\';
}
*cp++ = *pp;
}
*cp = '\0';
return (findegreppat(egreppat));
}
char *
findegreppat(char *egreppat)
{
int i;
char *egreperror;
char msg[MSGLEN + 1];
if ((egreperror = egrepinit(egreppat)) == NULL) {
for (i = 0; i < nsrcfiles; ++i) {
char *file = filepath(srcfiles[i]);
fileprogress();
if (egrep(file, refsfound, "%s <unknown> %ld ") < 0) {
(void) sprintf(msg, "Cannot open file %s",
file);
putmsg2(msg);
}
}
}
return (egreperror);
}
void
findfile(void)
{
int i;
char *s;
for (i = 0; i < nsrcfiles; ++i) {
s = srcfiles[i];
if (caseless == YES) {
s = strtolower(s);
}
if (regex(regexp, s) != NULL) {
(void) fprintf(refsfound, "%s <unknown> 1 <unknown>\n",
filepath(srcfiles[i]));
}
}
}
void
findinclude(void)
{
char file[PATHLEN + 1];
if (invertedindex == YES) {
POSTING *p;
findterm();
while ((p = getposting()) != NULL) {
if (p->type == INCLUDE) {
putpostingref(p);
}
}
return;
}
while (scanpast('\t') != NULL) {
switch (*blockp) {
case NEWFILE:
skiprefchar();
getstring(file);
if (*file == '\0') {
return;
}
fileprogress();
break;
case INCLUDE:
skiprefchar();
skiprefchar();
if (match()) {
putref(file, "");
}
}
}
}
FINDINIT
findinit(void)
{
char buf[PATLEN + 3];
BOOL isregexp = NO;
int i;
char *s;
unsigned c;
for (s = pattern + strlen(pattern) - 1; isspace(*s); --s) {
*s = '\0';
}
if (field == FILENAME || field == INCLUDES) {
if (invertedindex == YES && field == INCLUDES &&
strncmp(pattern, ".*", 2) != 0) {
(void) sprintf(pattern, ".*%s", strcpy(buf, pattern));
}
if ((regexp = regcmp(pattern, (char *)NULL)) == NULL) {
return (REGCMPERROR);
}
return (NOERROR);
}
if (strpbrk(pattern, "^.[{*+$") != NULL) {
isregexp = YES;
} else {
s = pattern;
if (!isalpha(*s) && *s != '_') {
return (NOTSYMBOL);
}
while (*++s != '\0') {
if (!isalnum(*s) && *s != '_') {
return (NOTSYMBOL);
}
}
if (truncatesyms == YES && isuptodate == YES &&
dbtruncated == NO && s - pattern >= 8) {
(void) strcpy(pattern + 8, ".*");
isregexp = YES;
}
}
if (isregexp == YES || caseless == YES || invertedindex == YES) {
s = pattern;
if (*s == '^') {
(void) strcpy(newpat, s + 1);
(void) strcpy(s, newpat);
}
i = strlen(s) - 1;
if (s[i] == '$') {
s[i] = '\0';
}
if (truncatesyms == YES && strpbrk(s, "[{*+") == NULL) {
s[8] = '\0';
}
(void) sprintf(buf, "^%s$", s);
if ((regexp = regcmp(buf, (char *)NULL)) == NULL) {
return (REGCMPERROR);
}
} else {
if (truncatesyms == YES && field <= CALLING) {
pattern[8] = '\0';
}
s = cpattern;
for (i = 0; (c = pattern[i]) != '\0'; ++i) {
if (dicode1[c] && dicode2[(unsigned)pattern[i + 1]]) {
c = (0200 - 2) + dicode1[c] +
dicode2[(unsigned)pattern[i + 1]];
++i;
}
*s++ = (char)c;
}
*s = '\0';
}
return (NOERROR);
}
void
findcleanup(void)
{
if (regexp != NULL) {
free(regexp);
regexp = NULL;
}
}
static void
findterm(void)
{
char *s;
int len;
char prefix[PATLEN + 1];
char term[PATLEN + 1];
npostings = 0;
lastfcnoffset = 0;
boolclear();
(void) strcpy(prefix, pattern);
if ((s = strpbrk(prefix, ".[{*+")) != NULL) {
*s = '\0';
}
if (caseless == YES) {
s = prefix;
while (*s != '\0') {
*s = toupper(*s);
++s;
}
}
(void) invfind(&invcontrol, prefix);
if (caseless == YES) {
(void) strcpy(prefix, strtolower(prefix));
}
if (*prefix == '\0') {
(void) invforward(&invcontrol);
}
len = strlen(prefix);
do {
(void) invterm(&invcontrol, term);
s = term;
if (caseless == YES) {
s = strtolower(s);
}
if (regex(regexp, s) != NULL) {
if ((postingp = boolfile(&invcontrol,
&npostings, OR)) == NULL) {
break;
}
} else if (len > 0) {
if (caseless == YES) {
if (strncmp(term, prefix, len) > 0) {
break;
}
}
else if (strncmp(term, prefix, len) != 0) {
break;
}
}
if (++searchcount % 50 == 0) {
progress("%ld of %ld symbols matched",
searchcount, totalterms);
}
} while (invforward(&invcontrol));
initprogress();
postingsfound = npostings;
}
static void
fileprogress(void)
{
if (++searchcount % 10 == 0) {
progress("%ld of %ld files searched", searchcount,
(long)nsrcfiles);
}
}
void
initprogress(void)
{
searchcount = 0;
starttime = time((long *)NULL);
}
void
progress(char *format, long n1, long n2)
{
char msg[MSGLEN + 1];
long now;
if (linemode == NO && (now = time((long *)NULL)) - starttime >= 2) {
starttime = now;
(void) sprintf(msg, format, n1, n2);
putmsg(msg);
}
}
BOOL
match(void)
{
char string[PATLEN + 1];
char *s;
if (regexp != NULL) {
getstring(string);
if (*string == '\0') {
return (NO);
}
s = string;
if (caseless == YES) {
s = strtolower(s);
}
return (regex(regexp, s) ? YES : NO);
}
return ((BOOL)(*blockp == cpattern[0] && matchrest()));
}
BOOL
matchrest(void)
{
int i = 1;
skiprefchar();
do {
while (*blockp == cpattern[i]) {
++blockp;
++i;
}
} while (*(blockp + 1) == '\0' && readblock() != NULL);
if (*blockp == '\n' && cpattern[i] == '\0') {
return (YES);
}
return (NO);
}
static POSTING *
getposting(void)
{
if (npostings-- <= 0) {
return (NULL);
}
if (++searchcount % 100 == 0) {
progress("%ld of %ld possible references retrieved",
searchcount, postingsfound);
}
return (postingp++);
}
static void
putpostingref(POSTING *p)
{
static char function[PATLEN + 1];
if (p->fcnoffset == 0) {
*function = '\0';
} else if (p->fcnoffset != lastfcnoffset) {
if (dbseek(p->fcnoffset) != -1) {
getstring(function);
lastfcnoffset = p->fcnoffset;
}
}
if (dbseek(p->lineoffset) != -1) {
putref(srcfiles[p->fileindex], function);
}
}
static void
putref(char *file, char *function)
{
FILE *output;
if (*function == '\0') {
function = "<global>";
output = refsfound;
} else {
output = nonglobalrefs;
}
if (fprintf(output, "%s %s ", filepath(file), function) == EOF) {
cannotwrite(temp1);
}
putsource(output);
}
static void
putsource(FILE *output)
{
char *cp, nextc = '\0';
if (fileversion <= 5) {
(void) scanpast(' ');
putline(output);
(void) putc('\n', output);
return;
}
cp = blockp;
while (*cp != '\n' || nextc != '\n') {
nextc = *cp;
if (--cp < block) {
(void) dbseek((blocknumber - 1) * BUFSIZ);
cp = &block[BUFSIZ - 1];
}
}
blockp = cp;
setmark(' ');
if (*blockp != '\n' || getrefchar() != '\n' ||
!isdigit(getrefchar()) && fileversion >= 12) {
putmsg("Internal error: cannot get source line from database");
myexit(1);
}
do {
if (*blockp == '\t') {
skiprefchar();
skiprefchar();
}
putline(output);
} while (blockp != NULL && getrefchar() != '\n');
(void) putc('\n', output);
}
static void
putline(FILE *output)
{
char *cp;
unsigned c;
setmark('\n');
cp = blockp;
do {
while ((c = *cp) != '\n') {
if (c & 0200) {
c &= 0177;
(void) putc(dichar1[c / 8], output);
(void) putc(dichar2[c & 7], output);
} else if (c < ' ') {
(void) fputs(keyword[c].text, output);
if (keyword[c].delim != '\0') {
(void) putc(' ', output);
}
if (keyword[c].delim == '(') {
(void) putc('(', output);
}
} else {
(void) putc((int)c, output);
}
++cp;
}
} while (*(cp + 1) == '\0' && (cp = readblock()) != NULL);
blockp = cp;
}
void
getstring(char *s)
{
char *cp;
unsigned c;
setmark('\n');
cp = blockp;
do {
while ((c = *cp) != '\n') {
if (c & 0200) {
c &= 0177;
*s++ = dichar1[c / 8];
*s++ = dichar2[c & 7];
} else {
*s++ = (char)c;
}
++cp;
}
} while (*(cp + 1) == '\0' && (cp = readblock()) != NULL);
blockp = cp;
*s = '\0';
}
char *
scanpast(int c)
{
char *cp;
setmark(c);
cp = blockp;
do {
while (*cp != c) {
++cp;
}
} while (*(cp + 1) == '\0' && (cp = readblock()) != NULL);
blockp = cp;
if (cp != NULL) {
skiprefchar();
}
return (blockp);
}
char *
readblock(void)
{
blocklen = read(symrefs, block, BUFSIZ);
blockp = block;
block[blocklen] = blockmark;
block[blocklen + 1] = '\0';
if (blocklen == 0) {
blockp = NULL;
} else {
++blocknumber;
}
return (blockp);
}
long
dbseek(long offset)
{
long n;
int rc = 0;
if ((n = offset / BUFSIZ) != blocknumber) {
if ((rc = lseek(symrefs, n * BUFSIZ, 0)) == -1) {
myperror("Lseek failed");
(void) sleep(3);
return (rc);
}
(void) readblock();
blocknumber = n;
}
blockp = block + offset % BUFSIZ;
return (rc);
}
static char *
strtolower(char *s)
{
static char buf[PATLEN + 1];
char *lp = buf;
while (*s != '\0') {
*lp++ = tolower(*s);
++s;
}
*lp = '\0';
return (buf);
}
static char *
filepath(char *file)
{
static char path[PATHLEN + 1];
int i;
if (*file != '/') {
if (strequal(file, lastfilepath)) {
return (path);
}
(void) strcpy(lastfilepath, file);
if (prependpath != NULL) {
(void) sprintf(path, "%s/%s", prependpath, file);
return (path);
}
if (dbvpndirs > 1) {
for (i = 0; i < dbvpndirs; i++) {
(void) sprintf(path,
"%s/%s", dbvpdirs[i], file);
if (access(path, READ) != -1) {
return (path);
}
}
}
(void) strcpy(path, file);
}
return (file);
}