1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1988 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 /* 34 * cscope - interactive C symbol cross-reference 35 * 36 * build cross-reference file 37 */ 38 39 #include "global.h" 40 41 /* convert long to a string */ 42 #define ltobase(value) n = value; \ 43 s = buf + (sizeof (buf) - 1); \ 44 *s = '\0'; \ 45 digits = 1; \ 46 while (n >= BASE) { \ 47 ++digits; \ 48 i = n; \ 49 n /= BASE; \ 50 *--s = i - n * BASE + '!'; \ 51 } \ 52 *--s = n + '!'; 53 54 #define SYMBOLINC 20 /* symbol list size increment */ 55 #define FREAD "r" /* fopen for reading */ 56 57 long dboffset; /* new database offset */ 58 BOOL errorsfound; /* prompt before clearing messages */ 59 long fileindex; /* source file name index */ 60 long lineoffset; /* source line database offset */ 61 long npostings; /* number of postings */ 62 int nsrcoffset; /* number of file name database offsets */ 63 long *srcoffset; /* source file name database offsets */ 64 int symbols; /* number of symbols */ 65 66 static char *filename; /* file name for warning messages */ 67 static long fcnoffset; /* function name database offset */ 68 static long macrooffset; /* macro name database offset */ 69 static int msymbols = SYMBOLINC; /* maximum number of symbols */ 70 static struct symbol { /* symbol data */ 71 int type; /* type */ 72 int first; /* index of first character in text */ 73 int last; /* index of last+1 character in text */ 74 int length; /* symbol length */ 75 } *symbol; 76 77 static void putcrossref(void); 78 79 void 80 crossref(char *srcfile) 81 { 82 int i; 83 int length; /* symbol length */ 84 int token; /* current token */ 85 86 /* open the source file */ 87 if ((yyin = vpfopen(srcfile, FREAD)) == NULL) { 88 cannotopen(srcfile); 89 errorsfound = YES; 90 return; 91 } 92 filename = srcfile; /* save the file name for warning messages */ 93 putfilename(srcfile); /* output the file name */ 94 dbputc('\n'); 95 dbputc('\n'); 96 97 /* read the source file */ 98 initscanner(srcfile); 99 fcnoffset = macrooffset = 0; 100 symbols = 0; 101 if (symbol == NULL) { 102 symbol = mymalloc(msymbols * sizeof (struct symbol)); 103 } 104 for (;;) { 105 106 /* get the next token */ 107 switch (token = yylex()) { 108 default: 109 /* if requested, truncate C symbols */ 110 length = last - first; 111 if (truncatesyms && length > 8 && 112 token != INCLUDE && token != NEWFILE) { 113 length = 8; 114 last = first + 8; 115 } 116 /* see if the token has a symbol */ 117 if (length == 0) { 118 savesymbol(token); 119 break; 120 } 121 /* see if the symbol is already in the list */ 122 for (i = 0; i < symbols; ++i) { 123 if (length == symbol[i].length && 124 strncmp(yytext + first, yytext + 125 symbol[i].first, length) == 0 && 126 (token == IDENT || 127 token == symbol[i].type)) { 128 first = yyleng; 129 break; 130 } 131 } 132 if (i == symbols) { /* if not already in list */ 133 savesymbol(token); 134 } 135 break; 136 137 case NEWLINE: /* end of line containing symbols */ 138 --yyleng; /* remove the newline */ 139 putcrossref(); /* output the symbols and source line */ 140 lineno = yylineno; /* save the symbol line number */ 141 break; 142 143 case LEXEOF: /* end of file; last line may not have \n */ 144 145 /* 146 * if there were symbols, output them and the 147 * source line 148 */ 149 if (symbols > 0) { 150 putcrossref(); 151 } 152 (void) fclose(yyin); /* close the source file */ 153 154 /* output the leading tab expected by the next call */ 155 dbputc('\t'); 156 return; 157 } 158 } 159 } 160 161 /* save the symbol in the list */ 162 163 void 164 savesymbol(int token) 165 { 166 /* make sure there is room for the symbol */ 167 if (symbols == msymbols) { 168 msymbols += SYMBOLINC; 169 symbol = (struct symbol *)myrealloc(symbol, 170 msymbols * sizeof (struct symbol)); 171 } 172 /* save the symbol */ 173 symbol[symbols].type = token; 174 symbol[symbols].first = first; 175 symbol[symbols].last = last; 176 symbol[symbols].length = last - first; 177 ++symbols; 178 first = yyleng; 179 } 180 181 /* output the file name */ 182 183 void 184 putfilename(char *srcfile) 185 { 186 /* check for file system out of space */ 187 /* note: dbputc is not used to avoid lint complaint */ 188 if (putc(NEWFILE, newrefs) == EOF) { 189 cannotwrite(newreffile); 190 /* NOTREACHED */ 191 } 192 ++dboffset; 193 if (invertedindex) { 194 srcoffset[nsrcoffset++] = dboffset; 195 } 196 dbfputs(srcfile); 197 fcnoffset = macrooffset = 0; 198 } 199 200 /* output the symbols and source line */ 201 202 static void 203 putcrossref(void) 204 { 205 int i, j; 206 unsigned c; 207 BOOL blank = NO; /* output blank */ 208 BOOL newline = NO; /* output newline */ 209 int symput = 0; /* symbols output */ 210 int type; 211 212 /* output the source line */ 213 lineoffset = dboffset; 214 dbfprintf(newrefs, "%d ", lineno); 215 for (i = 0; i < yyleng; ++i) { 216 217 /* change a tab to a blank and compress blanks */ 218 if ((c = yytext[i]) == ' ' || c == '\t') { 219 blank = YES; 220 } 221 /* look for the start of a symbol */ 222 else if (symput < symbols && i == symbol[symput].first) { 223 224 /* check for compressed blanks */ 225 if (blank) { 226 blank = NO; 227 if (newline) { 228 dbputc('\n'); 229 } 230 dbputc(' '); 231 } 232 dbputc('\n'); /* symbols start on a new line */ 233 234 /* output any symbol type */ 235 if ((type = symbol[symput].type) != IDENT) { 236 dbputc('\t'); 237 dbputc(type); 238 } else { 239 type = ' '; 240 } 241 /* output the symbol */ 242 j = symbol[symput].last; 243 c = yytext[j]; 244 yytext[j] = '\0'; 245 if (invertedindex) { 246 putposting(yytext + i, type); 247 } 248 putstring(yytext + i); 249 newline = YES; 250 yytext[j] = (char)c; 251 i = j - 1; 252 ++symput; 253 } else { 254 if (newline) { 255 newline = NO; 256 dbputc('\n'); 257 } 258 /* check for compressed blanks */ 259 if (blank) { 260 if (dicode2[c]) { 261 c = (0200 - 2) + dicode1[' '] + 262 dicode2[c]; 263 } else { 264 dbputc(' '); 265 } 266 } else if (dicode1[c] && 267 (j = dicode2[(unsigned)yytext[i + 1]]) != 0 && 268 symput < symbols && i + 1 != symbol[symput].first) { 269 /* compress digraphs */ 270 c = (0200 - 2) + dicode1[c] + j; 271 ++i; 272 } 273 /* 274 * if the last line of the file is a '}' without a 275 * newline, the lex EOF code overwrites it with a 0 276 */ 277 if (c) { 278 dbputc((int)c); 279 } else { 280 dbputc(' '); 281 } 282 blank = NO; 283 284 /* skip compressed characters */ 285 if (c < ' ') { 286 ++i; 287 288 /* skip blanks before a preprocesor keyword */ 289 /* 290 * note: don't use isspace() because \f and \v 291 * are used for keywords 292 */ 293 while ((j = yytext[i]) == ' ' || j == '\t') { 294 ++i; 295 } 296 /* skip the rest of the keyword */ 297 while (isalpha(yytext[i])) { 298 ++i; 299 } 300 /* skip space after certain keywords */ 301 if (keyword[c].delim != '\0') { 302 while ((j = yytext[i]) == ' ' || 303 j == '\t') { 304 ++i; 305 } 306 } 307 /* skip a '(' after certain keywords */ 308 if (keyword[c].delim == '(' && 309 yytext[i] == '(') { 310 ++i; 311 } 312 --i; /* compensate for ++i in for() */ 313 } 314 } 315 } 316 /* ignore trailing blanks */ 317 dbputc('\n'); 318 dbputc('\n'); 319 320 /* output any #define end marker */ 321 /* 322 * note: must not be part of #define so putsource() doesn't discard it 323 * so findcalledbysub() can find it and return 324 */ 325 if (symput < symbols && symbol[symput].type == DEFINEEND) { 326 dbputc('\t'); 327 dbputc(DEFINEEND); 328 dbputc('\n'); 329 dbputc('\n'); /* mark beginning of next source line */ 330 macrooffset = 0; 331 } 332 symbols = 0; 333 } 334 335 /* output the inverted index posting */ 336 337 void 338 putposting(char *term, int type) 339 { 340 long i, n; 341 char *s; 342 int digits; /* digits output */ 343 long offset; /* function/macro database offset */ 344 char buf[11]; /* number buffer */ 345 346 /* get the function or macro name offset */ 347 offset = fcnoffset; 348 if (macrooffset != 0) { 349 offset = macrooffset; 350 } 351 /* then update them to avoid negative relative name offset */ 352 switch (type) { 353 case DEFINE: 354 macrooffset = dboffset; 355 break; 356 case DEFINEEND: 357 macrooffset = 0; 358 return; /* null term */ 359 case FCNDEF: 360 fcnoffset = dboffset; 361 break; 362 case FCNEND: 363 fcnoffset = 0; 364 return; /* null term */ 365 } 366 /* ignore a null term caused by a enum/struct/union without a tag */ 367 if (*term == '\0') { 368 return; 369 } 370 /* skip any #include secondary type char (< or ") */ 371 if (type == INCLUDE) { 372 ++term; 373 } 374 /* 375 * output the posting, which should be as small as possible to reduce 376 * the temp file size and sort time 377 */ 378 (void) fputs(term, postings); 379 (void) putc(' ', postings); 380 381 /* 382 * the line offset is padded so postings for the same term will sort 383 * in ascending line offset order to order the references as they 384 * appear withing a source file 385 */ 386 ltobase(lineoffset); 387 for (i = PRECISION - digits; i > 0; --i) { 388 (void) putc('!', postings); 389 } 390 do { 391 (void) putc(*s, postings); 392 } while (*++s != '\0'); 393 394 /* postings are also sorted by type */ 395 (void) putc(type, postings); 396 397 /* function or macro name offset */ 398 if (offset > 0) { 399 (void) putc(' ', postings); 400 ltobase(offset); 401 do { 402 (void) putc(*s, postings); 403 } while (*++s != '\0'); 404 } 405 if (putc('\n', postings) == EOF) { 406 cannotwrite(temp1); 407 /* NOTREACHED */ 408 } 409 ++npostings; 410 } 411 412 /* put the string into the new database */ 413 414 void 415 putstring(char *s) 416 { 417 unsigned c; 418 int i; 419 420 /* compress digraphs */ 421 for (i = 0; (c = s[i]) != '\0'; ++i) { 422 if (dicode1[c] && dicode2[(unsigned)s[i + 1]]) { 423 c = (0200 - 2) + dicode1[c] + 424 dicode2[(unsigned)s[i + 1]]; 425 ++i; 426 } 427 dbputc((int)c); 428 } 429 } 430 431 /* print a warning message with the file name and line number */ 432 433 void 434 warning(text) 435 char *text; 436 { 437 extern int yylineno; 438 439 (void) fprintf(stderr, "cscope: \"%s\", line %d: warning: %s\n", 440 filename, yylineno, text); 441 errorsfound = YES; 442 } 443