📄 find.c
字号:
/* HBB 20020620: new: make sure pattern is lowercased. Curses * mode gets this right all on its own, but at least -L mode * doesn't */ if (caseless == YES) { pattern = lcasify(pattern); } /* allow a partial match for a file name */ if (field == FILENAME || field == INCLUDES) { if (regcomp (®exp, pattern, REG_EXTENDED | REG_NOSUB) != 0) { return(REGCMPERROR); } else { isregexp_valid = YES; } 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((unsigned char)*s) && *s != '_') { return(NOTSYMBOL); } while (*++s != '\0') { if (!isalnum((unsigned char)*s) && *s != '_') { return(NOTSYMBOL); } } /* look for use of the -T option (truncate symbol to 8 characters) on a database not built with -T */ if (trun_syms == 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] == '$') { if (i > 0 && s[i-1] == '\\' ) { s[i-1] = '$'; } s[i] = '\0'; } /* if requested, try to truncate a C symbol pattern */ if (trun_syms == YES && strpbrk(s, "[{*+") == NULL) { s[8] = '\0'; } /* must be an exact match */ /* note: regcomp doesn't recognize ^*keypad$ as a syntax error unless it is given as a single arg */ (void) sprintf(buf, "^%s$", s); if (regcomp (®exp, buf, REG_EXTENDED | REG_NOSUB) != 0) { return(REGCMPERROR); } else { isregexp_valid = YES; } } else { /* if requested, truncate a C symbol pattern */ if (trun_syms == YES && field <= CALLING) { pattern[8] = '\0'; } /* compress the string pattern for matching */ s = cpattern; for (i = 0; (c = pattern[i]) != '\0'; ++i) { if (IS_A_DICODE(c, pattern[i + 1])) { c = DICODE_COMPRESS(c, pattern[i + 1]); ++i; } *s++ = c; } *s = '\0'; } return(NOERROR);}voidfindcleanup(void){ /* discard any regular expression */}/* match the pattern to the string */static BOOLmatch(void){ char string[PATLEN + 1]; /* see if this is a regular expression pattern */ if (isregexp_valid == YES) { putstring(string); if (*string == '\0') { return(NO); } if (caseless == YES) { return (regexec (®exp, lcasify(string), (size_t)0, NULL, 0) ? NO : YES); } else { return (regexec (®exp, string, (size_t)0, NULL, 0) ? NO : YES); } } /* it is a string pattern */ return((BOOL) (*blockp == cpattern[0] && matchrest()));}/* match the rest of the pattern to the name */static BOOLmatchrest(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);}/* put the reference into the file */static voidputref(int seemore, char *file, char *func){ FILE *output; if (strcmp(func, global) == 0) { output = refsfound; } else { output = nonglobalrefs; } (void) fprintf(output, "%s %s ", file, func); putsource(seemore, output);}/* put the source line into the file */static voidputsource(int seemore, FILE *output){ char *tmpblockp; char *cp, nextc = '\0'; BOOL Change = NO, retreat = NO; if (fileversion <= 5) { (void) scanpast(' '); putline(output); (void) putc('\n', output); return; } /* scan back to the beginning of the source line */ cp = tmpblockp = blockp; while (*cp != '\n' || nextc != '\n') { nextc = *cp; if (--cp < block) { retreat = YES; /* read the previous block */ (void) dbseek((blocknumber - 1) * BUFSIZ); cp = &block[BUFSIZ - 1]; } } blockp = cp; if (*blockp != '\n' || getrefchar() != '\n' || (!isdigit(getrefchar()) && fileversion >= 12)) { postmsg("Internal error: cannot get source line from database"); myexit(1); } /* until a double newline is found */ do { /* skip a symbol type */ if (*blockp == '\t') { /* if retreat == YES, that means tmpblockp and blockp * point to different blocks. Offset comparison should * NOT be performed until they point to the same block. */ if (seemore && Change == NO && retreat == NO && blockp > tmpblockp) { Change = YES; cp = blockp; } skiprefchar(); skiprefchar(); } /* output a piece of the source line */ putline(output); if (retreat == YES) retreat = NO; } while (blockp != NULL && getrefchar() != '\n'); (void) putc('\n', output); if (Change == YES) blockp = cp;}/* put the rest of the cross-reference line into the file */static voidputline(FILE *output){ char *cp; unsigned c; setmark('\n'); cp = blockp; do { while ((c = (unsigned)(*cp)) != '\n') { /* check for a compressed digraph */ if (c > '\177') { c &= 0177; (void) putc(dichar1[c / 8], output); (void) putc(dichar2[c & 7], output); } /* check for a compressed keyword */ 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;}/* put the rest of the cross-reference line into the string */voidputstring(char *s){ char *cp; unsigned c; setmark('\n'); cp = blockp; do { while ((c = (unsigned)(*cp)) != '\n') { if (c > '\177') { c &= 0177; *s++ = dichar1[c / 8]; *s++ = dichar2[c & 7]; } else { *s++ = 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(char 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);}static char *lcasify(char *s){ static char ls[PATLEN+1]; /* largest possible match string */ char *lptr = ls; while(*s) { *lptr = tolower((unsigned char)*s); lptr++; s++; } *lptr = '\0'; return(ls);}/* find the functions called by this function *//* HBB 2000/05/05: for consitency of calling interface between the * different 'find...()' functions, this now returns a char pointer, * too. Implemented as a pointer to static storage containing 'y' or * 'n', for the boolean result values YES and NO */char *findcalledby(char *pattern){ char file[PATHLEN + 1]; /* source file name */ static char found_caller = 'n'; /* seen calling function? */ BOOL macro = NO; if (invertedindex == YES) { POSTING *p; findterm(pattern); 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 */ found_caller = 'y'; findcalledbysub(srcfiles[p->fileindex], macro); } } } return(&found_caller); } /* find the function definition(s) */ while (scanpast('\t') != NULL) { switch (*blockp) { case NEWFILE: skiprefchar(); /* save file name */ putstring(file); if (*file == '\0') { /* if end of symbols */ return(&found_caller); } progress("Search", searchcount, nsrcfiles); break; case DEFINE: /* could be a macro */ if (fileversion < 10) { break; } macro = YES; /* FALLTHROUGH */ case FCNDEF: skiprefchar(); /* match name to pattern */ if (match()) { found_caller = 'y'; findcalledbysub(file, macro); } break; } } return (&found_caller);}/* find this term, which can be a regular expression */static voidfindterm(char *pattern){ 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((unsigned char)*s); ++s; } } /* find the term lexically >= the prefix */ (void) invfind(&invcontrol, prefix); if (caseless == YES) { /* restore lower case */ (void) strcpy(prefix, lcasify(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 = lcasify(s); /* make it lower case */ } /* if it matches */ if (regexec (®exp, s, (size_t)0, NULL, 0) == 0) { /* add its postings to the set */ if ((postingp = boolfile(&invcontrol, &npostings, BOOL_OR)) == NULL) { break; } } /* if there is a prefix */ else if (len > 0) { /* 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("Symbols matched", searchcount, totalterms); } } while (invforward(&invcontrol)); /* while didn't wrap around */ /* initialize the progress message for retrieving the references */ searchcount = 0; postingsfound = npostings;}/* 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("Possible references retrieved", searchcount, postingsfound); } return(postingp++);}/* put the posting reference into the file */static voidputpostingref(POSTING *p, char *pat){ static char function[PATLEN + 1]; /* function name */ if (p->fcnoffset == 0) { if (p->type == FCNDEF) { /* need to find the function name */ if (dbseek(p->lineoffset) != -1) { scanpast(FCNDEF); putstring(function); } } else if (p->type != FCNCALL) { strcpy(function, global); } } else if (p->fcnoffset != lastfcnoffset) { if (dbseek(p->fcnoffset) != -1) { putstring(function); lastfcnoffset = p->fcnoffset; } } if (dbseek(p->lineoffset) != -1) { if (pat) putref(0, srcfiles[p->fileindex], pat); else putref(0, srcfiles[p->fileindex], function); }}/* seek to the database offset */longdbseek(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 voidfindcalledbysub(char *file, BOOL macro){ /* 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 ", file); /* output the function name */ skiprefchar(); putline(refsfound); (void) putc(' ', refsfound); /* output the source line */ putsource(1, refsfound); break; case DEFINEEND: /* #define end */ if (invertedindex == NO) { if (macro == YES) { return; } break; /* inside a function */ } /* FALLTHROUGH */ case FCNDEF: /* function end (pre 9.5) */ if (invertedindex == NO) break; /* FALLTHROUGH */ case FCNEND: /* function end */ case NEWFILE: /* file end */ return; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -