1 /*===========================================================================
2 Copyright (c) 1998-2000, The Santa Cruz Operation
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 *Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
11 *Redistributions in binary form must reproduce the above copyright notice,
12 this list of conditions and the following disclaimer in the documentation
13 and/or other materials provided with the distribution.
15 *Neither name of The Santa Cruz Operation nor the names of its contributors
16 may be used to endorse or promote products derived from this software
17 without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
20 IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 =========================================================================*/
33 /* cscope - interactive C symbol or text cross-reference
41 #include "scanner.h" /* for token definitions */
44 #if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
51 static char const rcsid[] = "$Id: find.c,v 1.25 2012/06/15 11:18:11 nhorman Exp $";
53 /* most of these functions have been optimized so their innermost loops have
54 * only one test for the desired character by putting the char and
55 * an end-of-block marker (\0) at the end of the disk block buffer.
56 * When the inner loop exits on the char, an outer loop will see if
57 * the char is followed by a \0. If so, it will read the next block
58 * and restart the inner loop.
61 char *blockp; /* pointer to current char in block */
62 char block[BUFSIZ + 2]; /* leave room for end-of-block mark */
63 int blocklen; /* length of disk block read */
64 char blockmark; /* mark character to be searched for */
65 long blocknumber; /* block number */
67 static char global[] = "<global>"; /* dummy global function name */
68 static char cpattern[PATLEN + 1]; /* compressed pattern */
69 static long lastfcnoffset; /* last function name offset */
70 static POSTING *postingp; /* retrieved posting set pointer */
71 static long postingsfound; /* retrieved number of postings */
72 static regex_t regexp; /* regular expression */
73 static BOOL isregexp_valid = NO; /* regular expression status */
75 static BOOL match(void);
76 static BOOL matchrest(void);
77 static POSTING *getposting(void);
78 static char *lcasify(char *s);
79 static void findcalledbysub(char *file, BOOL macro);
80 static void findterm(char *pattern);
81 static void putline(FILE *output);
82 static char *find_symbol_or_assignment(char *pattern, BOOL assign_flag);
83 static BOOL check_for_assignment(void);
84 static void putpostingref(POSTING *p, char *pat);
85 static void putref(int seemore, char *file, char *func);
86 static void putsource(int seemore, FILE *output);
88 \f/* find the symbol in the cross-reference */
91 findsymbol(char *pattern)
93 return find_symbol_or_assignment(pattern, NO);
96 \f/* find the symbol in the cross-reference, and look for assignments */
98 findassign(char *pattern)
100 return find_symbol_or_assignment(pattern, YES);
103 \f/* Test reference whether it's an assignment to the symbol found at
104 * (global variable) 'blockp' */
106 check_for_assignment(void)
108 /* Do the extra work here to determine if this is an
109 * assignment or not. Do this by examining the next character
110 * or two in blockp */
111 char *asgn_char = blockp;
113 while (isspace((unsigned char) asgn_char[0])) {
114 /* skip any whitespace or \n */
116 if (asgn_char[0] == '\0') {
117 /* get the next block when we reach the end of
118 * the current block */
119 if (NULL == (asgn_char = read_block()))
123 /* check for digraph starting with = */
124 if ((asgn_char[0] & 0x80) && (dichar1[(asgn_char[0] & 0177)/8] == '=')) {
127 /* check for plain '=', not '==' */
128 if ((asgn_char[0] == '=') &&
129 (((asgn_char[1] != '=') && !(asgn_char[1] & 0x80)) ||
130 ((asgn_char[1] & 0x80) && (dichar1[(asgn_char[1]& 0177)/8] != '=')))) {
134 /* check for operator assignments: +=, ... ^= ? */
135 if ( ( (asgn_char[0] == '+')
136 || (asgn_char[0] == '-')
137 || (asgn_char[0] == '*')
138 || (asgn_char[0] == '/')
139 || (asgn_char[0] == '%')
140 || (asgn_char[0] == '&')
141 || (asgn_char[0] == '|')
142 || (asgn_char[0] == '^')
144 && ((asgn_char[1] == '=') || ((asgn_char[1] & 0x80) && (dichar1[(asgn_char[1] &0177)/8] == '=')))
150 /* check for two-letter operator assignments: <<= or >>= ? */
151 if ( ( (asgn_char[0] == '<')
152 || (asgn_char[0] == '>')
154 && (asgn_char[1] == asgn_char[0])
155 && ((asgn_char[2] == '=') || ((asgn_char[2] & 0x80) && (dichar1[(asgn_char[2] & 0177)/8] == '=')))
161 \f/* The actual routine that does the work for findsymbol() and
164 find_symbol_or_assignment(char *pattern, BOOL assign_flag)
166 char file[PATHLEN + 1]; /* source file name */
167 char function[PATLEN + 1]; /* function name */
168 char macro[PATLEN + 1]; /* macro name */
169 char symbol[PATLEN + 1]; /* symbol name */
173 char firstchar; /* first character of a potential symbol */
176 if ((invertedindex == YES) && (assign_flag == NO)) {
181 while ((p = getposting()) != NULL) {
182 if (p->type != INCLUDE && p->lineoffset != lastline) {
184 lastline = p->lineoffset;
190 (void) scanpast('\t'); /* find the end of the header */
191 skiprefchar(); /* skip the file marker */
192 fetch_string_from_dbase(file, sizeof(file));
193 strcpy(function, global); /* set the dummy global function name */
194 strcpy(macro, global); /* set the dummy global macro name */
196 /* find the next symbol */
197 /* note: this code was expanded in-line for speed */
198 /* other macros were replaced by code using cp instead of blockp */
202 do { /* innermost loop optimized to only one test */
203 while (*cp != '\n') {
206 } while (*(cp + 1) == '\0' && (cp = read_block()) != NULL);
208 /* skip the found character */
209 if (cp != NULL && *(++cp + 1) == '\0') {
215 /* look for a source file, function, or macro name */
218 switch (getrefchar()) {
220 case NEWFILE: /* file name */
224 fetch_string_from_dbase(file, sizeof(file));
226 /* check for the end of the symbols */
230 progress("Search", searchcount, nsrcfiles);
233 case FCNEND: /* function end */
234 (void) strcpy(function, global);
235 goto notmatched; /* don't match name */
237 case FCNDEF: /* function name */
240 s_len = sizeof(function);
243 case DEFINE: /* macro name */
244 if (fileversion >= 10) {
246 s_len = sizeof(macro);
249 s_len = sizeof(symbol);
253 case DEFINEEND: /* macro end */
254 (void) strcpy(macro, global);
257 case INCLUDE: /* #include file */
258 goto notmatched; /* don't match name */
260 default: /* other symbol */
262 s_len = sizeof(symbol);
266 fetch_string_from_dbase(s, s_len);
268 /* see if this is a regular expression pattern */
269 if (isregexp_valid == YES) {
270 if (caseless == YES) {
273 if (*s != '\0' && regexec (®exp, s, (size_t)0, NULL, 0) == 0) {
277 /* match the symbol to the text pattern */
278 else if (strequal(pattern, s)) {
283 /* if this is a regular expression pattern */
284 if (isregexp_valid == YES) {
286 /* if this is a symbol */
288 /**************************************************
289 * The first character may be a digraph'ed char, so
290 * unpack it into firstchar, and then test that.
292 * Assume that all digraphed chars have the 8th bit
294 **************************************************/
295 if (*cp & 0200) { /* digraph char? */
296 firstchar = dichar1[(*cp & 0177) / 8];
302 if (isalpha((unsigned char)firstchar) || firstchar == '_') {
304 fetch_string_from_dbase(symbol, sizeof(symbol));
305 if (caseless == YES) {
306 s = lcasify(symbol); /* point to lower case version */
312 /* match the symbol to the regular expression */
313 if (*s != '\0' && regexec (®exp, s, (size_t)0, NULL, 0) == 0) {
319 /* match the character to the text pattern */
320 else if (*cp == cpattern[0]) {
323 /* match the rest of the symbol to the text pattern */
327 /* if the assignment flag is set then
328 * we are looking for assignments and
329 * some extra filtering is needed */
330 if(assign_flag == YES
331 && ! check_for_assignment())
335 /* output the file, function or macro, and source line */
336 if (strcmp(macro, global) && s != macro) {
337 putref(0, file, macro);
339 else if (fcndef == YES || s != function) {
341 putref(0, file, function);
344 putref(0, file, global);
348 if (blockp == NULL) {
359 \f/* find the function definition or #define */
362 finddef(char *pattern)
364 char file[PATHLEN + 1]; /* source file name */
366 if (invertedindex == YES) {
370 while ((p = getposting()) != NULL) {
372 case DEFINE:/* could be a macro */
380 case GLOBALDEF:/* other global definition */
381 putpostingref(p, pattern);
388 /* find the next file name or definition */
389 while (scanpast('\t') != NULL) {
393 skiprefchar(); /* save file name */
394 fetch_string_from_dbase(file, sizeof(file));
395 if (*file == '\0') { /* if end of symbols */
398 progress("Search", searchcount, nsrcfiles);
401 case DEFINE: /* could be a macro */
409 case GLOBALDEF: /* other global definition */
410 skiprefchar(); /* match name to pattern */
413 /* output the file, function and source line */
414 putref(0, file, pattern);
422 \f/* find all function definitions (used by samuel only) */
425 findallfcns(char *dummy)
427 char file[PATHLEN + 1]; /* source file name */
428 char function[PATLEN + 1]; /* function name */
430 (void) dummy; /* unused argument */
432 /* find the next file name or definition */
433 while (scanpast('\t') != NULL) {
437 skiprefchar(); /* save file name */
438 fetch_string_from_dbase(file, sizeof(file));
439 if (*file == '\0') { /* if end of symbols */
442 progress("Search", searchcount, nsrcfiles);
445 case FCNEND: /* function end */
446 (void) strcpy(function, global);
451 skiprefchar(); /* save function name */
452 fetch_string_from_dbase(function, sizeof(function));
454 /* output the file, function and source line */
455 putref(0, file, function);
462 \f/* find the functions calling this function */
465 findcalling(char *pattern)
467 char file[PATHLEN + 1]; /* source file name */
468 char function[PATLEN + 1]; /* function name */
469 char tmpfunc[10][PATLEN + 1];/* 10 temporary function names */
470 char macro[PATLEN + 1]; /* macro name */
474 if (invertedindex == YES) {
478 while ((p = getposting()) != NULL) {
479 if (p->type == FCNCALL) {
485 /* find the next file name or function definition */
486 *macro = '\0'; /* a macro can be inside a function, but not vice versa */
488 morefuns = 0; /* one function definition is normal case */
489 for (i = 0; i < 10; i++) *(tmpfunc[i]) = '\0';
490 while (scanpast('\t') != NULL) {
493 case NEWFILE: /* save file name */
495 fetch_string_from_dbase(file, sizeof(file));
496 if (*file == '\0') { /* if end of symbols */
499 progress("Search", searchcount, nsrcfiles);
500 (void) strcpy(function, global);
503 case DEFINE: /* could be a macro */
504 if (fileversion >= 10) {
506 fetch_string_from_dbase(macro, sizeof(macro));
514 case FCNDEF: /* save calling function name */
516 fetch_string_from_dbase(function, sizeof(function));
517 for (i = 0; i < morefuns; i++)
518 if ( !strcmp(tmpfunc[i], function) )
521 (void) strcpy(tmpfunc[morefuns], function);
522 if (++morefuns >= 10) morefuns = 9;
527 for (i = 0; i < morefuns; i++)
528 *(tmpfunc[i]) = '\0';
532 case FCNCALL: /* match function called to pattern */
536 /* output the file, calling function or macro, and source */
537 if (*macro != '\0') {
538 putref(1, file, macro);
542 for (i = 0; i < morefuns; i++) {
544 putref(1, file, tmpfunc[i]);
554 /* find the text in the source files */
557 findstring(char *pattern)
559 char egreppat[2 * PATLEN];
562 /* translate special characters in the regular expression */
564 for (pp = pattern; *pp != '\0'; ++pp) {
565 if (strchr(".*[\\^$+?|()", *pp) != NULL) {
572 /* search the source files */
573 return(findregexp(egreppat));
576 /* find this regular expression in the source files */
579 findregexp(char *egreppat)
584 /* compile the pattern */
585 if ((egreperror = egrepinit(egreppat)) == NULL) {
587 /* search the files */
588 for (i = 0; i < nsrcfiles; ++i) {
589 char *file = filepath(srcfiles[i]);
591 progress("Search", searchcount, nsrcfiles);
592 if (egrep(file, refsfound, "%s <unknown> %ld ") < 0) {
593 posterr ("Cannot open file %s", file);
600 /* find matching file names */
603 findfile(char *dummy)
607 (void) dummy; /* unused argument */
609 for (i = 0; i < nsrcfiles; ++i) {
612 if (caseless == YES) {
613 s = lcasify(srcfiles[i]);
617 if (regexec (®exp, s, (size_t)0, NULL, 0) == 0) {
618 (void) fprintf(refsfound, "%s <unknown> 1 <unknown>\n",
626 /* find files #including this file */
629 findinclude(char *pattern)
631 char file[PATHLEN + 1]; /* source file name */
633 if (invertedindex == YES) {
637 while ((p = getposting()) != NULL) {
638 if (p->type == INCLUDE) {
645 /* find the next file name or function definition */
646 while (scanpast('\t') != NULL) {
649 case NEWFILE: /* save file name */
651 fetch_string_from_dbase(file, sizeof(file));
652 if (*file == '\0') { /* if end of symbols */
655 progress("Search", searchcount, nsrcfiles);
658 case INCLUDE: /* match function called to pattern */
660 skiprefchar(); /* skip global or local #include marker */
663 /* output the file and source line */
664 putref(0, file, global);
675 findinit(char *pattern)
677 char buf[PATLEN + 3];
681 unsigned char c; /* HBB 20010427: changed uint to uchar */
683 /* HBB: be nice: free regexp before allocating a new one */
684 if(isregexp_valid == YES)
689 /* remove trailing white space */
690 for (s = pattern + strlen(pattern) - 1;
691 isspace((unsigned char)*s);
696 /* HBB 20020620: new: make sure pattern is lowercased. Curses
697 * mode gets this right all on its own, but at least -L mode
699 if (caseless == YES) {
700 pattern = lcasify(pattern);
703 /* allow a partial match for a file name */
704 if (field == FILENAME || field == INCLUDES) {
705 if (regcomp (®exp, pattern, REG_EXTENDED | REG_NOSUB) != 0) {
708 isregexp_valid = YES;
712 /* see if the pattern is a regular expression */
713 if (strpbrk(pattern, "^.[{*+$") != NULL) {
716 /* check for a valid C symbol */
718 if (!isalpha((unsigned char)*s) && *s != '_') {
721 while (*++s != '\0') {
722 if (!isalnum((unsigned char)*s) && *s != '_') {
726 /* look for use of the -T option (truncate symbol to 8
727 characters) on a database not built with -T */
728 if (trun_syms == YES && isuptodate == YES &&
729 dbtruncated == NO && s - pattern >= 8) {
730 (void) strcpy(pattern + 8, ".*");
734 /* if this is a regular expression or letter case is to be ignored */
735 /* or there is an inverted index */
736 if (isregexp == YES || caseless == YES || invertedindex == YES) {
738 /* remove a leading ^ */
741 (void) strcpy(newpat, s + 1);
742 (void) strcpy(s, newpat);
744 /* remove a trailing $ */
747 if (i > 0 && s[i-1] == '\\' ) {
752 /* if requested, try to truncate a C symbol pattern */
753 if (trun_syms == YES && strpbrk(s, "[{*+") == NULL) {
756 /* must be an exact match */
757 /* note: regcomp doesn't recognize ^*keypad$ as a syntax error
758 unless it is given as a single arg */
759 (void) snprintf(buf, sizeof(buf), "^%s$", s);
760 if (regcomp (®exp, buf, REG_EXTENDED | REG_NOSUB) != 0) {
765 isregexp_valid = YES;
769 /* if requested, truncate a C symbol pattern */
770 if (trun_syms == YES && field <= CALLING) {
773 /* compress the string pattern for matching */
775 for (i = 0; (c = pattern[i]) != '\0'; ++i) {
776 if (IS_A_DICODE(c, pattern[i + 1])) {
777 c = DICODE_COMPRESS(c, pattern[i + 1]);
790 /* discard any regular expression */
793 /* match the pattern to the string */
798 char string[PATLEN + 1];
800 /* see if this is a regular expression pattern */
801 if (isregexp_valid == YES) {
802 fetch_string_from_dbase(string, sizeof(string));
803 if (*string == '\0') {
806 if (caseless == YES) {
807 return (regexec (®exp, lcasify(string), (size_t)0, NULL, 0) ? NO : YES);
810 return (regexec (®exp, string, (size_t)0, NULL, 0) ? NO : YES);
813 /* it is a string pattern */
814 return((BOOL) (*blockp == cpattern[0] && matchrest()));
817 /* match the rest of the pattern to the name */
826 while (*blockp == cpattern[i]) {
830 } while (*(blockp + 1) == '\0' && read_block() != NULL);
832 if (*blockp == '\n' && cpattern[i] == '\0') {
838 /* put the reference into the file */
841 putref(int seemore, char *file, char *func)
845 if (strcmp(func, global) == 0) {
849 output = nonglobalrefs;
851 (void) fprintf(output, "%s %s ", file, func);
852 putsource(seemore, output);
855 /* put the source line into the file */
858 putsource(int seemore, FILE *output)
861 char *cp, nextc = '\0';
862 BOOL Change = NO, retreat = NO;
864 if (fileversion <= 5) {
865 (void) scanpast(' ');
867 (void) putc('\n', output);
870 /* scan back to the beginning of the source line */
871 cp = tmpblockp = blockp;
872 while (*cp != '\n' || nextc != '\n') {
876 /* read the previous block */
877 (void) dbseek((blocknumber - 1) * BUFSIZ);
878 cp = &block[BUFSIZ - 1];
882 if (*blockp != '\n' || getrefchar() != '\n' ||
883 (!isdigit(getrefchar()) && fileversion >= 12)) {
884 postfatal("Internal error: cannot get source line from database");
887 /* until a double newline is found */
889 /* skip a symbol type */
890 if (*blockp == '\t') {
891 /* if retreat == YES, that means tmpblockp and blockp
892 * point to different blocks. Offset comparison should
893 * NOT be performed until they point to the same block.
895 if (seemore && Change == NO && retreat == NO &&
896 blockp > tmpblockp) {
903 /* output a piece of the source line */
905 if (retreat == YES) retreat = NO;
906 } while (blockp != NULL && getrefchar() != '\n');
907 (void) putc('\n', output);
908 if (Change == YES) blockp = cp;
911 /* put the rest of the cross-reference line into the file */
914 putline(FILE *output)
922 while ((c = (unsigned)(*cp)) != '\n') {
924 /* check for a compressed digraph */
927 (void) putc(dichar1[c / 8], output);
928 (void) putc(dichar2[c & 7], output);
930 /* check for a compressed keyword */
932 (void) fputs(keyword[c].text, output);
933 if (keyword[c].delim != '\0') {
934 (void) putc(' ', output);
936 if (keyword[c].delim == '(') {
937 (void) putc('(', output);
941 (void) putc((int) c, output);
945 } while (*(cp + 1) == '\0' && (cp = read_block()) != NULL);
950 /* put the rest of the cross-reference line into the string */
952 fetch_string_from_dbase(char *s, size_t length)
957 assert(length > sizeof (char *));
962 while (length > 1 && (c = (unsigned int)(*cp)) != '\n') {
963 if (c >= 0x80 && length > 2) {
965 *s++ = dichar1[c / 8];
966 *s++ = dichar2[c & 7];
974 } while (length > 0 && cp[1] == '\0' && (cp = read_block()) != NULL);
980 /* scan past the next occurence of this character in the cross-reference */
988 do { /* innermost loop optimized to only one test */
992 } while (*(cp + 1) == '\0' && (cp = read_block()) != NULL);
995 skiprefchar(); /* skip the found character */
1000 /* read a block of the cross-reference */
1001 /* HBB 20040430: renamed from readblock(), to avoid name clash on QNX */
1005 /* read the next block */
1006 blocklen = read(symrefs, block, BUFSIZ);
1009 /* add the search character and end-of-block mark */
1010 block[blocklen] = blockmark;
1011 block[blocklen + 1] = '\0';
1013 /* return NULL on end-of-file */
1014 if (blocklen == 0) {
1026 static char ls[PATLEN+1]; /* largest possible match string */
1030 *lptr = tolower((unsigned char)*s);
1038 /* find the functions called by this function */
1040 /* HBB 2000/05/05: for consitency of calling interface between the
1041 * different 'find...()' functions, this now returns a char pointer,
1042 * too. Implemented as a pointer to static storage containing 'y' or
1043 * 'n', for the boolean result values YES and NO */
1046 findcalledby(char *pattern)
1048 char file[PATHLEN + 1]; /* source file name */
1049 static char found_caller = 'n'; /* seen calling function? */
1052 if (invertedindex == YES) {
1056 while ((p = getposting()) != NULL) {
1058 case DEFINE: /* could be a macro */
1060 if (dbseek(p->lineoffset) != -1 &&
1061 scanpast('\t') != NULL) { /* skip def */
1063 findcalledbysub(srcfiles[p->fileindex], macro);
1067 return(&found_caller);
1069 /* find the function definition(s) */
1070 while (scanpast('\t') != NULL) {
1074 skiprefchar(); /* save file name */
1075 fetch_string_from_dbase(file, sizeof(file));
1076 if (*file == '\0') { /* if end of symbols */
1077 return(&found_caller);
1079 progress("Search", searchcount, nsrcfiles);
1082 case DEFINE: /* could be a macro */
1083 if (fileversion < 10) {
1090 skiprefchar(); /* match name to pattern */
1093 findcalledbysub(file, macro);
1099 return (&found_caller);
1102 /* find this term, which can be a regular expression */
1105 findterm(char *pattern)
1109 char prefix[PATLEN + 1];
1110 char term[PATLEN + 1];
1112 npostings = 0; /* will be non-zero after database built */
1113 lastfcnoffset = 0; /* clear the last function name found */
1114 boolclear(); /* clear the posting set */
1116 /* get the string prefix (if any) of the regular expression */
1117 (void) strcpy(prefix, pattern);
1118 if ((s = strpbrk(prefix, ".[{*+")) != NULL) {
1121 /* if letter case is to be ignored */
1122 if (caseless == YES) {
1124 /* convert the prefix to upper case because it is lexically
1125 less than lower case */
1127 while (*s != '\0') {
1128 *s = toupper((unsigned char)*s);
1132 /* find the term lexically >= the prefix */
1133 (void) invfind(&invcontrol, prefix);
1134 if (caseless == YES) { /* restore lower case */
1135 (void) strcpy(prefix, lcasify(prefix));
1137 /* a null prefix matches the null term in the inverted index,
1138 so move to the first real term */
1139 if (*prefix == '\0') {
1140 (void) invforward(&invcontrol);
1142 len = strlen(prefix);
1144 (void) invterm(&invcontrol, term); /* get the term */
1146 if (caseless == YES) {
1147 s = lcasify(s); /* make it lower case */
1150 if (regexec (®exp, s, (size_t)0, NULL, 0) == 0) {
1152 /* add its postings to the set */
1153 if ((postingp = boolfile(&invcontrol, &npostings, BOOL_OR)) == NULL) {
1157 /* if there is a prefix */
1160 /* if ignoring letter case and the term is out of the
1161 range of possible matches */
1162 if (caseless == YES) {
1163 if (strncmp(term, prefix, len) > 0) {
1164 break; /* stop searching */
1167 /* if using letter case and the prefix doesn't match */
1168 else if (strncmp(term, prefix, len) != 0) {
1169 break; /* stop searching */
1172 /* display progress about every three seconds */
1173 if (++searchcount % 50 == 0) {
1174 progress("Symbols matched", searchcount, totalterms);
1176 } while (invforward(&invcontrol)); /* while didn't wrap around */
1178 /* initialize the progress message for retrieving the references */
1180 postingsfound = npostings;
1183 /* get the next posting for this term */
1188 if (npostings-- <= 0) {
1191 /* display progress about every three seconds */
1192 if (++searchcount % 100 == 0) {
1193 progress("Possible references retrieved", searchcount,
1199 /* put the posting reference into the file */
1202 putpostingref(POSTING *p, char *pat)
1204 static char function[PATLEN + 1]; /* function name */
1206 if (p->fcnoffset == 0) {
1207 if (p->type == FCNDEF) { /* need to find the function name */
1208 if (dbseek(p->lineoffset) != -1) {
1210 fetch_string_from_dbase(function,
1214 else if (p->type != FCNCALL) {
1215 strcpy(function, global);
1218 else if (p->fcnoffset != lastfcnoffset) {
1219 if (dbseek(p->fcnoffset) != -1) {
1220 fetch_string_from_dbase(function, sizeof(function));
1221 lastfcnoffset = p->fcnoffset;
1224 if (dbseek(p->lineoffset) != -1) {
1226 putref(0, srcfiles[p->fileindex], pat);
1228 putref(0, srcfiles[p->fileindex], function);
1232 /* seek to the database offset */
1240 if ((n = offset / BUFSIZ) != blocknumber) {
1241 if ((rc = lseek(symrefs, n * BUFSIZ, 0)) == -1) {
1242 myperror("Lseek failed");
1246 (void) read_block();
1249 blockp = block + offset % BUFSIZ;
1254 findcalledbysub(char *file, BOOL macro)
1256 /* find the next function call or the end of this function */
1257 while (scanpast('\t') != NULL) {
1260 case DEFINE: /* #define inside a function */
1261 if (fileversion >= 10) { /* skip it */
1262 while (scanpast('\t') != NULL &&
1263 *blockp != DEFINEEND)
1268 case FCNCALL: /* function call */
1270 /* output the file name */
1271 (void) fprintf(refsfound, "%s ", file);
1273 /* output the function name */
1276 (void) putc(' ', refsfound);
1278 /* output the source line */
1279 putsource(1, refsfound);
1282 case DEFINEEND: /* #define end */
1284 if (invertedindex == NO) {
1288 break; /* inside a function */
1292 case FCNDEF: /* function end (pre 9.5) */
1294 if (invertedindex == NO) break;
1297 case FCNEND: /* function end */
1298 case NEWFILE: /* file end */