summaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c906
1 files changed, 906 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..ca90ea9
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,906 @@
+/*===========================================================================
+ Copyright (c) 1998-2000, The Santa Cruz Operation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ *Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ *Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ *Neither name of The Santa Cruz Operation nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+ =========================================================================*/
+
+
+/* cscope - interactive C symbol cross-reference
+ *
+ * main functions
+ */
+
+#include "global.h"
+
+#include "build.h"
+#include "vp.h"
+#include "version.h" /* FILEVERSION and FIXVERSION */
+#include "scanner.h"
+#include "alloc.h"
+
+#include <stdlib.h> /* atoi */
+#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+#include <sys/types.h> /* needed by stat.h */
+#include <sys/stat.h> /* stat */
+#include <signal.h>
+
+/* defaults for unset environment variables */
+#define EDITOR "vi"
+#define HOME "/" /* no $HOME --> use root directory */
+#define SHELL "sh"
+#define LINEFLAG "+%s" /* default: used by vi and emacs */
+#define TMPDIR "/tmp"
+#ifndef DFLT_INCDIR
+#define DFLT_INCDIR "/usr/include"
+#endif
+
+static char const rcsid[] = "$Id: main.c,v 1.41 2006/08/20 15:00:34 broeker Exp $";
+
+/* note: these digraph character frequencies were calculated from possible
+ printable digraphs in the cross-reference for the C compiler */
+char dichar1[] = " teisaprnl(of)=c"; /* 16 most frequent first chars */
+char dichar2[] = " tnerpla"; /* 8 most frequent second chars
+ using the above as first chars */
+char dicode1[256]; /* digraph first character code */
+char dicode2[256]; /* digraph second character code */
+
+char *editor, *shell, *lineflag; /* environment variables */
+char *home; /* Home directory */
+BOOL lineflagafterfile;
+char *argv0; /* command name */
+BOOL compress = YES; /* compress the characters in the crossref */
+BOOL dbtruncated; /* database symbols are truncated to 8 chars */
+int dispcomponents = 1; /* file path components to display */
+#if CCS
+BOOL displayversion; /* display the C Compilation System version */
+#endif
+BOOL editallprompt = YES; /* prompt between editing files */
+unsigned int fileargc; /* file argument count */
+char **fileargv; /* file argument values */
+int fileversion; /* cross-reference file version */
+BOOL incurses = NO; /* in curses */
+BOOL invertedindex; /* the database has an inverted index */
+BOOL isuptodate; /* consider the crossref up-to-date */
+BOOL kernelmode; /* don't use DFLT_INCDIR - bad for kernels */
+BOOL linemode = NO; /* use line oriented user interface */
+BOOL verbosemode = NO; /* print extra information on line mode */
+BOOL recurse_dir = NO; /* recurse dirs when searching for src files */
+char *namefile; /* file of file names */
+BOOL ogs; /* display OGS book and subsystem names */
+char *prependpath; /* prepend path to file names */
+FILE *refsfound; /* references found file */
+char temp1[PATHLEN + 1]; /* temporary file name */
+char temp2[PATHLEN + 1]; /* temporary file name */
+char tempdirpv[PATHLEN + 1]; /* private temp directory */
+long totalterms; /* total inverted index terms */
+BOOL trun_syms; /* truncate symbols to 8 characters */
+char tempstring[TEMPSTRING_LEN + 1]; /* use this as a buffer, instead of 'yytext',
+ * which had better be left alone */
+char *tmpdir; /* temporary directory */
+
+static BOOL onesearch; /* one search only in line mode */
+static char *reflines; /* symbol reference lines file */
+
+/* Internal prototypes: */
+static void initcompress(void);
+static void longusage(void);
+static void skiplist(FILE *oldrefs);
+static void usage(void);
+
+#ifdef HAVE_FIXKEYPAD
+void fixkeypad();
+#endif
+
+#if defined(KEY_RESIZE) && !defined(__DJGPP__)
+void
+sigwinch_handler(int sig, siginfo_t *info, void *unused)
+{
+ (void) sig;
+ (void) info;
+ (void) unused;
+ ungetch(KEY_RESIZE);
+}
+#endif
+
+int
+main(int argc, char **argv)
+{
+ FILE *names; /* name file pointer */
+ int oldnum; /* number in old cross-ref */
+ char path[PATHLEN + 1]; /* file path */
+ FILE *oldrefs; /* old cross-reference file */
+ char *s;
+ int c;
+ unsigned int i;
+ pid_t pid;
+ struct stat stat_buf;
+#if defined(KEY_RESIZE) && !defined(__DJGPP__)
+ struct sigaction winch_action;
+#endif
+ mode_t orig_umask;
+
+ yyin = stdin;
+ yyout = stdout;
+ /* save the command name for messages */
+ argv0 = argv[0];
+#if defined(KEY_RESIZE) && !defined(__DJGPP__)
+ winch_action.sa_sigaction = sigwinch_handler;
+ sigemptyset(&winch_action.sa_mask);
+ winch_action.sa_flags = SA_SIGINFO;
+ sigaction(SIGWINCH,&winch_action,NULL);
+#endif
+ /* set the options */
+ while (--argc > 0 && (*++argv)[0] == '-') {
+ /* HBB 20030814: add GNU-style --help and --version options */
+ if (strequal(argv[0], "--help")
+ || strequal(argv[0], "-h")) {
+ longusage();
+ myexit(0);
+ }
+ if (strequal(argv[0], "--version")
+ || strequal(argv[0], "-V")) {
+#if CCS
+ displayversion = YES;
+#else
+ fprintf(stderr, "%s: version %d%s\n", argv0,
+ FILEVERSION, FIXVERSION);
+ myexit(0);
+#endif
+ }
+
+ for (s = argv[0] + 1; *s != '\0'; s++) {
+
+ /* look for an input field number */
+ if (isdigit((unsigned char) *s)) {
+ field = *s - '0';
+ if (field > 8) {
+ field = 8;
+ }
+ if (*++s == '\0' && --argc > 0) {
+ s = *++argv;
+ }
+ if (strlen(s) > PATLEN) {
+ postfatal("\
+cscope: pattern too long, cannot be > %d characters\n", PATLEN);
+ /* NOTREACHED */
+ }
+ strcpy(Pattern, s);
+ goto nextarg;
+ }
+ switch (*s) {
+ case '-': /* end of options */
+ --argc;
+ ++argv;
+ goto lastarg;
+ case 'b': /* only build the cross-reference */
+ buildonly = YES;
+ linemode = YES;
+ break;
+ case 'c': /* ASCII characters only in crossref */
+ compress = NO;
+ break;
+ case 'C': /* turn on caseless mode for symbol searches */
+ caseless = YES;
+ egrepcaseless(caseless); /* simulate egrep -i flag */
+ break;
+ case 'd': /* consider crossref up-to-date */
+ isuptodate = YES;
+ break;
+ case 'e': /* suppress ^E prompt between files */
+ editallprompt = NO;
+ break;
+ case 'k': /* ignore DFLT_INCDIR */
+ kernelmode = YES;
+ break;
+ case 'L':
+ onesearch = YES;
+ /* FALLTHROUGH */
+ case 'l':
+ linemode = YES;
+ break;
+ case 'v':
+ verbosemode = YES;
+ break;
+ case 'o': /* display OGS book and subsystem names */
+ ogs = YES;
+ break;
+ case 'q': /* quick search */
+ invertedindex = YES;
+ break;
+ case 'T': /* truncate symbols to 8 characters */
+ trun_syms = YES;
+ break;
+ case 'u': /* unconditionally build the cross-reference */
+ unconditional = YES;
+ break;
+ case 'U': /* assume some files have changed */
+ fileschanged = YES;
+ break;
+ case 'R':
+ recurse_dir = YES;
+ break;
+ case 'f': /* alternate cross-reference file */
+ case 'F': /* symbol reference lines file */
+ case 'i': /* file containing file names */
+ case 'I': /* #include file directory */
+ case 'p': /* file path components to display */
+ case 'P': /* prepend path to file names */
+ case 's': /* additional source file directory */
+ case 'S':
+ c = *s;
+ if (*++s == '\0' && --argc > 0) {
+ s = *++argv;
+ }
+ if (*s == '\0') {
+ fprintf(stderr, "%s: -%c option: missing or empty value\n",
+ argv0, c);
+ goto usage;
+ }
+ switch (c) {
+ case 'f': /* alternate cross-reference file */
+ reffile = s;
+ if (strlen(reffile) > sizeof(path) - 1) {
+ postfatal("\
+cscope: reffile too long, cannot be > %d characters\n", sizeof(path) - 1);
+ /* NOTREACHED */
+ }
+ strcpy(path, s);
+#ifdef SHORT_NAMES_ONLY
+ /* System V has a 14 character limit */
+ s = mybasename(path);
+ if (strlen(s) > 11) {
+ s[11] = '\0';
+ }
+#endif
+ s = path + strlen(path);
+ strcpy(s, ".in");
+ invname = my_strdup(path);
+ strcpy(s, ".po");
+ invpost = my_strdup(path);
+ break;
+ case 'F': /* symbol reference lines file */
+ reflines = s;
+ break;
+ case 'i': /* file containing file names */
+ namefile = s;
+ break;
+ case 'I': /* #include file directory */
+ includedir(s);
+ break;
+ case 'p': /* file path components to display */
+ if (*s < '0' || *s > '9' ) {
+ fprintf(stderr, "\
+%s: -p option: missing or invalid numeric value\n",
+ argv0);
+ goto usage;
+ }
+ dispcomponents = atoi(s);
+ break;
+ case 'P': /* prepend path to file names */
+ prependpath = s;
+ break;
+ case 's': /* additional source directory */
+ case 'S':
+ sourcedir(s);
+ break;
+ }
+ goto nextarg;
+ default:
+ fprintf(stderr, "%s: unknown option: -%c\n", argv0,
+ *s);
+ usage:
+ usage();
+ fprintf(stderr, "Try the -h option for more information.\n");
+ myexit(1);
+ } /* switch(option letter) */
+ } /* for(option) */
+ nextarg:
+ ;
+ } /* while(argv) */
+
+ lastarg:
+ /* read the environment */
+ editor = mygetenv("EDITOR", EDITOR);
+ editor = mygetenv("VIEWER", editor); /* use viewer if set */
+ editor = mygetenv("CSCOPE_EDITOR", editor); /* has last word */
+ home = mygetenv("HOME", HOME);
+ shell = mygetenv("SHELL", SHELL);
+ lineflag = mygetenv("CSCOPE_LINEFLAG", LINEFLAG);
+ lineflagafterfile = getenv("CSCOPE_LINEFLAG_AFTER_FILE") ? 1 : 0;
+ tmpdir = mygetenv("TMPDIR", TMPDIR);
+
+ /* XXX remove if/when clearerr() in dir.c does the right thing. */
+ if (namefile && strcmp(namefile, "-") == 0 && !buildonly) {
+ postfatal("cscope: Must use -b if file list comes from stdin\n");
+ /* NOTREACHED */
+ }
+
+ /* make sure that tmpdir exists */
+ if (lstat (tmpdir, &stat_buf)) {
+ fprintf (stderr, "\
+cscope: Temporary directory %s does not exist or cannot be accessed\n",
+ tmpdir);
+ fprintf (stderr, "\
+cscope: Please create the directory or set the environment variable\n\
+cscope: TMPDIR to a valid directory\n");
+ myexit(1);
+ }
+
+ /* create the temporary file names */
+ orig_umask = umask(S_IRWXG|S_IRWXO);
+ pid = getpid();
+ sprintf(tempdirpv, "%s/cscope.%d", tmpdir, pid);
+ if(mkdir(tempdirpv,S_IRWXU)) {
+ fprintf(stderr, "\
+cscope: Could not create private temp dir %s\n",
+ tempdirpv);
+ myexit(1);
+ }
+ umask(orig_umask);
+
+ sprintf(temp1, "%s/cscope.1", tempdirpv);
+ sprintf(temp2, "%s/cscope.2", tempdirpv);
+
+ /* if running in the foreground */
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
+ /* cleanup on the interrupt and quit signals */
+ signal(SIGINT, myexit);
+ signal(SIGQUIT, myexit);
+ }
+ /* cleanup on the hangup signal */
+ signal(SIGHUP, myexit);
+
+ /* if the database path is relative and it can't be created */
+ if (reffile[0] != '/' && access(".", WRITE) != 0) {
+
+ /* put it in the home directory if the database may not be
+ * up-to-date or doesn't exist in the relative directory,
+ * so a database in the current directory will be
+ * used instead of failing to open a non-existant database in
+ * the home directory
+ */
+ sprintf(path, "%s/%s", home, reffile);
+ if (isuptodate == NO || access(path, READ) == 0) {
+ reffile = my_strdup(path);
+ sprintf(path, "%s/%s", home, invname);
+ invname = my_strdup(path);
+ sprintf(path, "%s/%s", home, invpost);
+ invpost = my_strdup(path);
+ }
+ }
+
+ if (linemode == NO) {
+ signal(SIGINT, SIG_IGN); /* ignore interrupts */
+ signal(SIGPIPE, SIG_IGN);/* | command can cause pipe signal */
+
+ /* initialize the curses display package */
+ initscr(); /* initialize the screen */
+ entercurses();
+#if TERMINFO
+ keypad(stdscr, TRUE); /* enable the keypad */
+# ifdef HAVE_FIXKEYPAD
+ fixkeypad(); /* fix for getch() intermittently returning garbage */
+# endif
+#endif /* TERMINFO */
+#if UNIXPC
+ standend(); /* turn off reverse video */
+#endif
+ dispinit(); /* initialize display parameters */
+ setfield(); /* set the initial cursor position */
+ clearmsg(); /* clear any build progress message */
+ display(); /* display the version number and input fields */
+ }
+
+
+ /* if the cross-reference is to be considered up-to-date */
+ if (isuptodate == YES) {
+ if ((oldrefs = vpfopen(reffile, "rb")) == NULL) {
+ postfatal("cscope: cannot open file %s\n", reffile);
+ /* NOTREACHED */
+ }
+ /* get the crossref file version but skip the current directory */
+ if (fscanf(oldrefs, "cscope %d %*s", &fileversion) != 1) {
+ postfatal("cscope: cannot read file version from file %s\n",
+ reffile);
+ /* NOTREACHED */
+ }
+ if (fileversion >= 8) {
+
+ /* override these command line options */
+ compress = YES;
+ invertedindex = NO;
+
+ /* see if there are options in the database */
+ for (;;) {
+ getc(oldrefs); /* skip the blank */
+ if ((c = getc(oldrefs)) != '-') {
+ ungetc(c, oldrefs);
+ break;
+ }
+ switch (c = getc(oldrefs)) {
+ case 'c': /* ASCII characters only */
+ compress = NO;
+ break;
+ case 'q': /* quick search */
+ invertedindex = YES;
+ fscanf(oldrefs, "%ld", &totalterms);
+ break;
+ case 'T': /* truncate symbols to 8 characters */
+ dbtruncated = YES;
+ trun_syms = YES;
+ break;
+ }
+ }
+ initcompress();
+ seek_to_trailer(oldrefs);
+ }
+ /* skip the source and include directory lists */
+ skiplist(oldrefs);
+ skiplist(oldrefs);
+
+ /* get the number of source files */
+ if (fscanf(oldrefs, "%lu", &nsrcfiles) != 1) {
+ postfatal("\
+cscope: cannot read source file size from file %s\n", reffile);
+ /* NOTREACHED */
+ }
+ /* get the source file list */
+ srcfiles = mymalloc(nsrcfiles * sizeof(char *));
+ if (fileversion >= 9) {
+
+ /* allocate the string space */
+ if (fscanf(oldrefs, "%d", &oldnum) != 1) {
+ postfatal("\
+cscope: cannot read string space size from file %s\n", reffile);
+ /* NOTREACHED */
+ }
+ s = mymalloc(oldnum);
+ getc(oldrefs); /* skip the newline */
+
+ /* read the strings */
+ if (fread(s, oldnum, 1, oldrefs) != 1) {
+ postfatal("\
+cscope: cannot read source file names from file %s\n", reffile);
+ /* NOTREACHED */
+ }
+ /* change newlines to nulls */
+ for (i = 0; i < nsrcfiles; ++i) {
+ srcfiles[i] = s;
+ for (++s; *s != '\n'; ++s) {
+ ;
+ }
+ *s = '\0';
+ ++s;
+ }
+ /* if there is a file of source file names */
+ if ((namefile != NULL && (names = vpfopen(namefile, "r")) != NULL)
+ || (names = vpfopen(NAMEFILE, "r")) != NULL) {
+
+ /* read any -p option from it */
+ while (fgets(path, sizeof(path), names) != NULL && *path == '-') {
+ i = path[1];
+ s = path + 2; /* for "-Ipath" */
+ if (*s == '\0') { /* if "-I path" */
+ fgets(path, sizeof(path), names);
+ s = path;
+ }
+ switch (i) {
+ case 'p': /* file path components to display */
+ if (*s < '0' || *s > '9') {
+ posterr("cscope: -p option in file %s: missing or invalid numeric value\n", namefile);
+
+ }
+ dispcomponents = atoi(s);
+ }
+ }
+ fclose(names);
+ }
+ } else {
+ for (i = 0; i < nsrcfiles; ++i) {
+ if (!fgets(path, sizeof(path), oldrefs) ) {
+ postfatal("\
+cscope: cannot read source file name from file %s\n",
+ reffile);
+ /* NOTREACHED */
+ }
+ srcfiles[i] = my_strdup(path);
+ }
+ }
+ fclose(oldrefs);
+ } else {
+ /* save the file arguments */
+ fileargc = argc;
+ fileargv = argv;
+
+ /* get source directories from the environment */
+ if ((s = getenv("SOURCEDIRS")) != NULL) {
+ sourcedir(s);
+ }
+ /* make the source file list */
+ srcfiles = mymalloc(msrcfiles * sizeof(char *));
+ makefilelist();
+ if (nsrcfiles == 0) {
+ postfatal("cscope: no source files found\n");
+ /* NOTREACHED */
+ }
+ /* get include directories from the environment */
+ if ((s = getenv("INCLUDEDIRS")) != NULL) {
+ includedir(s);
+ }
+ /* add /usr/include to the #include directory list,
+ but not in kernelmode... kernels tend not to use it. */
+ if (kernelmode == NO) {
+ includedir(DFLT_INCDIR);
+ }
+
+ /* initialize the C keyword table */
+ initsymtab();
+
+ /* Tell build.c about the filenames to create: */
+ setup_build_filenames(reffile);
+
+ /* build the cross-reference */
+ initcompress();
+ if (linemode == NO || verbosemode == YES) /* display if verbose as well */
+ postmsg("Building cross-reference...");
+ build();
+ if (linemode == NO )
+ clearmsg(); /* clear any build progress message */
+ if (buildonly == YES) {
+ myexit(0);
+ }
+ }
+ opendatabase();
+
+ /* if using the line oriented user interface so cscope can be a
+ subprocess to emacs or samuel */
+ if (linemode == YES) {
+ if (*Pattern != '\0') { /* do any optional search */
+ if (search() == YES) {
+ /* print the total number of lines in
+ * verbose mode */
+ if (verbosemode == YES)
+ printf("cscope: %d lines\n",
+ totallines);
+
+ while ((c = getc(refsfound)) != EOF)
+ putchar(c);
+ }
+ }
+ if (onesearch == YES)
+ myexit(0);
+
+ for (;;) {
+ char buf[PATLEN + 2];
+
+ printf(">> ");
+ fflush(stdout);
+ if (fgets(buf, sizeof(buf), stdin) == NULL) {
+ myexit(0);
+ }
+ /* remove any trailing newline character */
+ if (*(s = buf + strlen(buf) - 1) == '\n') {
+ *s = '\0';
+ }
+ switch (*buf) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': /* samuel only */
+ field = *buf - '0';
+ strcpy(Pattern, buf + 1);
+ search();
+ printf("cscope: %d lines\n", totallines);
+ while ((c = getc(refsfound)) != EOF) {
+ putchar(c);
+ }
+ break;
+
+ case 'c': /* toggle caseless mode */
+ case ctrl('C'):
+ if (caseless == NO) {
+ caseless = YES;
+ } else {
+ caseless = NO;
+ }
+ egrepcaseless(caseless);
+ break;
+
+ case 'r': /* rebuild database cscope style */
+ case ctrl('R'):
+ freefilelist();
+ makefilelist();
+ /* FALLTHROUGH */
+
+ case 'R': /* rebuild database samuel style */
+ rebuild();
+ putchar('\n');
+ break;
+
+ case 'C': /* clear file names */
+ freefilelist();
+ putchar('\n');
+ break;
+
+ case 'F': /* add a file name */
+ strcpy(path, buf + 1);
+ if (infilelist(path) == NO &&
+ (s = inviewpath(path)) != NULL) {
+ addsrcfile(s);
+ }
+ putchar('\n');
+ break;
+
+ case 'q': /* quit */
+ case ctrl('D'):
+ case ctrl('Z'):
+ myexit(0);
+
+ default:
+ fprintf(stderr, "cscope: unknown command '%s'\n", buf);
+ break;
+ }
+ }
+ /* NOTREACHED */
+ }
+ /* pause before clearing the screen if there have been error messages */
+ if (errorsfound == YES) {
+ errorsfound = NO;
+ askforreturn();
+ }
+ /* do any optional search */
+ if (*Pattern != '\0') {
+ atfield(); /* move to the input field */
+ command(ctrl('Y')); /* search */
+ } else if (reflines != NULL) {
+ /* read any symbol reference lines file */
+ readrefs(reflines);
+ }
+ display(); /* update the display */
+
+ for (;;) {
+ if (!selecting)
+ atfield(); /* move to the input field */
+
+ /* exit if the quit command is entered */
+ if ((c = mygetch()) == EOF || c == ctrl('D') || c == ctrl('Z')) {
+ break;
+ }
+ /* execute the commmand, updating the display if necessary */
+ if (command(c) == YES) {
+ display();
+ }
+
+ if (selecting) {
+ move(displine[curdispline], 0);
+ refresh();
+ }
+ }
+ /* cleanup and exit */
+ myexit(0);
+ /* NOTREACHED */
+ return 0; /* avoid warning... */
+}
+
+void
+cannotopen(char *file)
+{
+ posterr("Cannot open file %s", file);
+}
+
+/* FIXME MTE - should use postfatal here */
+void
+cannotwrite(char *file)
+{
+#if HAVE_SNPRINTF
+ char msg[MSGLEN + 1];
+
+ snprintf(msg, sizeof(msg), "Removed file %s because write failed", file);
+#else
+ char *msg = mymalloc(50 + strlen(file));
+
+ sprintf(msg, "Removed file %s because write failed", file);
+#endif
+
+ myperror(msg); /* display the reason */
+
+#if !HAVE_SNPRINTF
+ free(msg);
+#endif
+
+ unlink(file);
+ myexit(1); /* calls exit(2), which closes files */
+}
+
+
+/* set up the digraph character tables for text compression */
+static void
+initcompress(void)
+{
+ int i;
+
+ if (compress == YES) {
+ for (i = 0; i < 16; ++i) {
+ dicode1[(unsigned char) (dichar1[i])] = i * 8 + 1;
+ }
+ for (i = 0; i < 8; ++i) {
+ dicode2[(unsigned char) (dichar2[i])] = i + 1;
+ }
+ }
+}
+
+/* skip the list in the cross-reference file */
+
+static void
+skiplist(FILE *oldrefs)
+{
+ int i;
+
+ if (fscanf(oldrefs, "%d", &i) != 1) {
+ postfatal("cscope: cannot read list size from file %s\n", reffile);
+ /* NOTREACHED */
+ }
+ while (--i >= 0) {
+ if (fscanf(oldrefs, "%*s") != 0) {
+ postfatal("cscope: cannot read list name from file %s\n", reffile);
+ /* NOTREACHED */
+ }
+ }
+}
+
+
+/* enter curses mode */
+void
+entercurses(void)
+{
+ incurses = YES;
+#ifndef __MSDOS__ /* HBB 20010313 */
+ nonl(); /* don't translate an output \n to \n\r */
+#endif
+ cbreak(); /* single character input */
+ noecho(); /* don't echo input characters */
+ clear(); /* clear the screen */
+ mouseinit(); /* initialize any mouse interface */
+ drawscrollbar(topline, nextline);
+}
+
+
+/* exit curses mode */
+void
+exitcurses(void)
+{
+ /* clear the bottom line */
+ move(LINES - 1, 0);
+ clrtoeol();
+ refresh();
+
+ /* exit curses and restore the terminal modes */
+ endwin();
+ incurses = NO;
+
+ /* restore the mouse */
+ mousecleanup();
+ fflush(stdout);
+}
+
+
+/* normal usage message */
+static void
+usage(void)
+{
+ fprintf(stderr, "Usage: cscope [-bcCdehklLqRTuUvV] [-f file] [-F file] [-i file] [-I dir] [-s dir]\n");
+ fprintf(stderr, " [-p number] [-P path] [-[0-8] pattern] [source files]\n");
+}
+
+
+/* long usage message */
+static void
+longusage(void)
+{
+ usage();
+ fprintf(stderr, "\
+\n\
+-b Build the cross-reference only.\n\
+-C Ignore letter case when searching.\n\
+-c Use only ASCII characters in the cross-ref file (don't compress).\n\
+-d Do not update the cross-reference.\n\
+-e Suppress the <Ctrl>-e command prompt between files.\n\
+-F symfile Read symbol reference lines from symfile.\n\
+-f reffile Use reffile as cross-ref file name instead of %s.\n",
+ REFFILE);
+ fprintf(stderr, "\
+-h This help screen.\n\
+-I incdir Look in incdir for any #include files.\n\
+-i namefile Browse through files listed in namefile, instead of %s\n",
+ NAMEFILE);
+ fprintf(stderr, "\
+-k Kernel Mode - don't use %s for #include files.\n",
+ DFLT_INCDIR);
+ fputs("\
+-L Do a single search with line-oriented output.\n\
+-l Line-oriented interface.\n\
+-num pattern Go to input field num (counting from 0) and find pattern.\n\
+-P path Prepend path to relative file names in pre-built cross-ref file.\n\
+-p n Display the last n file path components.\n\
+-q Build an inverted index for quick symbol searching.\n\
+-R Recurse directories for files.\n\
+-s dir Look in dir for additional source files.\n\
+-T Use only the first eight characters to match against C symbols.\n\
+-U Check file time stamps.\n\
+-u Unconditionally build the cross-reference file.\n\
+-v Be more verbose in line mode.\n\
+-V Print the version number.\n\
+\n\
+Please see the manpage for more information.\n",
+ stderr);
+}
+
+/* cleanup and exit */
+
+void
+myexit(int sig)
+{
+ /* HBB 20010313; close file before unlinking it. Unix may not care
+ * about that, but DOS absolutely needs it */
+ if (refsfound != NULL)
+ fclose(refsfound);
+
+ /* remove any temporary files */
+ if (temp1[0] != '\0') {
+ unlink(temp1);
+ unlink(temp2);
+ rmdir(tempdirpv);
+ }
+ /* restore the terminal to its original mode */
+ if (incurses == YES) {
+ exitcurses();
+ }
+ /* dump core for debugging on the quit signal */
+ if (sig == SIGQUIT) {
+ abort();
+ }
+ /* HBB 20000421: be nice: free allocated data */
+ freefilelist();
+ freeinclist();
+ freesrclist();
+ freecrossref();
+ free_newbuildfiles();
+
+ exit(sig);
+}