#include "global.h"
#include "version.h"
#include <curses.h>
#include <setjmp.h>
#include <string.h>
#include <errno.h>
#define displayfcn() (field <= ASSIGN)
#define MINCOLS 68
int *displine;
int disprefs;
int field;
unsigned fldcolumn;
int mdisprefs;
int selectlen;
int nextline;
int topline = 1;
int bottomline;
int totallines;
FILE *refsfound;
FILE *nonglobalrefs;
static int fldline;
static int subsystemlen;
static int booklen;
static int filelen;
static int fcnlen;
static jmp_buf env;
static int lastdispline;
static char lastmsg[MSGLEN + 1];
static int numlen;
static char depthstring[] = "Depth: ";
static char helpstring[] = "Press the ? key for help";
typedef char *(*FP)();
static struct {
char *text1;
char *text2;
FP findfcn;
enum {
EGREP,
REGCMP
} patterntype;
} fields[FIELDS + 1] = {
{ "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},
};
void
dispinit(void)
{
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;
}
(void) sprintf(newpat, "%d", mdisprefs);
selectlen = strlen(newpat);
}
displine = (int *)mymalloc(mdisprefs * sizeof (int));
}
void
display(void)
{
char *subsystem;
char *book;
char file[PATHLEN + 1];
char function[PATLEN + 1];
char linenum[NUMLEN + 1];
int screenline;
int width;
int i;
char *s;
(void) erase();
if (totallines == 0) {
if (*lastmsg != '\0') {
(void) addstr(lastmsg);
} else {
(void) printw("Cscope version %d%s", FILEVERSION,
FIXVERSION);
(void) move(0, COLS - (int)sizeof (helpstring));
(void) addstr(helpstring);
}
} else {
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);
}
if (cscopedepth > 1) {
(void) move(0, COLS - (int)sizeof (depthstring) - 2);
(void) addstr(depthstring);
(void) printw("%d", cscopedepth);
}
(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 (nextline > totallines) {
seekline(1);
}
width = COLS - selectlen - numlen - 2;
if (ogs == YES) {
width -= subsystemlen + booklen + 2;
}
if (dispcomponents > 0) {
width -= filelen + 1;
}
if (displayfcn()) {
width -= fcnlen + 1;
}
topline = nextline;
for (disprefs = 0, screenline = REFLINE;
disprefs < mdisprefs && screenline <= lastdispline;
++disprefs, ++screenline) {
if (fscanf(refsfound, "%s%s%s %[^\n]", file, function,
linenum, yytext) < 4) {
break;
}
++nextline;
displine[disprefs] = screenline;
if (!mouse) {
(void) printw("%*d", selectlen, disprefs + 1);
}
if (changing == YES &&
change[topline + disprefs - 1] == YES) {
(void) addch('>');
} else {
(void) addch(' ');
}
if (field == FILENAME) {
(void) printw("%-.*s\n", COLS - 3, file);
continue;
}
if (ogs == YES) {
ogsnames(file, &subsystem, &book);
(void) printw("%-*.*s ", subsystemlen,
subsystemlen, subsystem);
(void) printw("%-*.*s ", booklen, booklen,
book);
}
if (dispcomponents > 0) {
(void) printw("%-*.*s ", filelen, filelen,
pathcomponents(file, dispcomponents));
}
if (displayfcn()) {
(void) printw("%-*.*s ", fcnlen, fcnlen,
function);
}
(void) printw("%*s ", numlen, linenum);
while ((s = strchr(yytext, '\t')) != NULL) {
*s = ' ';
}
s = yytext;
for (;;) {
if ((i = strlen(s)) > width) {
for (i = width; s[i] != ' ' && i > 0;
--i) {
}
if (i == 0) {
i = width;
}
}
(void) printw("%.*s", i, s);
s += i;
if (i < width) {
(void) addch('\n');
}
while (*s == ' ') {
++s;
}
if (*s == '\0') {
break;
}
if (++screenline > lastdispline) {
if (topline == nextline - 1) {
goto endrefs;
}
while (--screenline >=
displine[disprefs]) {
(void) move(screenline, 0);
(void) clrtoeol();
}
++screenline;
--nextline;
seekline(nextline);
goto endrefs;
}
(void) move(screenline, COLS - width);
}
}
endrefs:
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();
}
}
(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);
}
void
setfield(void)
{
fldline = FLDLINE + field;
fldcolumn = strlen(fields[field].text1) +
strlen(fields[field].text2) + 3;
}
void
atfield(void)
{
(void) move(fldline, (int)fldcolumn);
}
SIGTYPE
jumpback(int sig)
{
longjmp(env, 1);
}
BOOL
search(void)
{
char *volatile egreperror = NULL;
FINDINIT volatile rc = NOERROR;
SIGTYPE (*volatile savesig)() = SIG_DFL;
FP f;
char *s;
int c;
if (caseless == YES) {
for (s = pattern; *s != '\0'; ++s) {
*s = tolower(*s);
}
}
if (writerefsfound() == NO) {
return (NO);
}
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);
(*f)();
findcleanup();
(void) freopen(temp2, "r", nonglobalrefs);
while ((c = getc(nonglobalrefs)) != EOF) {
(void) putc(c, refsfound);
}
}
(void) fclose(nonglobalrefs);
}
}
(void) signal(SIGINT, savesig);
(void) freopen(temp1, "r", refsfound);
nextline = 1;
totallines = 0;
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);
}
(void) ungetc(c, refsfound);
countrefs();
return (YES);
}
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);
}
void
countrefs(void)
{
char *subsystem;
char *book;
char file[PATHLEN + 1];
char function[PATLEN + 1];
char linenum[NUMLEN + 1];
int i;
subsystemlen = 9;
booklen = 4;
filelen = 4;
fcnlen = 8;
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);
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;
}
}
void
myperror(char *text)
{
char msg[MSGLEN + 1];
(void) sprintf(msg, "%s: %s", text, strerror(errno));
putmsg(msg);
}
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);
}
void
clearmsg2(void)
{
if (incurses == YES) {
(void) move(MSGLINE + 1, 0);
(void) clrtoeol();
}
}
void
putmsg2(char *msg)
{
if (incurses == NO) {
putmsg(msg);
} else {
clearmsg2();
(void) addstr(msg);
(void) refresh();
}
}
void
seekline(int line)
{
int c;
if (refsfound == NULL) {
return;
}
rewind(refsfound);
nextline = 1;
while (nextline < line && (c = getc(refsfound)) != EOF) {
if (c == '\n') {
nextline++;
}
}
}
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;
}
}
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);
}