/* * 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 or text cross-reference * * searching functions */ #include #include #include #include "global.h" #include "vp.h" /* * most of these functions have been optimized so their innermost loops have * only one test for the desired character by putting the char and * an end-of-block marker (\0) at the end of the disk block buffer. * When the inner loop exits on the char, an outer loop will see if * the char is followed by a \0. If so, it will read the next block * and restart the inner loop. */ char block[BUFSIZ + 2]; /* leave room for end-of-block mark */ int blocklen; /* length of disk block read */ char blockmark; /* mark character to be searched for */ long blocknumber; /* block number */ char *blockp; /* pointer to current char in block */ char lastfilepath[PATHLEN + 1]; /* last file that full path was */ /* computed for */ static char cpattern[PATLEN + 1]; /* compressed pattern */ static long lastfcnoffset; /* last function name offset */ static long postingsfound; /* retrieved number of postings */ static char *regexp; /* regular expression */ static POSTING *postingp; /* retrieved posting set pointer */ static long searchcount; /* count of files searched */ static long starttime; /* start time for progress messages */ 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); /* find the symbol in the cross-reference */ void findsymbol(void) { char file[PATHLEN + 1]; /* source file name */ char function[PATLEN + 1]; /* function name */ char macro[PATLEN + 1]; /* macro name */ char symbol[PATLEN + 1]; /* symbol name */ 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'); /* find the end of the header */ skiprefchar(); /* skip the file marker */ getstring(file); /* save the file name */ *function = '\0'; /* a macro can be inside a function, but not vice versa */ *macro = '\0'; /* find the next symbol */ /* note: this code was expanded in-line for speed */ /* while (scanpast('\n') != NULL) { */ /* other macros were replaced by code using cp instead of blockp */ cp = blockp; for (;;) { setmark('\n'); do { /* innermost loop optimized to only one test */ while (*cp != '\n') { ++cp; } } while (*(cp + 1) == '\0' && (cp = readblock()) != NULL); /* skip the found character */ if (cp != NULL && *(++cp + 1) == '\0') { cp = readblock(); } if (cp == NULL) { break; } /* look for a source file or function name */ if (*cp == '\t') { blockp = cp; switch (getrefchar()) { case NEWFILE: /* file name */ /* save the name */ skiprefchar(); getstring(file); /* check for the end of the symbols */ if (*file == '\0') { return; } fileprogress(); /* FALLTHROUGH */ case FCNEND: /* function end */ *function = '\0'; goto notmatched; /* don't match name */ case FCNDEF: /* function name */ s = function; break; case DEFINE: /* could be a macro */ if (fileversion >= 10) { s = macro; } else { s = symbol; } break; case DEFINEEND: *macro = '\0'; goto notmatched; /* don't match name */ case INCLUDE: /* #include file */ goto notmatched; /* don't match name */ default: /* other symbol */ s = symbol; } /* save the name */ skiprefchar(); getstring(s); /* see if this is a regular expression pattern */ if (regexp != NULL) { if (caseless == YES) { s = strtolower(s); } if (*s != '\0' && regex(regexp, s) != NULL) { goto matched; } } /* match the symbol to the text pattern */ else if (strequal(pattern, s)) { goto matched; } goto notmatched; } /* if this is a regular expression pattern */ if (regexp != NULL) { c = *cp; if (c & 0200) { /* digraph char? */ c = dichar1[(c & 0177) / 8]; } /* if this is a symbol */ if (isalpha(c) || c == '_') { blockp = cp; getstring(symbol); s = symbol; if (caseless == YES) { s = strtolower(s); } /* match the symbol to the regular expression */ if (regex(regexp, s) != NULL) { goto matched; } goto notmatched; } } /* match the character to the text pattern */ else if (*cp == cpattern[0]) { blockp = cp; /* match the rest of the symbol to the text pattern */ if (matchrest()) { s = NULL; matched: /* * output the file, calling function or macro, * and source line */ 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; } /* find the function definition or #define */ void finddef(void) { char file[PATHLEN + 1]; /* source file name */ char function[PATLEN + 1]; /* function name */ char macro[PATLEN + 1]; /* macro name */ char symbol[PATLEN + 1]; /* symbol name */ char *s; if (invertedindex == YES) { POSTING *p; findterm(); while ((p = getposting()) != NULL) { switch (p->type) { case DEFINE: /* could be a macro */ case FCNDEF: case CLASSDEF: case ENUMDEF: case MEMBERDEF: case STRUCTDEF: case TYPEDEF: case UNIONDEF: case GLOBALDEF: /* other global definition */ case LOCALDEF: /* other local definition */ case PARAMETER: putpostingref(p); } } return; } /* find the next file name or definition */ *function = '\0'; /* a macro can be inside a function, but not vice versa */ *macro = '\0'; while (scanpast('\t') != NULL) { switch (*blockp) { case NEWFILE: skiprefchar(); /* save file name */ getstring(file); if (*file == '\0') { /* if end of symbols */ return; } fileprogress(); /* FALLTHROUGH */ case FCNEND: /* function end */ *function = '\0'; break; case FCNDEF: /* function name */ s = function; goto def; case DEFINE: /* could be a macro */ 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: /* other global definition */ case LOCALDEF: /* other local definition */ case PARAMETER: s = symbol; def: /* save the name */ skiprefchar(); getstring(s); /* see if this is a regular expression pattern */ if (regexp != NULL) { if (caseless == YES) { s = strtolower(s); } if (*s != '\0' && regex(regexp, s) != NULL) { goto matched; } } else if (strequal(pattern, s)) { /* match the symbol to the text pattern */ matched: /* * output the file, calling function or macro, * and source line */ if (*macro != '\0' && s != macro) { putref(file, macro); } else if (s != function) { putref(file, function); } else { putref(file, ""); } } } } } /* find all function definitions (used by samuel only) */ void findallfcns(void) { char file[PATHLEN + 1]; /* source file name */ char function[PATLEN + 1]; /* function name */ /* find the next file name or definition */ while (scanpast('\t') != NULL) { switch (*blockp) { case NEWFILE: skiprefchar(); /* save file name */ getstring(file); if (*file == '\0') { /* if end of symbols */ return; } fileprogress(); break; case FCNDEF: case CLASSDEF: skiprefchar(); /* save function name */ getstring(function); /* output the file, function and source line */ putref(file, function); break; } } } /* find the functions called by this function */ void findcalledby(void) { char file[PATHLEN + 1]; /* source file name */ if (invertedindex == YES) { POSTING *p; findterm(); while ((p = getposting()) != NULL) { switch (p->type) { case DEFINE: /* could be a macro */ case FCNDEF: if (dbseek(p->lineoffset) != -1 && scanpast('\t') != NULL) { /* skip def */ findcalledbysub(srcfiles[p->fileindex]); } } } return; } /* find the function definition(s) */ while (scanpast('\t') != NULL) { switch (*blockp) { case NEWFILE: skiprefchar(); /* save file name */ getstring(file); if (*file == '\0') { /* if end of symbols */ return; } fileprogress(); break; case DEFINE: /* could be a macro */ if (fileversion < 10) { break; } /* FALLTHROUGH */ case FCNDEF: skiprefchar(); /* match name to pattern */ if (match()) { findcalledbysub(file); } break; } } } static void findcalledbysub(char *file) { /* find the next function call or the end of this function */ while (scanpast('\t') != NULL) { switch (*blockp) { case DEFINE: /* #define inside a function */ if (fileversion >= 10) { /* skip it */ while (scanpast('\t') != NULL && *blockp != DEFINEEND) ; } break; case FCNCALL: /* function call */ /* output the file name */ (void) fprintf(refsfound, "%s ", filepath(file)); /* output the function name */ skiprefchar(); putline(refsfound); (void) putc(' ', refsfound); /* output the source line */ putsource(refsfound); break; case DEFINEEND: /* #define end */ case FCNEND: /* function end */ case FCNDEF: /* function end (pre 9.5) */ case NEWFILE: /* file end */ return; } } } /* find the functions calling this function */ void findcalling(void) { char file[PATHLEN + 1]; /* source file name */ char function[PATLEN + 1]; /* function name */ char macro[PATLEN + 1]; /* macro name */ if (invertedindex == YES) { POSTING *p; findterm(); while ((p = getposting()) != NULL) { if (p->type == FCNCALL) { putpostingref(p); } } return; } /* find the next file name or function definition */ /* a macro can be inside a function, but not vice versa */ *macro = '\0'; while (scanpast('\t') != NULL) { switch (*blockp) { case NEWFILE: /* save file name */ skiprefchar(); getstring(file); if (*file == '\0') { /* if end of symbols */ return; } fileprogress(); /* FALLTHROUGH */ case FCNEND: /* function end */ *function = '\0'; break; case DEFINE: /* could be a macro */ if (fileversion >= 10) { skiprefchar(); getstring(macro); } break; case DEFINEEND: *macro = '\0'; break; case FCNDEF: /* save calling function name */ skiprefchar(); getstring(function); break; case FCNCALL: /* match function called to pattern */ skiprefchar(); if (match()) { /* output the file, calling function or */ /* macro, and source */ if (*macro != '\0') { putref(file, macro); } else { putref(file, function); } } } } } /* find direct assignment to, and increment and decrement of, this variable */ void findassignments(void) { char file[PATHLEN + 1]; /* source file name */ char function[PATLEN + 1]; /* function name */ char macro[PATLEN + 1]; /* macro name */ 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: /* can have initializer */ case LOCALDEF: /* can have initializer */ case PARAMETER: /* initial value */ putpostingref(p); } } return; } /* find the next file name or function definition */ /* a macro can be inside a function, but not vice versa */ *macro = '\0'; while (scanpast('\t') != NULL) { switch (*blockp) { case NEWFILE: /* save file name */ skiprefchar(); getstring(file); if (*file == '\0') { /* if end of symbols */ return; } fileprogress(); /* FALLTHROUGH */ case FCNEND: /* function end */ *function = '\0'; break; case DEFINE: /* could be a macro */ if (fileversion >= 10) { skiprefchar(); getstring(macro); } break; case DEFINEEND: *macro = '\0'; break; case FCNDEF: /* save calling function name */ skiprefchar(); getstring(function); break; case ASSIGNMENT: /* match assignment to pattern */ case GLOBALDEF: /* can have initializer */ case LOCALDEF: /* can have initializer */ case PARAMETER: /* initial value */ skiprefchar(); if (match()) { /* output the file, calling function or */ /* macro, and source */ if (*macro != '\0') { putref(file, macro); } else { putref(file, function); } } } } } /* find the grep pattern in the source files */ char * findgreppat(void) { char egreppat[2 * PATLEN]; char *cp, *pp; /* translate egrep special characters in the regular expression */ cp = egreppat; for (pp = pattern; *pp != '\0'; ++pp) { if (strchr("+?|()", *pp) != NULL) { *cp++ = '\\'; } *cp++ = *pp; } *cp = '\0'; /* search the source files */ return (findegreppat(egreppat)); } /* find this regular expression in the source files */ char * findegreppat(char *egreppat) { int i; char *egreperror; char msg[MSGLEN + 1]; /* compile the pattern */ if ((egreperror = egrepinit(egreppat)) == NULL) { /* search the files */ for (i = 0; i < nsrcfiles; ++i) { char *file = filepath(srcfiles[i]); fileprogress(); if (egrep(file, refsfound, "%s %ld ") < 0) { (void) sprintf(msg, "Cannot open file %s", file); putmsg2(msg); } } } return (egreperror); } /* find matching file names */ 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 1 \n", filepath(srcfiles[i])); } } } /* find files #including this file */ void findinclude(void) { char file[PATHLEN + 1]; /* source file name */ if (invertedindex == YES) { POSTING *p; findterm(); while ((p = getposting()) != NULL) { if (p->type == INCLUDE) { putpostingref(p); } } return; } /* find the next file name or function definition */ while (scanpast('\t') != NULL) { switch (*blockp) { case NEWFILE: /* save file name */ skiprefchar(); getstring(file); if (*file == '\0') { /* if end of symbols */ return; } fileprogress(); break; case INCLUDE: /* match function called to pattern */ skiprefchar(); /* skip global or local #include marker */ skiprefchar(); if (match()) { /* output the file and source line */ putref(file, ""); } } } } /* initialize */ FINDINIT findinit(void) { char buf[PATLEN + 3]; BOOL isregexp = NO; int i; char *s; unsigned c; /* remove trailing white space */ for (s = pattern + strlen(pattern) - 1; isspace(*s); --s) { *s = '\0'; } /* allow a partial match for a file name */ if (field == FILENAME || field == INCLUDES) { /* allow types.h to match #include */ 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); } /* see if the pattern is a regular expression */ if (strpbrk(pattern, "^.[{*+$") != NULL) { isregexp = YES; } else { /* check for a valid C symbol */ s = pattern; if (!isalpha(*s) && *s != '_') { return (NOTSYMBOL); } while (*++s != '\0') { if (!isalnum(*s) && *s != '_') { return (NOTSYMBOL); } } /* * look for use of the -T option (truncate symbol to 8 * characters) on a database not built with -T */ if (truncatesyms == YES && isuptodate == YES && dbtruncated == NO && s - pattern >= 8) { (void) strcpy(pattern + 8, ".*"); isregexp = YES; } } /* if this is a regular expression or letter case is to be ignored */ /* or there is an inverted index */ if (isregexp == YES || caseless == YES || invertedindex == YES) { /* remove a leading ^ */ s = pattern; if (*s == '^') { (void) strcpy(newpat, s + 1); (void) strcpy(s, newpat); } /* remove a trailing $ */ i = strlen(s) - 1; if (s[i] == '$') { s[i] = '\0'; } /* if requested, try to truncate a C symbol pattern */ if (truncatesyms == YES && strpbrk(s, "[{*+") == NULL) { s[8] = '\0'; } /* must be an exact match */ /* * note: regcmp doesn't recognize ^*keypad$ as an syntax error * unless it is given as a single arg */ (void) sprintf(buf, "^%s$", s); if ((regexp = regcmp(buf, (char *)NULL)) == NULL) { return (REGCMPERROR); } } else { /* if requested, truncate a C symbol pattern */ if (truncatesyms == YES && field <= CALLING) { pattern[8] = '\0'; } /* compress the string pattern for matching */ 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) { /* discard any regular expression */ if (regexp != NULL) { free(regexp); regexp = NULL; } } /* find this term, which can be a regular expression */ static void findterm(void) { char *s; int len; char prefix[PATLEN + 1]; char term[PATLEN + 1]; npostings = 0; /* will be non-zero after database built */ lastfcnoffset = 0; /* clear the last function name found */ boolclear(); /* clear the posting set */ /* get the string prefix (if any) of the regular expression */ (void) strcpy(prefix, pattern); if ((s = strpbrk(prefix, ".[{*+")) != NULL) { *s = '\0'; } /* if letter case is to be ignored */ if (caseless == YES) { /* * convert the prefix to upper case because it is lexically * less than lower case */ s = prefix; while (*s != '\0') { *s = toupper(*s); ++s; } } /* find the term lexically >= the prefix */ (void) invfind(&invcontrol, prefix); if (caseless == YES) { /* restore lower case */ (void) strcpy(prefix, strtolower(prefix)); } /* * a null prefix matches the null term in the inverted index, * so move to the first real term */ if (*prefix == '\0') { (void) invforward(&invcontrol); } len = strlen(prefix); do { (void) invterm(&invcontrol, term); /* get the term */ s = term; if (caseless == YES) { s = strtolower(s); /* make it lower case */ } /* if it matches */ if (regex(regexp, s) != NULL) { /* add it's postings to the set */ if ((postingp = boolfile(&invcontrol, &npostings, OR)) == NULL) { break; } } else if (len > 0) { /* if there is a prefix */ /* * if ignoring letter case and the term is out of the * range of possible matches */ if (caseless == YES) { if (strncmp(term, prefix, len) > 0) { break; /* stop searching */ } } /* if using letter case and the prefix doesn't match */ else if (strncmp(term, prefix, len) != 0) { break; /* stop searching */ } } /* display progress about every three seconds */ if (++searchcount % 50 == 0) { progress("%ld of %ld symbols matched", searchcount, totalterms); } } while (invforward(&invcontrol)); /* while didn't wrap around */ /* initialize the progress message for retrieving the references */ initprogress(); postingsfound = npostings; } /* display the file search progress about every three seconds */ static void fileprogress(void) { if (++searchcount % 10 == 0) { progress("%ld of %ld files searched", searchcount, (long)nsrcfiles); } } /* initialize the progress message */ void initprogress(void) { searchcount = 0; starttime = time((long *)NULL); } /* display the progress every three seconds */ void progress(char *format, long n1, long n2) { char msg[MSGLEN + 1]; long now; /* print after 2 seconds so the average is nearer 3 seconds */ if (linemode == NO && (now = time((long *)NULL)) - starttime >= 2) { starttime = now; (void) sprintf(msg, format, n1, n2); putmsg(msg); } } /* match the pattern to the string */ BOOL match(void) { char string[PATLEN + 1]; char *s; /* see if this is a regular expression pattern */ if (regexp != NULL) { getstring(string); if (*string == '\0') { return (NO); } s = string; if (caseless == YES) { s = strtolower(s); } return (regex(regexp, s) ? YES : NO); } /* it is a string pattern */ return ((BOOL)(*blockp == cpattern[0] && matchrest())); } /* match the rest of the pattern to the name */ 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); } /* get the next posting for this term */ static POSTING * getposting(void) { if (npostings-- <= 0) { return (NULL); } /* display progress about every three seconds */ if (++searchcount % 100 == 0) { progress("%ld of %ld possible references retrieved", searchcount, postingsfound); } return (postingp++); } /* put the posting reference into the file */ static void putpostingref(POSTING *p) { static char function[PATLEN + 1]; /* function name */ 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); } } /* put the reference into the file */ static void putref(char *file, char *function) { FILE *output; /* put global references first */ if (*function == '\0') { function = ""; output = refsfound; } else { output = nonglobalrefs; } if (fprintf(output, "%s %s ", filepath(file), function) == EOF) { cannotwrite(temp1); /* NOTREACHED */ } putsource(output); } /* put the source line into the file */ static void putsource(FILE *output) { char *cp, nextc = '\0'; if (fileversion <= 5) { (void) scanpast(' '); putline(output); (void) putc('\n', output); return; } /* scan back to the beginning of the source line */ cp = blockp; while (*cp != '\n' || nextc != '\n') { nextc = *cp; if (--cp < block) { /* read the previous block */ (void) dbseek((blocknumber - 1) * BUFSIZ); cp = &block[BUFSIZ - 1]; } } /* there must be a double newline followed by a line number */ blockp = cp; setmark(' '); /* so getrefchar doesn't skip the last block char */ if (*blockp != '\n' || getrefchar() != '\n' || !isdigit(getrefchar()) && fileversion >= 12) { putmsg("Internal error: cannot get source line from database"); myexit(1); } /* until a double newline is found */ do { /* skip a symbol type */ if (*blockp == '\t') { skiprefchar(); skiprefchar(); } /* output a piece of the source line */ putline(output); } while (blockp != NULL && getrefchar() != '\n'); (void) putc('\n', output); } /* put the rest of the cross-reference line into the file */ static void putline(FILE *output) { char *cp; unsigned c; setmark('\n'); cp = blockp; do { while ((c = *cp) != '\n') { /* check for a compressed digraph */ if (c & 0200) { c &= 0177; (void) putc(dichar1[c / 8], output); (void) putc(dichar2[c & 7], output); } else if (c < ' ') { /* a compressed keyword */ (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; } /* put the rest of the cross-reference line into the string */ 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'; } /* scan past the next occurence of this character in the cross-reference */ char * scanpast(int c) { char *cp; setmark(c); cp = blockp; do { /* innermost loop optimized to only one test */ while (*cp != c) { ++cp; } } while (*(cp + 1) == '\0' && (cp = readblock()) != NULL); blockp = cp; if (cp != NULL) { skiprefchar(); /* skip the found character */ } return (blockp); } /* read a block of the cross-reference */ char * readblock(void) { /* read the next block */ blocklen = read(symrefs, block, BUFSIZ); blockp = block; /* add the search character and end-of-block mark */ block[blocklen] = blockmark; block[blocklen + 1] = '\0'; /* return NULL on end-of-file */ if (blocklen == 0) { blockp = NULL; } else { ++blocknumber; } return (blockp); } /* seek to the database offset */ 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); } /* convert the string to lower case */ static char * strtolower(char *s) { static char buf[PATLEN + 1]; char *lp = buf; while (*s != '\0') { /* * note: s in not incremented in this line because the BSD * compatibility tolower macro evaluates its argument twice */ *lp++ = tolower(*s); ++s; } *lp = '\0'; return (buf); } /* if needed, convert a relative path to a full path */ static char * filepath(char *file) { static char path[PATHLEN + 1]; int i; if (*file != '/') { /* if same file as last time, return the same path */ if (strequal(file, lastfilepath)) { return (path); } (void) strcpy(lastfilepath, file); /* if requested, prepend a path to a relative file path */ if (prependpath != NULL) { (void) sprintf(path, "%s/%s", prependpath, file); return (path); } /* * if the database was built with a view path, return a * full path so "cscope -d -f" does not have to be called * from the build directory with the same view 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); /* for lastfilepath check */ } return (file); }