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
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.
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]
22 /* Copyright (c) 1988 AT&T */
23 /* All Rights Reserved */
27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 * Copyright 2015 Gary Mills
33 * cscope - interactive C symbol cross-reference
39 #include "version.h" /* FILEVERSION and FIXVERSION */
40 #include <curses.h> /* COLS and LINES */
41 #include <setjmp.h> /* jmp_buf */
45 /* see if the function column should be displayed */
46 #define displayfcn() (field <= ASSIGN)
48 #define MINCOLS 68 /* minimum columns for 3 digit Lines message numbers */
50 int *displine
; /* screen line of displayed reference */
51 int disprefs
; /* displayed references */
52 int field
; /* input field */
53 unsigned fldcolumn
; /* input field column */
54 int mdisprefs
; /* maximum displayed references */
55 int selectlen
; /* selection number field length */
56 int nextline
; /* next line to be shown */
57 int topline
= 1; /* top line of page */
58 int bottomline
; /* bottom line of page */
59 int totallines
; /* total reference lines */
60 FILE *refsfound
; /* references found file */
61 FILE *nonglobalrefs
; /* non-global references file */
63 static int fldline
; /* input field line */
64 static int subsystemlen
; /* OGS subsystem name display */
66 static int booklen
; /* OGS book name display field length */
67 static int filelen
; /* file name display field length */
68 static int fcnlen
; /* function name display field length */
69 static jmp_buf env
; /* setjmp/longjmp buffer */
70 static int lastdispline
; /* last displayed reference line */
71 static char lastmsg
[MSGLEN
+ 1]; /* last message displayed */
72 static int numlen
; /* line number display field length */
73 static char depthstring
[] = "Depth: ";
74 static char helpstring
[] = "Press the ? key for help";
77 typedef char *(*FP
)(); /* pointer to function returning a character pointer */
87 } fields
[FIELDS
+ 1] = {
88 /* last search is not part of the cscope display */
89 { "Find this", "C symbol",
90 (FP
) findsymbol
, REGCMP
},
91 { "Find this", "definition",
92 (FP
) finddef
, REGCMP
},
93 { "Find", "functions called by this function",
94 (FP
) findcalledby
, REGCMP
},
95 { "Find", "functions calling this function",
96 (FP
) findcalling
, REGCMP
},
97 { "Find", "assignments to",
98 (FP
) findassignments
, REGCMP
},
99 { "Change this", "grep pattern",
101 { "Find this", "egrep pattern",
102 findegreppat
, EGREP
},
103 { "Find this", "file",
104 (FP
) findfile
, REGCMP
},
105 { "Find", "files #including this file",
106 (FP
) findinclude
, REGCMP
},
107 { "Find all", "function/class definitions",
108 (FP
) findallfcns
, REGCMP
},
111 /* initialize display parameters */
116 /* calculate the maximum displayed reference lines */
117 lastdispline
= FLDLINE
- 2;
118 mdisprefs
= lastdispline
- REFLINE
+ 1;
119 if (mdisprefs
<= 0) {
120 (void) printw("cscope: window must be at least %d lines high",
124 if (COLS
< MINCOLS
) {
125 (void) printw("cscope: window must be at least %d columns wide",
130 if (returnrequired
== NO
&& mdisprefs
> 9) {
131 mdisprefs
= 9; /* single digit selection number */
133 /* calculate the maximum selection number width */
134 (void) sprintf(newpat
, "%d", mdisprefs
);
135 selectlen
= strlen(newpat
);
137 /* allocate the displayed line array */
138 displine
= (int *)mymalloc(mdisprefs
* sizeof (int));
141 /* display a page of the references */
146 char *subsystem
; /* OGS subsystem name */
147 char *book
; /* OGS book name */
148 char file
[PATHLEN
+ 1]; /* file name */
149 char function
[PATLEN
+ 1]; /* function name */
150 char linenum
[NUMLEN
+ 1]; /* line number */
151 int screenline
; /* screen line number */
152 int width
; /* source line display width */
158 /* if there are no references */
159 if (totallines
== 0) {
160 if (*lastmsg
!= '\0') {
161 (void) addstr(lastmsg
); /* redisplay any message */
163 (void) printw("Cscope version %d%s", FILEVERSION
,
165 (void) move(0, COLS
- (int)sizeof (helpstring
));
166 (void) addstr(helpstring
);
168 } else { /* display the pattern */
169 if (changing
== YES
) {
170 (void) printw("Change \"%s\" to \"%s\"",
173 (void) printw("%c%s: %s",
174 toupper(fields
[field
].text2
[0]),
175 fields
[field
].text2
+ 1, pattern
);
177 /* display the cscope invocation nesting depth */
178 if (cscopedepth
> 1) {
179 (void) move(0, COLS
- (int)sizeof (depthstring
) - 2);
180 (void) addstr(depthstring
);
181 (void) printw("%d", cscopedepth
);
183 /* display the column headings */
184 (void) move(2, selectlen
+ 1);
185 if (ogs
== YES
&& field
!= FILENAME
) {
186 (void) printw("%-*s ", subsystemlen
, "Subsystem");
187 (void) printw("%-*s ", booklen
, "Book");
189 if (dispcomponents
> 0) {
190 (void) printw("%-*s ", filelen
, "File");
193 (void) printw("%-*s ", fcnlen
, "Function");
195 if (field
!= FILENAME
) {
196 (void) addstr("Line");
200 /* if at end of file go back to beginning */
201 if (nextline
> totallines
) {
204 /* calculate the source text column */
205 width
= COLS
- selectlen
- numlen
- 2;
207 width
-= subsystemlen
+ booklen
+ 2;
209 if (dispcomponents
> 0) {
210 width
-= filelen
+ 1;
216 * until the max references have been displayed or
217 * there is no more room
220 for (disprefs
= 0, screenline
= REFLINE
;
221 disprefs
< mdisprefs
&& screenline
<= lastdispline
;
222 ++disprefs
, ++screenline
) {
223 /* read the reference line */
224 if (fscanf(refsfound
, "%s%s%s %[^\n]", file
, function
,
225 linenum
, yytext
) < 4) {
229 displine
[disprefs
] = screenline
;
231 /* if no mouse, display the selection number */
233 (void) printw("%*d", selectlen
, disprefs
+ 1);
235 /* display any change mark */
236 if (changing
== YES
&&
237 change
[topline
+ disprefs
- 1] == YES
) {
242 /* display the file name */
243 if (field
== FILENAME
) {
244 (void) printw("%-.*s\n", COLS
- 3, file
);
247 /* if OGS, display the subsystem and book names */
249 ogsnames(file
, &subsystem
, &book
);
250 (void) printw("%-*.*s ", subsystemlen
,
251 subsystemlen
, subsystem
);
252 (void) printw("%-*.*s ", booklen
, booklen
,
255 /* display the requested path components */
256 if (dispcomponents
> 0) {
257 (void) printw("%-*.*s ", filelen
, filelen
,
258 pathcomponents(file
, dispcomponents
));
260 /* display the function name */
262 (void) printw("%-*.*s ", fcnlen
, fcnlen
,
265 /* display the line number */
266 (void) printw("%*s ", numlen
, linenum
);
268 /* there may be tabs in egrep output */
269 while ((s
= strchr(yytext
, '\t')) != NULL
) {
272 /* display the source line */
275 /* see if the source line will fit */
276 if ((i
= strlen(s
)) > width
) {
277 /* find the nearest blank */
278 for (i
= width
; s
[i
] != ' ' && i
> 0;
282 i
= width
; /* no blank */
285 /* print up to this point */
286 (void) printw("%.*s", i
, s
);
289 /* if line didn't wrap around */
291 /* go to next line */
298 /* see if there is more text */
302 /* if the source line is too long */
303 if (++screenline
> lastdispline
) {
305 * if this is the first displayed line,
306 * display what will fit on the screen
308 if (topline
== nextline
- 1) {
311 /* erase the reference */
312 while (--screenline
>=
313 displine
[disprefs
]) {
314 (void) move(screenline
, 0);
320 * go back to the beginning of this
327 /* indent the continued source line */
328 (void) move(screenline
, COLS
- width
);
333 /* check for more references */
334 bottomline
= nextline
;
335 if (bottomline
- topline
< totallines
) {
336 (void) move(FLDLINE
- 1, 0);
338 (void) printw("%*s", selectlen
+ 1, "");
339 if (bottomline
- 1 == topline
) {
340 (void) printw("Line %d", topline
);
342 (void) printw("Lines %d-%d", topline
,
345 (void) printw(" of %d, press the space bar to "
346 "display next lines", totallines
);
350 /* display the input fields */
351 (void) move(FLDLINE
, 0);
352 for (i
= 0; i
< FIELDS
; ++i
) {
353 (void) printw("%s %s:\n", fields
[i
].text1
, fields
[i
].text2
);
355 drawscrollbar(topline
, nextline
, totallines
);
358 /* set the cursor position for the field */
362 fldline
= FLDLINE
+ field
;
363 fldcolumn
= strlen(fields
[field
].text1
) +
364 strlen(fields
[field
].text2
) + 3;
367 /* move to the current input field */
372 (void) move(fldline
, (int)fldcolumn
);
375 /* search for the symbol or text pattern */
387 char *volatile egreperror
= NULL
; /* egrep error message */
388 FINDINIT
volatile rc
= NOERROR
; /* findinit return code */
389 SIGTYPE (*volatile savesig
)() = SIG_DFL
; /* old value of signal */
390 FP f
; /* searching function */
394 /* note: the pattern may have been a cscope argument */
395 if (caseless
== YES
) {
396 for (s
= pattern
; *s
!= '\0'; ++s
) {
400 /* open the references found file for writing */
401 if (writerefsfound() == NO
) {
404 /* find the pattern - stop on an interrupt */
405 if (linemode
== NO
) {
409 if (setjmp(env
) == 0) {
410 savesig
= signal(SIGINT
, jumpback
);
411 f
= fields
[field
].findfcn
;
412 if (fields
[field
].patterntype
== EGREP
) {
413 egreperror
= (*f
)(pattern
);
415 if ((nonglobalrefs
= fopen(temp2
, "w")) == NULL
) {
419 if ((rc
= findinit()) == NOERROR
) {
420 (void) dbseek(0L); /* goto the first block */
424 /* append the non-global references */
425 (void) freopen(temp2
, "r", nonglobalrefs
);
426 while ((c
= getc(nonglobalrefs
)) != EOF
) {
427 (void) putc(c
, refsfound
);
430 (void) fclose(nonglobalrefs
);
433 (void) signal(SIGINT
, savesig
);
434 /* reopen the references found file for reading */
435 (void) freopen(temp1
, "r", refsfound
);
439 /* see if it is empty */
440 if ((c
= getc(refsfound
)) == EOF
) {
441 if (egreperror
!= NULL
) {
442 (void) sprintf(lastmsg
, "Egrep %s in this pattern: %s",
443 egreperror
, pattern
);
444 } else if (rc
== NOTSYMBOL
) {
445 (void) sprintf(lastmsg
, "This is not a C symbol: %s",
447 } else if (rc
== REGCMPERROR
) {
448 (void) sprintf(lastmsg
,
449 "Error in this regcmp(3X) regular expression: %s",
452 (void) sprintf(lastmsg
, "Could not find the %s: %s",
453 fields
[field
].text2
, pattern
);
457 /* put back the character read */
458 (void) ungetc(c
, refsfound
);
464 /* open the references found file for writing */
469 if (refsfound
== NULL
) {
470 if ((refsfound
= fopen(temp1
, "w")) == NULL
) {
474 } else if (freopen(temp1
, "w", refsfound
) == NULL
) {
475 putmsg("Cannot reopen temporary file");
481 /* count the references found */
486 char *subsystem
; /* OGS subsystem name */
487 char *book
; /* OGS book name */
488 char file
[PATHLEN
+ 1]; /* file name */
489 char function
[PATLEN
+ 1]; /* function name */
490 char linenum
[NUMLEN
+ 1]; /* line number */
494 * count the references found and find the length of the file,
495 * function, and line number display fields
497 subsystemlen
= 9; /* strlen("Subsystem") */
498 booklen
= 4; /* strlen("Book") */
499 filelen
= 4; /* strlen("File") */
500 fcnlen
= 8; /* strlen("Function") */
502 while ((i
= fscanf(refsfound
, "%250s%250s%6s %5000[^\n]", file
,
503 function
, linenum
, yytext
)) != EOF
) {
504 if (i
!= 4 || !isgraph(*file
) ||
505 !isgraph(*function
) || !isdigit(*linenum
)) {
506 putmsg("File does not have expected format");
510 if ((i
= strlen(pathcomponents(file
,
511 dispcomponents
))) > filelen
) {
515 ogsnames(file
, &subsystem
, &book
);
516 if ((i
= strlen(subsystem
)) > subsystemlen
) {
519 if ((i
= strlen(book
)) > booklen
) {
523 if ((i
= strlen(function
)) > fcnlen
) {
526 if ((i
= strlen(linenum
)) > numlen
) {
533 /* restrict the width of displayed columns */
538 if (filelen
> i
&& i
> 4) {
541 if (subsystemlen
> i
&& i
> 9) {
544 if (booklen
> i
&& i
> 4) {
547 if (fcnlen
> i
&& i
> 8) {
552 /* print error message on system call failure */
557 char msg
[MSGLEN
+ 1]; /* message */
559 (void) sprintf(msg
, "%s: %s", text
, strerror(errno
));
563 /* putmsg clears the message line and prints the message */
568 if (incurses
== NO
) {
569 *msg
= tolower(*msg
);
570 (void) fprintf(stderr
, "cscope: %s\n", msg
);
572 (void) move(MSGLINE
, 0);
577 (void) strncpy(lastmsg
, msg
, sizeof (lastmsg
) - 1);
580 /* clearmsg2 clears the second message line */
585 if (incurses
== YES
) {
586 (void) move(MSGLINE
+ 1, 0);
591 /* putmsg2 clears the second message line and prints the message */
596 if (incurses
== NO
) {
605 /* position the references found file at the specified line */
612 /* verify that there is a references found file */
613 if (refsfound
== NULL
) {
616 /* go to the beginning of the file */
619 /* find the requested line */
621 while (nextline
< line
&& (c
= getc(refsfound
)) != EOF
) {
628 /* get the OGS subsystem and book names */
631 ogsnames(char *file
, char **subsystem
, char **book
)
633 static char buf
[PATHLEN
+ 1];
636 *subsystem
= *book
= "";
637 (void) strcpy(buf
, file
);
642 while ((slash
= strchr(s
, '/')) != NULL
) {
644 if ((int)strlen(s
) >= 3 && strncmp(slash
- 3, ".ss", 3) == 0) {
647 if ((slash
= strchr(s
, '/')) != NULL
) {
657 /* get the requested path components */
660 pathcomponents(char *path
, int components
)
665 s
= path
+ strlen(path
) - 1;
666 for (i
= 0; i
< components
; ++i
) {
667 while (s
> path
&& *--s
!= '/') {
671 if (s
> path
&& *s
== '/') {