#include "global.h"
#include "build.h"
#include "alloc.h"
#ifdef CCS
#include "sgs.h"
#else
#include "version.h"
#endif
#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
#include <ncurses.h>
#else
#include <curses.h>
#endif
#include <setjmp.h>
#include <stdarg.h>
#include <time.h>
#include <errno.h>
#include <stdarg.h>
#ifndef HAVE_SIGSETJMP
# define sigsetjmp(a,b) setjmp(a)
# define siglongjmp(a,b) longjmp(a,b)
typedef jmp_buf sigjmp_buf;
#endif
static char const rcsid[] = "$Id: display.c,v 1.29 2006/08/20 15:00:34 broeker Exp $";
int booklen;
int *displine;
unsigned int disprefs;
int field;
int filelen;
int fcnlen;
unsigned int mdisprefs;
unsigned int nextline;
FILE *nonglobalrefs;
int numlen;
unsigned int topline = 1;
int bottomline;
long searchcount;
int subsystemlen;
unsigned int totallines;
unsigned fldcolumn;
const char dispchars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
static int fldline;
static sigjmp_buf env;
static int lastdispline;
static char lastmsg[MSGLEN + 1];
static char helpstring[] = "Press the ? key for help";
static char selprompt[] =
"Select lines to change (press the ? key for help): ";
typedef char * (*FP)(char *);
static struct {
char *text1;
char *text2;
FP findfcn;
} fields[FIELDS + 1] = {
{"Find this", "C symbol", findsymbol},
{"Find this", "global definition", finddef},
{"Find", "functions called by this function", findcalledby},
{"Find", "functions calling this function", findcalling},
{"Find this", "text string", findstring},
{"Change this", "text string", findstring},
{"Find this", "egrep pattern", findregexp},
{"Find this", "file", findfile},
{"Find", "files #including this file", findinclude},
{"Find all", "function definitions", findallfcns},
};
static RETSIGTYPE jumpback(int sig);
void
dispinit(void)
{
lastdispline = FLDLINE - 3;
mdisprefs = lastdispline - REFLINE + 1;
if (mdisprefs <= 0) {
postfatal("%s: screen too small\n", argv0);
}
if (mouse == NO && mdisprefs > strlen(dispchars))
mdisprefs = strlen(dispchars);
displine = 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;
erase();
if (refsfound == NULL) {
#if CCS
if (displayversion == YES) {
printw("cscope %s", ESG_REL);
}
else {
printw("cscope");
}
#else
printw("Cscope version %d%s", FILEVERSION, FIXVERSION);
#endif
move(0, COLS - (int) sizeof(helpstring));
addstr(helpstring);
} else if (totallines == 0) {
addstr(lastmsg);
} else {
if (changing == YES) {
printw("Change \"%s\" to \"%s\"", Pattern, newpat);
} else {
printw("%c%s: %s", toupper((unsigned char)fields[field].text2[0]),
fields[field].text2 + 1, Pattern);
}
move(2, 2);
if (ogs == YES && field != FILENAME) {
printw("%-*s ", subsystemlen, "Subsystem");
printw("%-*s ", booklen, "Book");
}
if (dispcomponents > 0)
printw("%-*s ", filelen, "File");
if (field == SYMBOL || field == CALLEDBY || field == CALLING) {
printw("%-*s ", fcnlen, "Function");
}
if (field != FILENAME) {
addstr("Line");
}
addch('\n');
if (nextline > totallines) {
seekline(1);
}
width = COLS - numlen - 3;
if (ogs == YES) {
width -= subsystemlen + booklen + 2;
}
if (dispcomponents > 0) {
width -= filelen + 1;
}
if (field == SYMBOL || field == CALLEDBY || field == CALLING) {
width -= fcnlen + 1;
}
topline = nextline;
for (disprefs = 0, screenline = REFLINE;
disprefs < mdisprefs && screenline <= lastdispline;
++disprefs, ++screenline) {
if (fscanf(refsfound, "%" PATHLEN_STR "s%" PATHLEN_STR "s%" NUMLEN_STR "s %" TEMPSTRING_LEN_STR "[^\n]", file, function,
linenum, tempstring) < 4) {
break;
}
++nextline;
displine[disprefs] = screenline;
if (mouse == YES) {
addch(' ');
} else {
printw("%c", dispchars[disprefs]);
}
if (changing == YES &&
change[topline + disprefs - 1] == YES) {
addch('>');
} else {
addch(' ');
}
if (field == FILENAME) {
printw("%-*s ", filelen, file);
} else {
if (ogs == YES) {
ogsnames(file, &subsystem, &book);
printw("%-*.*s ", subsystemlen, subsystemlen, subsystem);
printw("%-*.*s ", booklen, booklen, book);
}
if (dispcomponents > 0) {
printw("%-*.*s ", filelen, filelen,
pathcomponents(file, dispcomponents));
}
}
if (field == SYMBOL || field == CALLEDBY || field == CALLING) {
printw("%-*.*s ", fcnlen, fcnlen, function);
}
if (field == FILENAME) {
addch('\n');
continue;
}
printw("%*s ", numlen, linenum);
while ((s = strchr(tempstring, '\t')) != NULL) {
*s = ' ';
}
s = tempstring;
for (;;) {
if ((i = strlen(s)) > width) {
for (i = width; s[i] != ' ' && i > 0; --i) {
;
}
if (i == 0) {
i = width;
}
}
printw("%.*s", i, s);
s += i;
if (i < width) {
addch('\n');
}
while (*s == ' ') {
++s;
}
if (*s == '\0') {
break;
}
if (++screenline > lastdispline) {
if (topline == nextline -1) {
disprefs++;
goto endrefs;
}
while (--screenline >= displine[disprefs]) {
move(screenline, 0);
clrtoeol();
}
++screenline;
--nextline;
seekline(nextline);
goto endrefs;
}
move(screenline, COLS - width);
}
}
endrefs:
i = FLDLINE - 1;
if (screenline < i) {
addch('\n');
}
else {
move(i, 0);
}
i = totallines - nextline + 1;
bottomline = nextline;
if (i > 0) {
s = "s";
if (i == 1) {
s = "";
}
printw("* %d more line%s - press the space bar to display more *", i, s);
}
else if (topline > 1 && nextline > totallines) {
addstr("* Press the space bar to display the first lines again *");
}
}
move(FLDLINE, 0);
for (i = 0; i < FIELDS; ++i) {
printw("%s %s:\n", fields[i].text1, fields[i].text2);
}
if (changing == YES) {
move(PRLINE, 0);
addstr(selprompt);
}
drawscrollbar(topline, nextline);
refresh();
}
void
setfield(void)
{
fldline = FLDLINE + field;
fldcolumn = strlen(fields[field].text1) + strlen(fields[field].text2) + 3;
}
void
atfield(void)
{
move(fldline, fldcolumn);
}
void
atchange(void)
{
move(PRLINE, (int) sizeof(selprompt) - 1);
}
static RETSIGTYPE
jumpback(int sig)
{
signal(sig, jumpback);
siglongjmp(env, 1);
}
BOOL
search(void)
{
char *findresult = NULL;
BOOL funcexist = YES;
FINDINIT rc = NOERROR;
sighandler_t savesig;
FP f;
int c;
if (writerefsfound() == NO) {
return(NO);
}
if (linemode == NO) {
postmsg("Searching");
}
searchcount = 0;
savesig = signal(SIGINT, jumpback);
if (sigsetjmp(env, 1) == 0) {
f = fields[field].findfcn;
if (f == findregexp || f == findstring) {
findresult = (*f)(Pattern);
} else {
if ((nonglobalrefs = myfopen(temp2, "wb")) == NULL) {
cannotopen(temp2);
return(NO);
}
if ((rc = findinit(Pattern)) == NOERROR) {
(void) dbseek(0L);
findresult = (*f)(Pattern);
if (f == findcalledby)
funcexist = (*findresult == 'y');
findcleanup();
(void) fclose(nonglobalrefs);
if ((nonglobalrefs = myfopen(temp2, "rb"))
== NULL) {
cannotopen(temp2);
return(NO);
}
while ((c = getc(nonglobalrefs)) != EOF) {
(void) putc(c, refsfound);
}
}
(void) fclose(nonglobalrefs);
}
}
signal(SIGINT, savesig);
(void) lseek(symrefs, (long) 0, 0);
(void) fclose(refsfound);
if ((refsfound = myfopen(temp1, "rb")) == NULL) {
cannotopen(temp1);
return(NO);
}
nextline = 1;
totallines = 0;
disprefs = 0;
if ((c = getc(refsfound)) == EOF) {
if (findresult != NULL) {
(void) snprintf(lastmsg, sizeof(lastmsg), "Egrep %s in this pattern: %s",
findresult, Pattern);
} else if (rc == NOTSYMBOL) {
(void) snprintf(lastmsg, sizeof(lastmsg), "This is not a C symbol: %s",
Pattern);
} else if (rc == REGCMPERROR) {
(void) snprintf(lastmsg, sizeof(lastmsg), "Error in this regcomp(3) regular expression: %s",
Pattern);
} else if (funcexist == NO) {
(void) snprintf(lastmsg, sizeof(lastmsg), "Function definition does not exist: %s",
Pattern);
} else {
(void) snprintf(lastmsg, sizeof(lastmsg), "Could not find the %s: %s",
fields[field].text2, Pattern);
}
return(NO);
}
(void) ungetc(c, refsfound);
countrefs();
return(YES);
}
void
progress(char *what, long current, long max)
{
static long start;
long now;
char msg[MSGLEN + 1];
int i;
if (searchcount == 0) {
start = time(NULL);
}
if ((now = time(NULL)) - start >= 1)
{
if (linemode == NO)
{
move(MSGLINE, 0);
clrtoeol();
addstr(what);
snprintf(msg, sizeof(msg), "%ld", current);
move(MSGLINE, (COLS / 2) - (strlen(msg) / 2));
addstr(msg);
snprintf(msg, sizeof(msg), "%ld", max);
move(MSGLINE, COLS - strlen(msg));
addstr(msg);
refresh();
}
else if (verbosemode == YES)
{
snprintf(msg, sizeof(msg), "> %s %ld of %ld", what, current, max);
}
start = now;
if ((linemode == NO) && (incurses == YES))
{
move(MSGLINE, 0);
i = (float)COLS * (float)current / (float)max;
standout();
for (; i > 0; i--)
addch(inch());
standend();
refresh();
}
else
if (linemode == NO || verbosemode == YES)
postmsg(msg);
}
++searchcount;
}
void
myperror(char *text)
{
char msg[MSGLEN + 1];
char *s;
s = "Unknown error";
#ifdef HAVE_STRERROR
s = strerror(errno);
#else
if (errno < sys_nerr) {
s = sys_errlist[errno];
}
#endif
(void) snprintf(msg, sizeof(msg), "%s: %s", text, s);
postmsg(msg);
}
void
postmsg(char *msg)
{
if (linemode == YES || incurses == NO) {
(void) printf("%s\n", msg);
fflush(stdout);
}
else {
clearmsg();
addstr(msg);
refresh();
}
(void) strncpy(lastmsg, msg, sizeof(lastmsg) - 1);
}
void
clearmsg(void)
{
if (linemode == NO) {
move(MSGLINE, 0);
clrtoeol();
}
}
void
clearmsg2(void)
{
if (linemode == NO) {
move(MSGLINE + 1, 0);
clrtoeol();
}
}
void
postmsg2(char *msg)
{
if (linemode == YES) {
(void) printf("%s\n", msg);
}
else {
clearmsg2();
addstr(msg);
refresh();
}
}
void
posterr(char *msg, ...)
{
va_list ap;
char errbuf[MSGLEN];
va_start(ap, msg);
if (linemode == YES || incurses == NO)
{
(void) vfprintf(stderr, msg, ap);
(void) fputc('\n', stderr);
} else {
vsnprintf(errbuf, sizeof(errbuf), msg, ap);
postmsg2(errbuf);
}
}
void
postfatal(const char *msg, ...)
{
va_list ap;
char errbuf[MSGLEN];
va_start(ap, msg);
vsnprintf(errbuf, sizeof(errbuf), msg, ap);
if (incurses == YES) {
exitcurses();
}
fprintf(stderr,"%s",errbuf);
myexit(1);
}
void
seekline(unsigned 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);
}
BOOL
writerefsfound(void)
{
if (refsfound == NULL) {
if ((refsfound = myfopen(temp1, "wb")) == NULL) {
cannotopen(temp1);
return(NO);
}
} else {
(void) fclose(refsfound);
if ( (refsfound = myfopen(temp1, "wb")) == NULL) {
postmsg("Cannot reopen temporary file");
return(NO);
}
}
return(YES);
}