/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2015 Gary Mills */ /* * cscope - interactive C symbol cross-reference * * display functions */ #include "global.h" #include "version.h" /* FILEVERSION and FIXVERSION */ #include /* COLS and LINES */ #include /* jmp_buf */ #include #include /* see if the function column should be displayed */ #define displayfcn() (field <= ASSIGN) #define MINCOLS 68 /* minimum columns for 3 digit Lines message numbers */ int *displine; /* screen line of displayed reference */ int disprefs; /* displayed references */ int field; /* input field */ unsigned fldcolumn; /* input field column */ int mdisprefs; /* maximum displayed references */ int selectlen; /* selection number field length */ int nextline; /* next line to be shown */ int topline = 1; /* top line of page */ int bottomline; /* bottom line of page */ int totallines; /* total reference lines */ FILE *refsfound; /* references found file */ FILE *nonglobalrefs; /* non-global references file */ static int fldline; /* input field line */ static int subsystemlen; /* OGS subsystem name display */ /* field length */ static int booklen; /* OGS book name display field length */ static int filelen; /* file name display field length */ static int fcnlen; /* function name display field length */ static jmp_buf env; /* setjmp/longjmp buffer */ static int lastdispline; /* last displayed reference line */ static char lastmsg[MSGLEN + 1]; /* last message displayed */ static int numlen; /* line number display field length */ static char depthstring[] = "Depth: "; static char helpstring[] = "Press the ? key for help"; typedef char *(*FP)(); /* pointer to function returning a character pointer */ static struct { char *text1; char *text2; FP findfcn; enum { EGREP, REGCMP } patterntype; } fields[FIELDS + 1] = { /* last search is not part of the cscope display */ { "Find this", "C symbol", (FP) findsymbol, REGCMP}, { "Find this", "definition", (FP) finddef, REGCMP}, { "Find", "functions called by this function", (FP) findcalledby, REGCMP}, { "Find", "functions calling this function", (FP) findcalling, REGCMP}, { "Find", "assignments to", (FP) findassignments, REGCMP}, { "Change this", "grep pattern", findgreppat, EGREP}, { "Find this", "egrep pattern", findegreppat, EGREP}, { "Find this", "file", (FP) findfile, REGCMP}, { "Find", "files #including this file", (FP) findinclude, REGCMP}, { "Find all", "function/class definitions", (FP) findallfcns, REGCMP}, }; /* initialize display parameters */ void dispinit(void) { /* calculate the maximum displayed reference lines */ lastdispline = FLDLINE - 2; mdisprefs = lastdispline - REFLINE + 1; if (mdisprefs <= 0) { (void) printw("cscope: window must be at least %d lines high", FIELDS + 6); myexit(1); } if (COLS < MINCOLS) { (void) printw("cscope: window must be at least %d columns wide", MINCOLS); myexit(1); } if (!mouse) { if (returnrequired == NO && mdisprefs > 9) { mdisprefs = 9; /* single digit selection number */ } /* calculate the maximum selection number width */ (void) sprintf(newpat, "%d", mdisprefs); selectlen = strlen(newpat); } /* allocate the displayed line array */ displine = (int *)mymalloc(mdisprefs * sizeof (int)); } /* display a page of the references */ void display(void) { char *subsystem; /* OGS subsystem name */ char *book; /* OGS book name */ char file[PATHLEN + 1]; /* file name */ char function[PATLEN + 1]; /* function name */ char linenum[NUMLEN + 1]; /* line number */ int screenline; /* screen line number */ int width; /* source line display width */ int i; char *s; (void) erase(); /* if there are no references */ if (totallines == 0) { if (*lastmsg != '\0') { (void) addstr(lastmsg); /* redisplay any message */ } else { (void) printw("Cscope version %d%s", FILEVERSION, FIXVERSION); (void) move(0, COLS - (int)sizeof (helpstring)); (void) addstr(helpstring); } } else { /* display the pattern */ if (changing == YES) { (void) printw("Change \"%s\" to \"%s\"", pattern, newpat); } else { (void) printw("%c%s: %s", toupper(fields[field].text2[0]), fields[field].text2 + 1, pattern); } /* display the cscope invocation nesting depth */ if (cscopedepth > 1) { (void) move(0, COLS - (int)sizeof (depthstring) - 2); (void) addstr(depthstring); (void) printw("%d", cscopedepth); } /* display the column headings */ (void) move(2, selectlen + 1); if (ogs == YES && field != FILENAME) { (void) printw("%-*s ", subsystemlen, "Subsystem"); (void) printw("%-*s ", booklen, "Book"); } if (dispcomponents > 0) { (void) printw("%-*s ", filelen, "File"); } if (displayfcn()) { (void) printw("%-*s ", fcnlen, "Function"); } if (field != FILENAME) { (void) addstr("Line"); } (void) addch('\n'); /* if at end of file go back to beginning */ if (nextline > totallines) { seekline(1); } /* calculate the source text column */ width = COLS - selectlen - numlen - 2; if (ogs == YES) { width -= subsystemlen + booklen + 2; } if (dispcomponents > 0) { width -= filelen + 1; } if (displayfcn()) { width -= fcnlen + 1; } /* * until the max references have been displayed or * there is no more room */ topline = nextline; for (disprefs = 0, screenline = REFLINE; disprefs < mdisprefs && screenline <= lastdispline; ++disprefs, ++screenline) { /* read the reference line */ if (fscanf(refsfound, "%s%s%s %[^\n]", file, function, linenum, yytext) < 4) { break; } ++nextline; displine[disprefs] = screenline; /* if no mouse, display the selection number */ if (!mouse) { (void) printw("%*d", selectlen, disprefs + 1); } /* display any change mark */ if (changing == YES && change[topline + disprefs - 1] == YES) { (void) addch('>'); } else { (void) addch(' '); } /* display the file name */ if (field == FILENAME) { (void) printw("%-.*s\n", COLS - 3, file); continue; } /* if OGS, display the subsystem and book names */ if (ogs == YES) { ogsnames(file, &subsystem, &book); (void) printw("%-*.*s ", subsystemlen, subsystemlen, subsystem); (void) printw("%-*.*s ", booklen, booklen, book); } /* display the requested path components */ if (dispcomponents > 0) { (void) printw("%-*.*s ", filelen, filelen, pathcomponents(file, dispcomponents)); } /* display the function name */ if (displayfcn()) { (void) printw("%-*.*s ", fcnlen, fcnlen, function); } /* display the line number */ (void) printw("%*s ", numlen, linenum); /* there may be tabs in egrep output */ while ((s = strchr(yytext, '\t')) != NULL) { *s = ' '; } /* display the source line */ s = yytext; for (;;) { /* see if the source line will fit */ if ((i = strlen(s)) > width) { /* find the nearest blank */ for (i = width; s[i] != ' ' && i > 0; --i) { } if (i == 0) { i = width; /* no blank */ } } /* print up to this point */ (void) printw("%.*s", i, s); s += i; /* if line didn't wrap around */ if (i < width) { /* go to next line */ (void) addch('\n'); } /* skip blanks */ while (*s == ' ') { ++s; } /* see if there is more text */ if (*s == '\0') { break; } /* if the source line is too long */ if (++screenline > lastdispline) { /* * if this is the first displayed line, * display what will fit on the screen */ if (topline == nextline - 1) { goto endrefs; } /* erase the reference */ while (--screenline >= displine[disprefs]) { (void) move(screenline, 0); (void) clrtoeol(); } ++screenline; /* * go back to the beginning of this * reference */ --nextline; seekline(nextline); goto endrefs; } /* indent the continued source line */ (void) move(screenline, COLS - width); } } endrefs: /* check for more references */ bottomline = nextline; if (bottomline - topline < totallines) { (void) move(FLDLINE - 1, 0); (void) standout(); (void) printw("%*s", selectlen + 1, ""); if (bottomline - 1 == topline) { (void) printw("Line %d", topline); } else { (void) printw("Lines %d-%d", topline, bottomline - 1); } (void) printw(" of %d, press the space bar to " "display next lines", totallines); (void) standend(); } } /* display the input fields */ (void) move(FLDLINE, 0); for (i = 0; i < FIELDS; ++i) { (void) printw("%s %s:\n", fields[i].text1, fields[i].text2); } drawscrollbar(topline, nextline, totallines); } /* set the cursor position for the field */ void setfield(void) { fldline = FLDLINE + field; fldcolumn = strlen(fields[field].text1) + strlen(fields[field].text2) + 3; } /* move to the current input field */ void atfield(void) { (void) move(fldline, (int)fldcolumn); } /* search for the symbol or text pattern */ /*ARGSUSED*/ SIGTYPE jumpback(int sig) { longjmp(env, 1); } BOOL search(void) { char *volatile egreperror = NULL; /* egrep error message */ FINDINIT volatile rc = NOERROR; /* findinit return code */ SIGTYPE (*volatile savesig)() = SIG_DFL; /* old value of signal */ FP f; /* searching function */ char *s; int c; /* note: the pattern may have been a cscope argument */ if (caseless == YES) { for (s = pattern; *s != '\0'; ++s) { *s = tolower(*s); } } /* open the references found file for writing */ if (writerefsfound() == NO) { return (NO); } /* find the pattern - stop on an interrupt */ if (linemode == NO) { putmsg("Searching"); } initprogress(); if (setjmp(env) == 0) { savesig = signal(SIGINT, jumpback); f = fields[field].findfcn; if (fields[field].patterntype == EGREP) { egreperror = (*f)(pattern); } else { if ((nonglobalrefs = fopen(temp2, "w")) == NULL) { cannotopen(temp2); return (NO); } if ((rc = findinit()) == NOERROR) { (void) dbseek(0L); /* goto the first block */ (*f)(); findcleanup(); /* append the non-global references */ (void) freopen(temp2, "r", nonglobalrefs); while ((c = getc(nonglobalrefs)) != EOF) { (void) putc(c, refsfound); } } (void) fclose(nonglobalrefs); } } (void) signal(SIGINT, savesig); /* reopen the references found file for reading */ (void) freopen(temp1, "r", refsfound); nextline = 1; totallines = 0; /* see if it is empty */ if ((c = getc(refsfound)) == EOF) { if (egreperror != NULL) { (void) sprintf(lastmsg, "Egrep %s in this pattern: %s", egreperror, pattern); } else if (rc == NOTSYMBOL) { (void) sprintf(lastmsg, "This is not a C symbol: %s", pattern); } else if (rc == REGCMPERROR) { (void) sprintf(lastmsg, "Error in this regcmp(3C) regular expression: %s", pattern); } else { (void) sprintf(lastmsg, "Could not find the %s: %s", fields[field].text2, pattern); } return (NO); } /* put back the character read */ (void) ungetc(c, refsfound); countrefs(); return (YES); } /* open the references found file for writing */ BOOL writerefsfound(void) { if (refsfound == NULL) { if ((refsfound = fopen(temp1, "w")) == NULL) { cannotopen(temp1); return (NO); } } else if (freopen(temp1, "w", refsfound) == NULL) { putmsg("Cannot reopen temporary file"); return (NO); } return (YES); } /* count the references found */ void countrefs(void) { char *subsystem; /* OGS subsystem name */ char *book; /* OGS book name */ char file[PATHLEN + 1]; /* file name */ char function[PATLEN + 1]; /* function name */ char linenum[NUMLEN + 1]; /* line number */ int i; /* * count the references found and find the length of the file, * function, and line number display fields */ subsystemlen = 9; /* strlen("Subsystem") */ booklen = 4; /* strlen("Book") */ filelen = 4; /* strlen("File") */ fcnlen = 8; /* strlen("Function") */ numlen = 0; while ((i = fscanf(refsfound, "%250s%250s%6s %5000[^\n]", file, function, linenum, yytext)) != EOF) { if (i != 4 || !isgraph(*file) || !isgraph(*function) || !isdigit(*linenum)) { putmsg("File does not have expected format"); totallines = 0; return; } if ((i = strlen(pathcomponents(file, dispcomponents))) > filelen) { filelen = i; } if (ogs == YES) { ogsnames(file, &subsystem, &book); if ((i = strlen(subsystem)) > subsystemlen) { subsystemlen = i; } if ((i = strlen(book)) > booklen) { booklen = i; } } if ((i = strlen(function)) > fcnlen) { fcnlen = i; } if ((i = strlen(linenum)) > numlen) { numlen = i; } ++totallines; } rewind(refsfound); /* restrict the width of displayed columns */ i = (COLS - 5) / 3; if (ogs == YES) { i = (COLS - 7) / 5; } if (filelen > i && i > 4) { filelen = i; } if (subsystemlen > i && i > 9) { subsystemlen = i; } if (booklen > i && i > 4) { booklen = i; } if (fcnlen > i && i > 8) { fcnlen = i; } } /* print error message on system call failure */ void myperror(char *text) { char msg[MSGLEN + 1]; /* message */ (void) sprintf(msg, "%s: %s", text, strerror(errno)); putmsg(msg); } /* putmsg clears the message line and prints the message */ void putmsg(char *msg) { if (incurses == NO) { *msg = tolower(*msg); (void) fprintf(stderr, "cscope: %s\n", msg); } else { (void) move(MSGLINE, 0); (void) clrtoeol(); (void) addstr(msg); (void) refresh(); } (void) strncpy(lastmsg, msg, sizeof (lastmsg) - 1); } /* clearmsg2 clears the second message line */ void clearmsg2(void) { if (incurses == YES) { (void) move(MSGLINE + 1, 0); (void) clrtoeol(); } } /* putmsg2 clears the second message line and prints the message */ void putmsg2(char *msg) { if (incurses == NO) { putmsg(msg); } else { clearmsg2(); (void) addstr(msg); (void) refresh(); } } /* position the references found file at the specified line */ void seekline(int line) { int c; /* verify that there is a references found file */ if (refsfound == NULL) { return; } /* go to the beginning of the file */ rewind(refsfound); /* find the requested line */ nextline = 1; while (nextline < line && (c = getc(refsfound)) != EOF) { if (c == '\n') { nextline++; } } } /* get the OGS subsystem and book names */ void ogsnames(char *file, char **subsystem, char **book) { static char buf[PATHLEN + 1]; char *s, *slash; *subsystem = *book = ""; (void) strcpy(buf, file); s = buf; if (*s == '/') { ++s; } while ((slash = strchr(s, '/')) != NULL) { *slash = '\0'; if ((int)strlen(s) >= 3 && strncmp(slash - 3, ".ss", 3) == 0) { *subsystem = s; s = slash + 1; if ((slash = strchr(s, '/')) != NULL) { *book = s; *slash = '\0'; } break; } s = slash + 1; } } /* get the requested path components */ char * pathcomponents(char *path, int components) { int i; char *s; s = path + strlen(path) - 1; for (i = 0; i < components; ++i) { while (s > path && *--s != '/') { ; } } if (s > path && *s == '/') { ++s; } return (s); }