1 /*===========================================================================
2 Copyright (c) 1998-2000, The Santa Cruz Operation
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 *Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10
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.
14
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.
18
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
26 INTERRUPTION)
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
30 DAMAGE.
31 =========================================================================*/
32
33 /* cscope - interactive C symbol or text cross-reference
34 *
35 * command functions
36 */
37
38 #include "global.h"
39 #include "build.h" /* for rebuild() */
40 #include "alloc.h"
41
42 #include <stdlib.h>
43 #if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
44 #include <ncurses.h>
45 #else
46 #include <curses.h>
47 #endif
48 #include <ctype.h>
49
50 int selecting;
51 unsigned int curdispline = 0;
52
53 BOOL caseless; /* ignore letter case when searching */
54 BOOL *change; /* change this line */
55 BOOL changing; /* changing text */
56 char newpat[PATLEN + 1]; /* new pattern */
57 /* HBB 20040430: renamed to avoid lots of clashes with function arguments
58 * also named 'pattern' */
59 char Pattern[PATLEN + 1]; /* symbol or text pattern */
60
61 /* HBB FIXME 20060419: these should almost certainly be const */
62 static char appendprompt[] = "Append to file: ";
63 static char pipeprompt[] = "Pipe to shell command: ";
64 static char readprompt[] = "Read from file: ";
65 static char toprompt[] = "To: ";
66
67
68 /* Internal prototypes: */
69 static BOOL changestring(void);
70 static void clearprompt(void);
71 static void mark(unsigned int i);
72 static void scrollbar(MOUSE *p);
73
74
75 /* execute the command */
76 BOOL
command(int commandc)77 command(int commandc)
78 {
79 char filename[PATHLEN + 1]; /* file path name */
80 MOUSE *p; /* mouse data */
81 int c, i;
82 FILE *file;
83 struct cmd *curritem, *item; /* command history */
84 char *s;
85
86 switch (commandc) {
87 case ctrl('C'): /* toggle caseless mode */
88 if (caseless == NO) {
89 caseless = YES;
90 postmsg2("Caseless mode is now ON");
91 } else {
92 caseless = NO;
93 postmsg2("Caseless mode is now OFF");
94 }
95 egrepcaseless(caseless); /* turn on/off -i flag */
96 return(NO);
97
98 case ctrl('R'): /* rebuild the cross reference */
99 if (isuptodate == YES) {
100 postmsg("The -d option prevents rebuilding the symbol database");
101 return(NO);
102 }
103 exitcurses();
104 freefilelist(); /* remake the source file list */
105 makefilelist();
106 rebuild();
107 if (errorsfound == YES) {
108 errorsfound = NO;
109 askforreturn();
110 }
111 entercurses();
112 clearmsg(); /* clear any previous message */
113 totallines = 0;
114 disprefs = 0;
115 topline = nextline = 1;
116 selecting = 0;
117 break;
118
119 #if UNIXPC
120 case ESC: /* possible unixpc mouse selection */
121 #endif
122 case ctrl('X'): /* mouse selection */
123 if ((p = getmouseaction(DUMMYCHAR)) == NULL) {
124 return(NO); /* unknown control sequence */
125 }
126 /* if the button number is a scrollbar tag */
127 if (p->button == '0') {
128 scrollbar(p);
129 break;
130 }
131 /* ignore a sweep */
132 if (p->x2 >= 0) {
133 return(NO);
134 }
135 /* if this is a line selection */
136 if (p->y1 < FLDLINE) {
137
138 /* find the selected line */
139 /* note: the selection is forced into range */
140 for (i = disprefs - 1; i > 0; --i) {
141 if (p->y1 >= displine[i]) {
142 break;
143 }
144 }
145 /* display it in the file with the editor */
146 editref(i);
147 } else { /* this is an input field selection */
148 field = p->y1 - FLDLINE;
149 /* force it into range */
150 if (field >= FIELDS) {
151 field = FIELDS - 1;
152 }
153 setfield();
154 resetcmd();
155 return(NO);
156 }
157 break;
158
159 case '\t': /* go to next input field */
160 if (disprefs) {
161 selecting = !selecting;
162 if (selecting) {
163 move(displine[curdispline], 0);
164 refresh();
165 } else {
166 atfield();
167 resetcmd();
168 }
169 }
170 return(NO);
171
172 #ifdef KEY_ENTER
173 case KEY_ENTER:
174 #endif
175 case '\r':
176 case '\n': /* go to reference */
177 if (selecting) {
178 editref(curdispline);
179 return(YES);
180 }
181 /* FALLTHROUGH */
182
183 case ctrl('N'):
184 #ifdef KEY_DOWN
185 case KEY_DOWN:
186 #endif
187 #ifdef KEY_RIGHT
188 case KEY_RIGHT:
189 #endif
190 if (selecting) {
191 if ((curdispline + 1) < disprefs) {
192 move(displine[++curdispline], 0);
193 refresh();
194 }
195 } else {
196 field = (field + 1) % FIELDS;
197 setfield();
198 atfield();
199 resetcmd();
200 }
201 return(NO);
202
203 case ctrl('P'): /* go to previous input field */
204 #ifdef KEY_UP
205 case KEY_UP:
206 #endif
207 #ifdef KEY_LEFT
208 case KEY_LEFT:
209 #endif
210 if (selecting) {
211 if (curdispline) {
212 move(displine[--curdispline], 0);
213 refresh();
214 }
215 } else {
216 field = (field + (FIELDS - 1)) % FIELDS;
217 setfield();
218 atfield();
219 resetcmd();
220 }
221 return(NO);
222 #ifdef KEY_HOME
223 case KEY_HOME: /* go to first input field */
224 if (selecting) {
225 curdispline = 0;
226 move(REFLINE, 0);
227 refresh();
228 } else {
229 field = 0;
230 setfield();
231 atfield();
232 resetcmd();
233 }
234 return(NO);
235 #endif
236
237 #ifdef KEY_LL
238 case KEY_LL: /* go to last input field */
239 if (selecting) {
240 move(displine[disprefs - 1], 0);
241 refresh();
242 } else {
243 field = FIELDS - 1;
244 setfield();
245 atfield();
246 resetcmd();
247 }
248 return(NO);
249 #endif /* def(KEY_LL) */
250
251 case ' ': /* display next page */
252 case '+':
253 case ctrl('V'):
254 #ifdef KEY_NPAGE
255 case KEY_NPAGE:
256 #endif
257 /* don't redisplay if there are no lines */
258 if (totallines == 0) {
259 return(NO);
260 }
261 /* note: seekline() is not used to move to the next
262 * page because display() leaves the file pointer at
263 * the next page to optimize paging forward
264 */
265 curdispline = 0;
266 break;
267
268 case ctrl('H'):
269 case '-': /* display previous page */
270 #ifdef KEY_PPAGE
271 case KEY_PPAGE:
272 #endif
273 /* don't redisplay if there are no lines */
274 if (totallines == 0) {
275 return(NO);
276 }
277
278 curdispline = 0;
279
280 /* if there are only two pages, just go to the other one */
281 if (totallines <= 2 * mdisprefs) {
282 break;
283 }
284 /* if on first page but not at beginning, go to beginning */
285 nextline -= mdisprefs; /* already at next page */
286 if (nextline > 1 && nextline <= mdisprefs) {
287 nextline = 1;
288 } else {
289 nextline -= mdisprefs;
290 if (nextline < 1) {
291 nextline = totallines - mdisprefs + 1;
292 if (nextline < 1) {
293 nextline = 1;
294 }
295 }
296 }
297 seekline(nextline);
298 break;
299
300 case '>': /* write or append the lines to a file */
301 if (totallines == 0) {
302 postmsg("There are no lines to write to a file");
303 } else { /* get the file name */
304 move(PRLINE, 0);
305 addstr("Write to file: ");
306 s = "w";
307 if ((c = mygetch()) == '>') {
308 move(PRLINE, 0);
309 addstr(appendprompt);
310 c = '\0';
311 s = "a";
312 }
313 if (c != '\r' &&
314 mygetline("", newpat, COLS - sizeof(appendprompt), c, NO) > 0) {
315 shellpath(filename, sizeof(filename), newpat);
316 if ((file = myfopen(filename, s)) == NULL) {
317 cannotopen(filename);
318 } else {
319 seekline(1);
320 while ((c = getc(refsfound)) != EOF) {
321 putc(c, file);
322 }
323 seekline(topline);
324 fclose(file);
325 }
326 }
327 clearprompt();
328 }
329 return(NO); /* return to the previous field */
330
331 case '<': /* read lines from a file */
332 move(PRLINE, 0);
333 addstr(readprompt);
334 if (mygetline("", newpat, COLS - sizeof(readprompt), '\0', NO) > 0) {
335 clearprompt();
336 shellpath(filename, sizeof(filename), newpat);
337 if (readrefs(filename) == NO) {
338 postmsg2("Ignoring an empty file");
339 return(NO);
340 }
341 return(YES);
342 }
343 clearprompt();
344 return(NO);
345
346 case '^': /* pipe the lines through a shell command */
347 case '|': /* pipe the lines to a shell command */
348 if (totallines == 0) {
349 postmsg("There are no lines to pipe to a shell command");
350 return(NO);
351 }
352 /* get the shell command */
353 move(PRLINE, 0);
354 addstr(pipeprompt);
355 if (mygetline("", newpat, COLS - sizeof(pipeprompt), '\0', NO) == 0) {
356 clearprompt();
357 return(NO);
358 }
359 /* if the ^ command, redirect output to a temp file */
360 if (commandc == '^') {
361 strcat(strcat(newpat, " >"), temp2);
362 /* HBB 20020708: somebody might have even
363 * their non-interactive default shells
364 * complain about clobbering
365 * redirections... --> delete before
366 * overwriting */
367 remove(temp2);
368 }
369 exitcurses();
370 if ((file = mypopen(newpat, "w")) == NULL) {
371 fprintf(stderr, "\
372 cscope: cannot open pipe to shell command: %s\n", newpat);
373 } else {
374 seekline(1);
375 while ((c = getc(refsfound)) != EOF) {
376 putc(c, file);
377 }
378 seekline(topline);
379 mypclose(file);
380 }
381 if (commandc == '^') {
382 if (readrefs(temp2) == NO) {
383 postmsg("Ignoring empty output of ^ command");
384 }
385 }
386 askforreturn();
387 entercurses();
388 break;
389 #if defined(KEY_RESIZE) && !defined(__DJGPP__)
390 case KEY_RESIZE:
391 exitcurses();
392 initscr();
393 entercurses();
394 #if TERMINFO
395 keypad(stdscr, TRUE); /* enable the keypad */
396 #ifdef HAVE_FIXKEYPAD
397 fixkeypad(); /* fix for getch() intermittently returning garbage */
398 #endif
399 #endif
400 #if UNIXPC
401 standend(); /* turn off reverse video */
402 #endif
403 dispinit(); /* initialize display parameters */
404 setfield(); /* set the initial cursor position */
405 postmsg(""); /* clear any build progress message */
406 display(); /* display the version number and input fields */
407 break;
408 #endif
409 case ctrl('L'): /* redraw screen */
410 #ifdef KEY_CLEAR
411 case KEY_CLEAR:
412 #endif
413 clearmsg2();
414 clearok(curscr, TRUE);
415 wrefresh(curscr);
416 drawscrollbar(topline, bottomline);
417 return(NO);
418
419 case '!': /* shell escape */
420 execute(shell, shell, NULL);
421 seekline(topline);
422 break;
423
424 case '?': /* help */
425 clear();
426 help();
427 clear();
428 seekline(topline);
429 break;
430
431 case ctrl('E'): /* edit all lines */
432 editall();
433 break;
434
435 case ctrl('A'): /* HBB 20050428: added alt. keymapping */
436 case ctrl('Y'): /* repeat last pattern */
437 if (*Pattern != '\0') {
438 addstr(Pattern);
439 goto repeat;
440 }
441 break;
442
443 case ctrl('B'): /* cmd history back */
444 case ctrl('F'): /* cmd history fwd */
445 if (selecting) {
446 selecting = 0;
447 }
448
449 curritem = currentcmd();
450 item = (commandc == ctrl('F')) ? nextcmd() : prevcmd();
451 clearmsg2();
452 if (curritem == item) { /* inform user that we're at history end */
453 postmsg2("End of input field and search pattern history");
454 }
455 if (item) {
456 field = item->field;
457 setfield();
458 atfield();
459 addstr(item->text);
460 strcpy(Pattern, item->text);
461 switch (c = mygetch()) {
462 case '\r':
463 case '\n':
464 goto repeat;
465 case ctrl('F'):
466 case ctrl('B'):
467 myungetch(c);
468 atfield();
469 clrtoeol(); /* clear current field */
470 break;
471 default:
472 myungetch(c);
473 if (mygetline(Pattern, newpat, COLS - fldcolumn - 1, '\0', caseless )) {
474 strcpy (Pattern, newpat);
475 resetcmd();
476 }
477 goto repeat;
478 break;
479 }
480 }
481 return(NO);
482
483 case '\\': /* next character is not a command */
484 addch('\\'); /* display the quote character */
485
486 /* get a character from the terminal */
487 if ((commandc = mygetch()) == EOF) {
488 return(NO); /* quit */
489 }
490 addstr("\b \b"); /* erase the quote character */
491 goto ispat;
492
493 case '.':
494 postmsg("The . command has been replaced by ^Y");
495 atfield(); /* move back to the input field */
496 /* FALLTHROUGH */
497 default:
498 if (selecting && !mouse) {
499 char *c;
500
501 if ((c = strchr(dispchars, commandc)))
502 editref(c - dispchars);
503
504 /* if this is the start of a pattern */
505 } else if (isprint(commandc)) {
506 ispat:
507 if (mygetline("", newpat, COLS - fldcolumn - 1,
508 commandc, caseless) > 0) {
509 strcpy(Pattern, newpat);
510 resetcmd(); /* reset command history */
511 repeat:
512 addcmd(field, Pattern); /* add to command history */
513 if (field == CHANGE) {
514 /* prompt for the new text */
515 move(PRLINE, 0);
516 addstr(toprompt);
517 mygetline("", newpat,
518 COLS - sizeof(toprompt),
519 '\0', NO);
520 }
521 /* search for the pattern */
522 if (search() == YES) {
523 curdispline = 0;
524 ++selecting;
525
526 switch (field) {
527 case DEFINITION:
528 case FILENAME:
529 if (totallines > 1) {
530 break;
531 }
532 topline = 1;
533 editref(0);
534 break;
535 case CHANGE:
536 return(changestring());
537 }
538
539 } else if (field == FILENAME &&
540 access(newpat, READ) == 0) {
541 /* try to edit the file anyway */
542 edit(newpat, "1");
543 }
544 } else { /* no pattern--the input was erased */
545 return(NO);
546 }
547 } else { /* control character */
548 return(NO);
549 }
550 } /* switch(commandc) */
551 return(YES);
552 }
553
554 /* clear the prompt line */
555
556 static void
clearprompt(void)557 clearprompt(void)
558 {
559 move(PRLINE, 0);
560 clrtoeol();
561 }
562
563 /* read references from a file */
564
565 BOOL
readrefs(char * filename)566 readrefs(char *filename)
567 {
568 FILE *file;
569 int c;
570
571 if ((file = myfopen(filename, "rb")) == NULL) {
572 cannotopen(filename);
573 return(NO);
574 }
575 if ((c = getc(file)) == EOF) { /* if file is empty */
576 fclose(file);
577 return(NO);
578 }
579 totallines = 0;
580 disprefs = 0;
581 nextline = 1;
582 if (writerefsfound() == YES) {
583 putc(c, refsfound);
584 while ((c = getc(file)) != EOF) {
585 putc(c, refsfound);
586 }
587 fclose(file);
588 fclose(refsfound);
589 if ( (refsfound = myfopen(temp1, "rb")) == NULL) {
590 cannotopen(temp1);
591 return(NO);
592 }
593 countrefs();
594 } else
595 fclose(file);
596 return(YES);
597 }
598
599 /* change one text string to another */
600
601 static BOOL
changestring(void)602 changestring(void)
603 {
604 char newfile[PATHLEN + 1]; /* new file name */
605 char oldfile[PATHLEN + 1]; /* old file name */
606 char linenum[NUMLEN + 1]; /* file line number */
607 char msg[MSGLEN + 1]; /* message */
608 FILE *script; /* shell script file */
609 BOOL anymarked = NO; /* any line marked */
610 MOUSE *p; /* mouse data */
611 int c;
612 unsigned int i;
613 char *s;
614
615 /* open the temporary file */
616 if ((script = myfopen(temp2, "w")) == NULL) {
617 cannotopen(temp2);
618 return(NO);
619 }
620 /* create the line change indicators */
621 change = mycalloc(totallines, sizeof(*change));
622 changing = YES;
623 mousemenu();
624
625 /* until the quit command is entered */
626 for (;;) {
627 /* display the current page of lines */
628 display();
629 same:
630 atchange();
631
632 /* get a character from the terminal */
633 if ((c = mygetch()) == EOF || c == ctrl('D')) {
634 break; /* change lines */
635 }
636 if (c == ctrl('Z')) {
637 #ifdef SIGTSTP
638 kill(0, SIGTSTP);
639 goto same;
640 #else
641 break; /* change lines */
642 #endif
643 }
644 /* see if the input character is a command */
645 switch (c) {
646 case ' ': /* display next page */
647 case '+':
648 case ctrl('V'):
649 #ifdef KEY_NPAGE
650 case KEY_NPAGE:
651 #endif
652 case '-': /* display previous page */
653 #ifdef KEY_PPAGE
654 case KEY_PPAGE:
655 #endif
656 case '!': /* shell escape */
657 case '?': /* help */
658 command(c);
659 break;
660
661 case ctrl('L'): /* redraw screen */
662 #ifdef KEY_CLEAR
663 case KEY_CLEAR:
664 #endif
665 command(c);
666 goto same;
667
668 case ESC: /* don't change lines */
669 #if UNIXPC
670 if((p = getmouseaction(DUMMYCHAR)) == NULL) {
671 goto nochange; /* unknown escape sequence */
672 }
673 break;
674 #endif
675 case ctrl('G'):
676 goto nochange;
677
678 case '*': /* mark/unmark all displayed lines */
679 for (i = 0; topline + i < nextline; ++i) {
680 mark(i);
681 }
682 goto same;
683
684 case ctrl('A'): /* mark/unmark all lines */
685 for (i = 0; i < totallines; ++i) {
686 if (change[i] == NO) {
687 change[i] = YES;
688 } else {
689 change[i] = NO;
690 }
691 }
692 /* show that all have been marked */
693 seekline(totallines);
694 break;
695
696 case ctrl('X'): /* mouse selection */
697 if ((p = getmouseaction(DUMMYCHAR)) == NULL) {
698 goto same; /* unknown control sequence */
699 }
700 /* if the button number is a scrollbar tag */
701 if (p->button == '0') {
702 scrollbar(p);
703 break;
704 }
705 /* find the selected line */
706 /* note: the selection is forced into range */
707 for (i = disprefs - 1; i > 0; --i) {
708 if (p->y1 >= displine[i]) {
709 break;
710 }
711 }
712 mark(i);
713 goto same;
714
715 default:
716 {
717 /* if a line was selected */
718 char *cc;
719
720 if ((cc = strchr(dispchars, c)))
721 mark(cc - dispchars);
722
723 goto same;
724 } /* default case */
725 } /* switch(change code character) */
726 } /* for(ever) */
727
728 /* for each line containing the old text */
729 fprintf(script, "ed - <<\\!\n");
730 *oldfile = '\0';
731 seekline(1);
732 for (i = 0;
733 fscanf(refsfound, "%" PATHLEN_STR "s%*s%" NUMLEN_STR "s%*[^\n]", newfile, linenum) == 2;
734 ++i) {
735 /* see if the line is to be changed */
736 if (change[i] == YES) {
737 anymarked = YES;
738
739 /* if this is a new file */
740 if (strcmp(newfile, oldfile) != 0) {
741
742 /* make sure it can be changed */
743 if (access(newfile, WRITE) != 0) {
744 snprintf(msg, sizeof(msg), "Cannot write to file %s", newfile);
745 postmsg(msg);
746 anymarked = NO;
747 break;
748 }
749 /* if there was an old file */
750 if (*oldfile != '\0') {
751 fprintf(script, "w\n"); /* save it */
752 }
753 /* edit the new file */
754 strcpy(oldfile, newfile);
755 fprintf(script, "e %s\n", oldfile);
756 }
757 /* output substitute command */
758 fprintf(script, "%ss/", linenum); /* change */
759 for (s = Pattern; *s != '\0'; ++s) {
760 /* old text */
761 if (strchr("/\\[.^*", *s) != NULL) {
762 putc('\\', script);
763 }
764 if (caseless == YES && isalpha((unsigned char)*s)) {
765 putc('[', script);
766 if(islower((unsigned char)*s)) {
767 putc(toupper((unsigned char)*s), script);
768 putc(*s, script);
769 } else {
770 putc(*s, script);
771 putc(tolower((unsigned char)*s), script);
772 }
773 putc(']', script);
774 } else
775 putc(*s, script);
776 }
777 putc('/', script); /* to */
778 for (s = newpat; *s != '\0'; ++s) { /* new text */
779 if (strchr("/\\&", *s) != NULL) {
780 putc('\\', script);
781 }
782 putc(*s, script);
783 }
784 fprintf(script, "/gp\n"); /* and print */
785 }
786 }
787 fprintf(script, "w\nq\n!\n"); /* write and quit */
788 fclose(script);
789
790 /* if any line was marked */
791 if (anymarked == YES) {
792
793 /* edit the files */
794 clearprompt();
795 refresh();
796 fprintf(stderr, "Changed lines:\n\r");
797 execute("sh", "sh", temp2, NULL);
798 askforreturn();
799 seekline(1);
800 } else {
801 nochange:
802 clearprompt();
803 }
804 changing = NO;
805 mousemenu();
806 fclose(script);
807 free(change);
808 return(anymarked);
809 }
810
811
812 /* mark/unmark this displayed line to be changed */
813 static void
mark(unsigned int i)814 mark(unsigned int i)
815 {
816 unsigned int j;
817
818 j = i + topline - 1;
819 if (j < totallines) {
820 move(displine[i], 1);
821
822 if (change[j] == NO) {
823 change[j] = YES;
824 addch('>');
825 } else {
826 change[j] = NO;
827 addch(' ');
828 }
829 }
830 }
831
832
833 /* scrollbar actions */
834 static void
scrollbar(MOUSE * p)835 scrollbar(MOUSE *p)
836 {
837 /* reposition list if it makes sense */
838 if (totallines == 0) {
839 return;
840 }
841 switch (p->percent) {
842
843 case 101: /* scroll down one page */
844 if (nextline + mdisprefs > totallines) {
845 nextline = totallines - mdisprefs + 1;
846 }
847 break;
848
849 case 102: /* scroll up one page */
850 nextline = topline - mdisprefs;
851 if (nextline < 1) {
852 nextline = 1;
853 }
854 break;
855
856 case 103: /* scroll down one line */
857 nextline = topline + 1;
858 break;
859
860 case 104: /* scroll up one line */
861 if (topline > 1) {
862 nextline = topline - 1;
863 }
864 break;
865 default:
866 nextline = p->percent * totallines / 100;
867 }
868 seekline(nextline);
869 }
870
871
872 /* count the references found */
873 void
countrefs(void)874 countrefs(void)
875 {
876 char *subsystem; /* OGS subsystem name */
877 char *book; /* OGS book name */
878 char file[PATHLEN + 1]; /* file name */
879 char function[PATLEN + 1]; /* function name */
880 char linenum[NUMLEN + 1]; /* line number */
881 int i;
882
883 /* count the references found and find the length of the file,
884 function, and line number display fields */
885 subsystemlen = 9; /* strlen("Subsystem") */
886 booklen = 4; /* strlen("Book") */
887 filelen = 4; /* strlen("File") */
888 fcnlen = 8; /* strlen("Function") */
889 numlen = 0;
890 /* HBB NOTE 2012-04-07: it may look like we shouldn't assing tempstring here,
891 * since it's not used. But it has to be assigned just so the return value
892 * of fscanf will actually reach 4. */
893 while (EOF != (i = fscanf(refsfound,
894 "%" PATHLEN_STR "s%" PATLEN_STR "s%" NUMLEN_STR "s %" TEMPSTRING_LEN_STR "[^\n]",
895 file, function, linenum, tempstring
896 )
897 )
898 ) {
899 if ( (i != 4)
900 || !isgraph((unsigned char) *file)
901 || !isgraph((unsigned char) *function)
902 || !isdigit((unsigned char) *linenum)
903 ) {
904 postmsg("File does not have expected format");
905 totallines = 0;
906 disprefs = 0;
907 return;
908 }
909 if ((i = strlen(pathcomponents(file, dispcomponents))) > filelen) {
910 filelen = i;
911 }
912 if (ogs == YES) {
913 ogsnames(file, &subsystem, &book);
914 if ((i = strlen(subsystem)) > subsystemlen) {
915 subsystemlen = i;
916 }
917 if ((i = strlen(book)) > booklen) {
918 booklen = i;
919 }
920 }
921 if ((i = strlen(function)) > fcnlen) {
922 fcnlen = i;
923 }
924 if ((i = strlen(linenum)) > numlen) {
925 numlen = i;
926 }
927 ++totallines;
928 }
929 rewind(refsfound);
930
931 /* restrict the width of displayed columns */
932 /* HBB FIXME 20060419: magic number alert! */
933 i = (COLS - 5) / 3;
934 if (ogs == YES) {
935 i = (COLS - 7) / 5;
936 }
937 if (filelen > i && i > 4) {
938 filelen = i;
939 }
940 if (subsystemlen > i && i > 9) {
941 subsystemlen = i;
942 }
943 if (booklen > i && i > 4) {
944 booklen = i;
945 }
946 if (fcnlen > i && i > 8) {
947 fcnlen = i;
948 }
949 }
950