root/gtags-cscope/gtags-cscope.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sigwinch_handler
  2. main
  3. cannotopen
  4. cannotwrite
  5. entercurses
  6. exitcurses
  7. usage
  8. longusage
  9. myexit

   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 
  34 /**     @file
  35  *      @NAME{gtags-cscope} - interactive C symbol cross-reference (@NAME{cscope})
  36  *
  37  *      main functions
  38  */
  39 
  40 #include "global-cscope.h"
  41 
  42 #include "build.h"
  43 #include "version-cscope.h"     /* FILEVERSION and FIXVERSION */
  44 
  45 /* for libutil */
  46 #include "env.h"
  47 #include "gparam.h"
  48 #include "path.h"
  49 #include "test.h"
  50 #include "version.h"
  51 /* usage */
  52 #include "const.h"
  53 
  54 #include <stdlib.h>     /* atoi */
  55 #include <unistd.h>
  56 #if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
  57 #include <ncurses.h>
  58 #else
  59 #include <curses.h>
  60 #endif
  61 #include <sys/types.h>  /* needed by stat.h */
  62 #include <sys/stat.h>   /* stat */
  63 #include <signal.h>
  64 
  65 #if defined(_WIN32) && !defined(__CYGWIN__)
  66 #define S_IRWXG 0070
  67 #define S_IRWXO 0007
  68 #define mkdir(path,mode) mkdir(path)
  69 #endif
  70 
  71 /** @name defaults for unset environment variables */
  72 /** @{ */
  73 /** text editor */
  74 #if defined(__DJGPP__) || (defined(_WIN32) && !defined(__CYGWIN__))
  75 #define EDITOR  "tde"
  76 #else
  77 #define EDITOR  "vi"
  78 #endif
  79 
  80 /** no @NAME{\$HOME} --\> use root directory */
  81 #define HOME    "/"
  82 /** shell executable */
  83 #define SHELL   "sh"
  84 
  85 /** default: used by @NAME{vi} and @NAME{emacs} */
  86 #define LINEFLAG "+%s"
  87 /** temp dir */
  88 #define TMPDIR  "/tmp"
  89 /** @} */
  90 
  91 static char const rcsid[] = "$Id: gtags-cscope.c,v 1.27 2012/10/13 07:02:06 shigio Exp $";
  92 
  93 char    *editor, *shell, *lineflag;     /**< environment variables */
  94 char    *global_command;        /**< @FILE{global} by default */
  95 char    *gtags_command;         /**< @FILE{gtags} by default */
  96 char    *home;                  /**< Home directory */
  97 BOOL    lineflagafterfile;
  98 char    *argv0;                 /**< command name */
  99 int     dispcomponents = 1;     /**< file path components to display */
 100 #if CCS
 101 BOOL    displayversion;         /**< display the C Compilation System version */
 102 #endif
 103 BOOL    editallprompt = YES;    /**< prompt between editing files */
 104 BOOL    incurses = NO;          /**< in @NAME{curses} */
 105 BOOL    isuptodate;             /**< consider the crossref up-to-date */
 106 BOOL    linemode = NO;          /**< use line oriented user interface */
 107 BOOL    verbosemode = NO;       /**< print extra information on line mode */
 108 BOOL    absolutepath = NO;      /**< print absolute path name */
 109 BOOL    ignoresigint = NO;      /**< ignore @NAME{SIGINT} signal */
 110 BOOL    ogs;                    /**< display @NAME{OGS} book and subsystem names */
 111 char    *prependpath;           /**< prepend path to file names */
 112 FILE    *refsfound;             /**< references found file */
 113 char    temp1[PATHLEN + 1];     /**< temporary file name */
 114 char    temp2[PATHLEN + 1];     /**< temporary file name */
 115 char    tempdirpv[PATHLEN + 1]; /**< private temp directory */
 116 char    tempstring[TEMPSTRING_LEN + 1]; /**< use this as a buffer, instead of @CODE{yytext}, 
 117                                  * which had better be left alone */
 118 char    *tmpdir;                /**< temporary directory */
 119 
 120 static  BOOL    onesearch;              /**< one search only in line mode */
 121 static  char    *reflines;              /**< symbol reference lines file */
 122 
 123 /* Internal prototypes: */
 124 static  void    longusage(void);
 125 static  void    usage(void);
 126 int     qflag;
 127 
 128 #ifdef HAVE_FIXKEYPAD
 129 void    fixkeypad();
 130 #endif
 131 
 132 #if defined(KEY_RESIZE) && defined(SIGWINCH)
 133 void 
 134 sigwinch_handler(int sig, siginfo_t *info, void *unused)
 135 {
 136     (void) sig;
 137     (void) info;
 138     (void) unused;
 139     if(incurses == YES)
 140         ungetch(KEY_RESIZE);
 141 }
 142 #endif
 143 
 144 int
 145 main(int argc, char **argv)
 146 {
 147     char *s;
 148     int c;
 149     pid_t pid;
 150     struct stat stat_buf;
 151     mode_t orig_umask;
 152 #if defined(KEY_RESIZE) && defined(SIGWINCH)
 153     struct sigaction winch_action;
 154 #endif
 155         
 156     /* save the command name for messages */
 157     argv0 = argv[0];
 158 
 159     /* set the options */
 160     while (--argc > 0 && (*++argv)[0] == '-') {
 161         /* HBB 20030814: add GNU-style --help and --version options */
 162         if (strequal(argv[0], "--help")
 163             || strequal(argv[0], "-h")) {
 164             longusage();
 165             myexit(0);
 166         }
 167         if (strequal(argv[0], "--version")
 168             || strequal(argv[0], "-V")) {
 169 #if CCS
 170             displayversion = YES;
 171 #else
 172             fprintf(stderr, "%s: %s (based on cscope version %d%s)\n", argv0, get_version(),
 173                     FILEVERSION, FIXVERSION);
 174             myexit(0);
 175 #endif
 176         }
 177 
 178         for (s = argv[0] + 1; *s != '\0'; s++) {
 179                         
 180             /* look for an input field number */
 181             if (isdigit((unsigned char) *s)) {
 182                 field = *s - '0';
 183                 if (field > 8) {
 184                     field = 8;
 185                 }
 186                 if (*++s == '\0' && --argc > 0) {
 187                     s = *++argv;
 188                 }
 189                 if (strlen(s) > PATLEN) {
 190                     postfatal("\
 191 gtags-cscope: pattern too long, cannot be > %d characters\n", PATLEN);
 192                     /* NOTREACHED */
 193                 }
 194                 strcpy(Pattern, s);
 195                 goto nextarg;
 196             }
 197             switch (*s) {
 198             case '-':   /* end of options */
 199                 --argc;
 200                 ++argv;
 201                 goto lastarg;
 202             case 'a':   /* absolute path name */
 203                 absolutepath = YES;
 204                 break;
 205             case 'b':   /* only build the cross-reference */
 206                 buildonly = YES;
 207                 linemode  = YES;
 208                 break;
 209             case 'c':   /* ASCII characters only in crossref */
 210                 /* N/A */
 211                 break;
 212             case 'C':   /* turn on caseless mode for symbol searches */
 213                 caseless = YES;
 214                 break;
 215             case 'd':   /* consider crossref up-to-date */
 216                 isuptodate = YES;
 217                 break;
 218             case 'e':   /* suppress ^E prompt between files */
 219                 editallprompt = NO;
 220                 break;
 221             case 'i':   /* ignore SIGINT signal */
 222                 ignoresigint = YES;
 223                 break;
 224             case 'k':   /* ignore DFLT_INCDIR */
 225                 /* N/A */
 226                 break;
 227             case 'L':
 228                 onesearch = YES;
 229                 /* FALLTHROUGH */
 230             case 'l':
 231                 linemode = YES;
 232                 break;
 233             case 'v':
 234                 verbosemode = YES;
 235                 break;
 236             case 'o':   /* display OGS book and subsystem names */
 237                 ogs = YES;
 238                 break;
 239             case 'q':   /* quick search */
 240                 /* N/A */
 241                 break;
 242             case 'T':   /* truncate symbols to 8 characters */
 243                 /* N/A */
 244                 break;
 245             case 'u':   /* unconditionally build the cross-reference */
 246                 /* N/A */
 247                 break;
 248             case 'U':   /* assume some files have changed */
 249                 /* N/A */
 250                 break;
 251             case 'R':
 252                 usage();
 253                 break;
 254             case 'f':   /* alternate cross-reference file */
 255             case 'F':   /* symbol reference lines file */
 256 /*          case 'i':   /* file containing file names */
 257             case 'I':   /* #include file directory */
 258             case 'p':   /* file path components to display */
 259             case 'P':   /* prepend path to file names */
 260             case 's':   /* additional source file directory */
 261             case 'S':
 262                 c = *s;
 263                 if (*++s == '\0' && --argc > 0) {
 264                     s = *++argv;
 265                 }
 266                 if (*s == '\0') {
 267                     fprintf(stderr, "%s: -%c option: missing or empty value\n", 
 268                             argv0, c);
 269                     goto usage;
 270                 }
 271                 switch (c) {
 272                 case 'f':       /* alternate cross-reference file (default: cscope.out) */
 273                     /* N/A */
 274                     break;
 275                 case 'F':       /* symbol reference lines file */
 276                     reflines = s;
 277                     break;
 278                 case 'i':       /* file containing file names (default: cscope.files) */
 279                     /* N/A */
 280                     break;
 281                 case 'I':       /* #include file directory */
 282                     /* N/A */
 283                     break;
 284                 case 'p':       /* file path components to display */
 285                     if (*s < '0' || *s > '9' ) {
 286                         fprintf(stderr, "\
 287 %s: -p option: missing or invalid numeric value\n", 
 288                                 argv0);
 289                         goto usage;
 290                     }
 291                     dispcomponents = atoi(s);
 292                     break;
 293                 case 'P':       /* prepend path to file names */
 294                     /* N/A */
 295                     break;
 296                 case 's':       /* additional source directory */
 297                 case 'S':
 298                     /* N/A */
 299                     break;
 300                 }
 301                 goto nextarg;
 302             default:
 303                 fprintf(stderr, "%s: unknown option: -%c\n", argv0, 
 304                         *s);
 305             usage:
 306                 usage();
 307                 fprintf(stderr, "Try the -h option for more information.\n");
 308                 myexit(1);
 309             } /* switch(option letter) */
 310         } /* for(option) */
 311     nextarg:    
 312         ;
 313     } /* while(argv) */
 314 
 315  lastarg:
 316     /* read the environment */
 317     editor = mygetenv("EDITOR", EDITOR);
 318     editor = mygetenv("VIEWER", editor); /* use viewer if set */
 319     editor = mygetenv("CSCOPE_EDITOR", editor); /* has last word */
 320     home = mygetenv("HOME", HOME);
 321     global_command = mygetenv("GTAGSGLOBAL", "global");
 322     gtags_command = mygetenv("GTAGSGTAGS", "gtags");
 323 #if defined(_WIN32) || defined(__DJGPP__)
 324     shell = mygetenv("COMSPEC", SHELL);
 325     shell = mygetenv("SHELL", shell);
 326     tmpdir = mygetenv("TMP", TMPDIR);
 327     tmpdir = mygetenv("TMPDIR", tmpdir);
 328 #else
 329     shell = mygetenv("SHELL", SHELL);
 330     tmpdir = mygetenv("TMPDIR", TMPDIR);
 331 #endif
 332     lineflag = mygetenv("CSCOPE_LINEFLAG", LINEFLAG);
 333     lineflagafterfile = getenv("CSCOPE_LINEFLAG_AFTER_FILE") ? 1 : 0;
 334 
 335     /* make sure that tmpdir exists */
 336     if (lstat (tmpdir, &stat_buf)) {
 337         fprintf (stderr, "\
 338 cscope: Temporary directory %s does not exist or cannot be accessed\n", 
 339                  tmpdir);
 340         fprintf (stderr, "\
 341 cscope: Please create the directory or set the environment variable\n\
 342 cscope: TMPDIR to a valid directory\n");
 343         myexit(1);
 344     }
 345 
 346     /* create the temporary file names */
 347     orig_umask = umask(S_IRWXG|S_IRWXO);
 348     pid = getpid();
 349     snprintf(tempdirpv, sizeof(tempdirpv), "%s/cscope.%d", tmpdir, pid);
 350     if(mkdir(tempdirpv,S_IRWXU)) {
 351         fprintf(stderr, "\
 352 cscope: Could not create private temp dir %s\n",
 353                 tempdirpv);
 354         myexit(1);
 355     }
 356     umask(orig_umask);
 357 
 358     snprintf(temp1, sizeof(temp1), "%s/cscope.1", tempdirpv);
 359     snprintf(temp2, sizeof(temp2), "%s/cscope.2", tempdirpv);
 360 
 361     /* if running in the foreground */
 362     if (signal(SIGINT, SIG_IGN) != SIG_IGN && ignoresigint == NO) {
 363         /* cleanup on the interrupt and quit signals */
 364         signal(SIGINT, myexit);
 365 #ifdef SIGQUIT
 366         signal(SIGQUIT, myexit);
 367 #endif
 368     }
 369     /* cleanup on the hangup signal */
 370 #ifdef SIGHUP
 371     signal(SIGHUP, myexit);
 372 #endif
 373 
 374     /* ditto the TERM signal */
 375     signal(SIGTERM, myexit);
 376 
 377     if (linemode == NO) {
 378         signal(SIGINT, SIG_IGN);        /* ignore interrupts */
 379 #ifdef SIGPIPE
 380         signal(SIGPIPE, SIG_IGN);/* | command can cause pipe signal */
 381 #endif
 382 
 383 #if defined(KEY_RESIZE) && defined(SIGWINCH)
 384         winch_action.sa_sigaction = sigwinch_handler;
 385         sigemptyset(&winch_action.sa_mask);
 386         winch_action.sa_flags = SA_SIGINFO;
 387         sigaction(SIGWINCH,&winch_action,NULL);
 388 #endif
 389 
 390         /* initialize the curses display package */
 391         initscr();      /* initialize the screen */
 392         entercurses();
 393 #if TERMINFO
 394         keypad(stdscr, TRUE);   /* enable the keypad */
 395 # ifdef HAVE_FIXKEYPAD
 396         fixkeypad();    /* fix for getch() intermittently returning garbage */
 397 # endif
 398 #endif /* TERMINFO */
 399 #if UNIXPC
 400         standend();     /* turn off reverse video */
 401 #endif
 402         dispinit();     /* initialize display parameters */
 403         setfield();     /* set the initial cursor position */
 404         clearmsg();     /* clear any build progress message */
 405         display();      /* display the version number and input fields */
 406     }
 407 
 408     /* if the cross-reference is to be considered up-to-date */
 409     if (isuptodate == YES) {
 410         char com[80];
 411         snprintf(com, sizeof(com), "%s -p >" NULL_DEVICE, global_command);
 412         if (system(com) != 0) {
 413             postfatal("gtags-cscope: GTAGS not found. Please invoke again without -d option.\n");
 414             /* NOTREACHED */
 415         }
 416     } else {
 417         char buf[MAXPATHLEN];
 418 
 419         if (linemode == NO || verbosemode == YES)    /* display if verbose as well */
 420             postmsg("Building cross-reference...");                 
 421         rebuild();
 422         if (linemode == NO )
 423             clearmsg(); /* clear any build progress message */
 424         if (buildonly == YES) {
 425             myexit(0);
 426         }
 427         set_env("GTAGSROOT", getcwd(buf, sizeof(buf)));
 428         set_env("GTAGSDBPATH", getcwd(buf, sizeof(buf)));
 429     }
 430 
 431     /* opendatabase(); */
 432 
 433     /* if using the line oriented user interface so cscope can be a 
 434        subprocess to emacs or samuel */
 435     if (linemode == YES) {
 436         if (*Pattern != '\0') {         /* do any optional search */
 437             if (search() == YES) {
 438                 /* print the total number of lines in
 439                  * verbose mode */
 440                 if (verbosemode == YES)
 441                     printf("cscope: %d lines\n",
 442                            totallines);
 443 
 444                 while ((c = getc(refsfound)) != EOF)
 445                     putchar(c);
 446             }
 447         }
 448         if (onesearch == YES)
 449             myexit(0);
 450                 
 451         for (;;) {
 452             char buf[PATLEN + 2];
 453                         
 454             printf(">> ");
 455             fflush(stdout);
 456             if (fgets(buf, sizeof(buf), stdin) == NULL) {
 457                 myexit(0);
 458             }
 459             /* remove any trailing newline character */
 460             if (*(s = buf + strlen(buf) - 1) == '\n') {
 461                 *s = '\0';
 462             }
 463             switch (*buf) {
 464             case '0':
 465             case '1':
 466             case '2':
 467             case '3':
 468             case '4':
 469             case '5':
 470             case '6':
 471             case '7':
 472             case '8':
 473                 field = *buf - '0';
 474                 strcpy(Pattern, buf + 1);
 475                 search();
 476                 printf("cscope: %d lines\n", totallines);
 477                 while ((c = getc(refsfound)) != EOF) {
 478                     putchar(c);
 479                 }
 480                 break;
 481 
 482             case 'c':   /* toggle caseless mode */
 483             case ctrl('C'):
 484                 if (caseless == NO) {
 485                     caseless = YES;
 486                 } else {
 487                     caseless = NO;
 488                 }
 489                 break;
 490 
 491             case 'r':   /* rebuild database cscope style */
 492             case ctrl('R'):
 493                 rebuild();
 494                 putchar('\n');
 495                 break;
 496 
 497             case 'C':   /* clear file names */
 498                 /* N/A */
 499                 putchar('\n');
 500                 break;
 501 
 502             case 'F':   /* add a file name */
 503                 /* N/A */
 504                 putchar('\n');
 505                 break;
 506 
 507             case 'q':   /* quit */
 508             case ctrl('D'):
 509             case ctrl('Z'):
 510                 myexit(0);
 511 
 512             default:
 513                 fprintf(stderr, "gtags-cscope: unknown command '%s'\n", buf);
 514                 break;
 515             }
 516         }
 517         /* NOTREACHED */
 518     }
 519     /* do any optional search */
 520     if (*Pattern != '\0') {
 521         atfield();              /* move to the input field */
 522         command(ctrl('Y'));     /* search */
 523     } else if (reflines != NULL) {
 524         /* read any symbol reference lines file */
 525         readrefs(reflines);
 526     }
 527     display();          /* update the display */
 528 
 529     for (;;) {
 530         if (!selecting)
 531             atfield();  /* move to the input field */
 532 
 533         /* exit if the quit command is entered */
 534         if ((c = mygetch()) == EOF || c == ctrl('D') || c == ctrl('Z')) {
 535             break;
 536         }
 537         /* execute the commmand, updating the display if necessary */
 538         if (command(c) == YES) {
 539             display();
 540         }
 541 
 542         if (selecting) {
 543             move(displine[curdispline], 0);
 544             refresh();
 545         }
 546     }
 547     /* cleanup and exit */
 548     myexit(0);
 549     /* NOTREACHED */
 550     return 0;           /* avoid warning... */
 551 }
 552 
 553 void
 554 cannotopen(char *file)
 555 {
 556     posterr("Cannot open file %s", file);
 557 }
 558 
 559 /* FIXME MTE - should use postfatal here */
 560 void
 561 cannotwrite(char *file)
 562 {
 563     char        msg[MSGLEN + 1];
 564 
 565     snprintf(msg, sizeof(msg), "Removed file %s because write failed", file);
 566     myperror(msg);      /* display the reason */
 567 
 568     unlink(file);
 569     myexit(1);  /* calls exit(2), which closes files */
 570 }
 571 
 572 /** enter curses mode */
 573 void
 574 entercurses(void)
 575 {
 576     incurses = YES;
 577 #ifndef __MSDOS__ /* HBB 20010313 */
 578     nonl();                 /* don't translate an output \n to \n\r */
 579 #endif
 580     raw();                      /* single character input */
 581     noecho();                   /* don't echo input characters */
 582     clear();                    /* clear the screen */
 583     mouseinit();                /* initialize any mouse interface */
 584     drawscrollbar(topline, nextline);
 585 }
 586 
 587 
 588 /** exit curses mode */
 589 void
 590 exitcurses(void)
 591 {
 592         /* clear the bottom line */
 593         move(LINES - 1, 0);
 594         clrtoeol();
 595         refresh();
 596 
 597         /* exit curses and restore the terminal modes */
 598         endwin();
 599         incurses = NO;
 600 
 601         /* restore the mouse */
 602         mousecleanup();
 603         fflush(stdout);
 604 }
 605 
 606 
 607 /** normal usage message */
 608 static void
 609 usage(void)
 610 {
 611         fputs(usage_const, stderr);
 612 }
 613 
 614 
 615 /** long usage message */
 616 static void
 617 longusage(void)
 618 {
 619         fputs(usage_const, stdout);
 620         fputs(help_const, stdout);
 621 }
 622 
 623 /** cleanup and exit */
 624 
 625 void
 626 myexit(int sig)
 627 {
 628         /* HBB 20010313; close file before unlinking it. Unix may not care
 629          * about that, but DOS absolutely needs it */
 630         if (refsfound != NULL)
 631                 fclose(refsfound);
 632         
 633         /* remove any temporary files */
 634         if (temp1[0] != '\0') {
 635                 unlink(temp1);
 636                 unlink(temp2);
 637                 rmdir(tempdirpv);
 638         }
 639         /* restore the terminal to its original mode */
 640         if (incurses == YES) {
 641                 exitcurses();
 642         }
 643         /* dump core for debugging on the quit signal */
 644 #ifdef SIGQUIT
 645         if (sig == SIGQUIT) {
 646                 abort();
 647         }
 648 #endif
 649         /* HBB 20000421: be nice: free allocated data */
 650         exit(sig);
 651 }

/* [previous][next][first][last][top][bottom][index][help] */