root/gtags-cscope/display.c

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

DEFINITIONS

This source file includes following definitions.
  1. dispinit
  2. display
  3. setfield
  4. atfield
  5. atchange
  6. jumpback
  7. search
  8. progress
  9. myperror
  10. postmsg
  11. clearmsg
  12. clearmsg2
  13. postmsg2
  14. posterr
  15. postfatal
  16. seekline
  17. ogsnames
  18. pathcomponents
  19. writerefsfound

   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 /** @file
  34  *      display functions
  35  *
  36  *      cscope - interactive C symbol cross-reference
  37  */
  38 
  39 #ifdef _WIN32
  40 #define WIN32_LEAN_AND_MEAN
  41 #define __OBJC__        /* to make BOOL a define rather than typedef */
  42 #include <windows.h>
  43 #undef BOOL
  44 #undef NOERROR
  45 #undef __OBJC__
  46 #endif
  47 
  48 #include "global-cscope.h"
  49 #include "build.h"
  50 #include "alloc.h"
  51 
  52 #ifdef CCS
  53 #include "sgs.h"        /* ESG_PKG and ESG_REL */
  54 #else
  55 #include "version-cscope.h"     /* FILEVERSION and FIXVERSION */
  56 #endif
  57 
  58 #if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
  59 #include <ncurses.h>
  60 #else
  61 #include <curses.h>
  62 #endif
  63 #include <setjmp.h>     /* jmp_buf */
  64 #include <stdarg.h>     /* va_list stuff */
  65 #include <time.h>
  66 #include <errno.h>
  67 #include <stdarg.h>
  68 
  69 #ifndef HAVE_SIGSETJMP
  70 # define sigsetjmp(a,b) setjmp(a)
  71 # define siglongjmp(a,b) longjmp(a,b)
  72 typedef jmp_buf sigjmp_buf;
  73 #endif
  74 
  75 /* jmh: I'll just take the easy way out and hope for the best... */
  76 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ < 4
  77 #define vsnprintf(one,two,three,four) vsprintf(one,three,four)
  78 #endif
  79 
  80 static char const rcsid[] = "$Id: display.c,v 1.7 2012/10/13 07:01:59 shigio Exp $";
  81 
  82 int     booklen;                /**< OGS book name display field length */
  83 int     *displine;              /**< screen line of displayed reference */
  84 unsigned int disprefs;          /**< displayed references */
  85 int     field;                  /**< input field */
  86 int     filelen;                /**< file name display field length */
  87 int     fcnlen;                 /**< function name display field length */
  88 unsigned int mdisprefs;         /**< maximum displayed references */
  89 unsigned int nextline;          /**< next line to be shown */
  90 int     numlen;                 /**< line number display field length */
  91 unsigned int topline = 1;               /**< top line of page */
  92 int     bottomline;             /**< bottom line of page */
  93 long    searchcount;            /**< count of files searched */
  94 int     subsystemlen;           /**< OGS subsystem name display field length */
  95 unsigned int totallines;        /**< total reference lines */
  96 unsigned fldcolumn;             /**< input field column */
  97 
  98 const char      dispchars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  99 
 100 static  int     fldline;                /**< input field line */
 101 static  sigjmp_buf      env;            /**< setjmp/longjmp buffer */
 102 static  int     lastdispline;           /**< last displayed reference line */
 103 static  char    lastmsg[MSGLEN + 1];    /**< last message displayed */
 104 static  char    helpstring[] = "Press the ? key for help";
 105 static  char    selprompt[] = 
 106         "Select lines to change (press the ? key for help): ";
 107 
 108 typedef char * (*FP)(char *);   /**< pointer to function returning a character pointer */
 109 
 110 /* HBB 2000/05/05: I removed the casts to function pointer type. It is
 111  * fundamentally unsafe to call a function through a pointer of a
 112  * different type ('undefined behaviour' in the words of the ANSI/ISO
 113  * C standard).  Instead, I made all the find...() functions adhere to
 114  * the same function type, by changing argument passing a bit. */
 115 static  struct  {               /**< text of input fields */
 116         char    *text1;
 117         char    *text2;
 118         FP      findfcn;
 119 } fields[FIELDS + 1] = {        /* samuel has a search that is not part of the cscope display */
 120         {"Find this", "symbol",                         findsymbol},
 121         {"Find this", "global definition",              finddef},
 122         {"Find", "functions called by this function (N/A)",     findcalledby},
 123         {"Find", "locations calling this function",     findcalling},
 124         {"Find this", "text string",                    findstring},
 125         {"Change this", "text string",                  findstring},
 126         {"Find this", "egrep pattern",                  findregexp},
 127         {"Find this", "file",                           findfile},
 128         {"Find", "files #including this file",          findinclude},
 129 };
 130 
 131 /* Internal prototypes: */
 132 static  RETSIGTYPE      jumpback(int sig);
 133 
 134 /** initialize display parameters */
 135 
 136 void
 137 dispinit(void)
 138 {
 139         /* calculate the maximum displayed reference lines */
 140         lastdispline = FLDLINE - 3;
 141         mdisprefs = lastdispline - REFLINE + 1;
 142 
 143 
 144         if (mdisprefs <= 0) {
 145                 postfatal("%s: screen too small\n", argv0);
 146                 /* NOTREACHED */
 147         }
 148 
 149         if (mouse == NO && mdisprefs > strlen(dispchars))
 150                 mdisprefs = strlen(dispchars);
 151 
 152         /* allocate the displayed line array */
 153         displine = mymalloc(mdisprefs * sizeof(int));
 154 }
 155 
 156 /** display a page of the references */
 157 
 158 void
 159 display(void)
 160 {
 161     char    *subsystem;             /* OGS subsystem name */
 162     char    *book;                  /* OGS book name */
 163     char    file[PATHLEN + 1];      /* file name */
 164     char    function[PATLEN + 1];   /* function name */
 165     char    linenum[NUMLEN + 1];    /* line number */
 166     int     screenline;             /* screen line number */
 167     int     width;                  /* source line display width */
 168     int     i;
 169     char    *s;
 170 
 171     /* see if this is the initial display */
 172     erase();
 173     if (refsfound == NULL) {
 174 #if CCS
 175         if (displayversion == YES) {
 176             printw("cscope %s", ESG_REL);
 177         }
 178         else {
 179             printw("cscope");
 180         }
 181 #else
 182         printw("Gtags-cscope (based on cscope version %d%s)", FILEVERSION, FIXVERSION);
 183 #endif
 184         move(0, COLS - (int) sizeof(helpstring));
 185         addstr(helpstring);
 186     } else if (totallines == 0) {
 187         /* if no references were found */
 188         /* redisplay the last message */
 189         addstr(lastmsg);
 190     } else {
 191         /* display the pattern */
 192         if (changing == YES) {
 193             printw("Change \"%s\" to \"%s\"", Pattern, newpat);
 194         } else {
 195             printw("%c%s: %s", toupper((unsigned char)fields[field].text2[0]),
 196                    fields[field].text2 + 1, Pattern);
 197         }
 198         /* display the column headings */
 199         move(2, 2);
 200         if (ogs == YES && field != FILENAME) {
 201             printw("%-*s ", subsystemlen, "Subsystem");
 202             printw("%-*s ", booklen, "Book");
 203         }
 204         if (dispcomponents > 0)
 205             printw("%-*s ", filelen, "File");
 206 
 207         if (field == SYMBOL || field == CALLEDBY || field == CALLING) {
 208             printw("%-*s ", fcnlen, "Function");
 209         }
 210         if (field != FILENAME) {
 211             addstr("Line");
 212         }
 213         addch('\n');
 214 
 215         /* if at end of file go back to beginning */
 216         if (nextline > totallines) {
 217             seekline(1);
 218         }
 219         /* calculate the source text column */
 220 
 221         width = COLS - numlen - 3;
 222 
 223         if (ogs == YES) {
 224             width -= subsystemlen + booklen + 2;
 225         }
 226         if (dispcomponents > 0) {
 227             width -= filelen + 1;
 228         }
 229         if (field == SYMBOL || field == CALLEDBY || field == CALLING) {
 230             width -= fcnlen + 1;
 231         }
 232 
 233         /* until the max references have been displayed or 
 234            there is no more room */
 235         topline = nextline;
 236         for (disprefs = 0, screenline = REFLINE;
 237              disprefs < mdisprefs && screenline <= lastdispline;
 238              ++disprefs, ++screenline) {
 239             /* read the reference line */
 240             if (fscanf(refsfound, "%" PATHLEN_STR "s%" PATHLEN_STR "s%" NUMLEN_STR "s %" TEMPSTRING_LEN_STR "[^\n]", file, function, 
 241                        linenum, tempstring) < 4) {
 242                 break;
 243             }
 244             ++nextline;
 245             displine[disprefs] = screenline;
 246                         
 247             /* if no mouse, display the selection number */
 248             if (mouse == YES) {
 249                 addch(' ');
 250             } else {
 251                 printw("%c", dispchars[disprefs]);
 252             }
 253 
 254             /* display any change mark */
 255             if (changing == YES && 
 256                 change[topline + disprefs - 1] == YES) {
 257                 addch('>');
 258             } else {
 259                 addch(' ');
 260             }
 261 
 262             /* display the file name */
 263             if (field == FILENAME) {
 264                 printw("%-*s ", filelen, file);
 265             } else {
 266                 /* if OGS, display the subsystem and book names */
 267                 if (ogs == YES) {
 268                     ogsnames(file, &subsystem, &book);
 269                     printw("%-*.*s ", subsystemlen, subsystemlen, subsystem);
 270                     printw("%-*.*s ", booklen, booklen, book);
 271                 }
 272                 /* display the requested path components */
 273                 if (dispcomponents > 0) {
 274                     printw("%-*.*s ", filelen, filelen,
 275                            pathcomponents(file, dispcomponents));
 276                 }
 277             } /* else(field == FILENAME) */
 278 
 279             /* display the function name */
 280             if (field == SYMBOL || field == CALLEDBY || field == CALLING) {
 281                 printw("%-*.*s ", fcnlen, fcnlen, function);
 282             }
 283             if (field == FILENAME) {
 284                 addch('\n');    /* go to next line */
 285                 continue;
 286             }
 287 
 288             /* display the line number */
 289             printw("%*s ", numlen, linenum);
 290             /* there may be tabs in egrep output */
 291             while ((s = strchr(tempstring, '\t')) != NULL) {
 292                 *s = ' ';
 293             }
 294 
 295             /* display the source line */
 296             s = tempstring;
 297             for (;;) {
 298                 /* see if the source line will fit */
 299                 if ((i = strlen(s)) > width) {
 300                                         
 301                     /* find the nearest blank */
 302                     for (i = width; s[i] != ' ' && i > 0; --i) {
 303                         ;
 304                     }
 305                     if (i == 0) {
 306                         i = width;      /* no blank */
 307                     }
 308                 }
 309                 /* print up to this point */
 310                 printw("%.*s", i, s);
 311                 s += i;
 312                                 
 313                 /* if line didn't wrap around */
 314                 if (i < width) {
 315                     addch('\n');        /* go to next line */
 316                 }
 317                 /* skip blanks */
 318                 while (*s == ' ') {
 319                     ++s;
 320                 }
 321                 /* see if there is more text */
 322                 if (*s == '\0') {
 323                     break;
 324                 }
 325                 /* if the source line is too long */
 326                 if (++screenline > lastdispline) {
 327 
 328                     /* if this is the first displayed line,
 329                        display what will fit on the screen */
 330                     if (topline == nextline -1) {
 331                         disprefs++;
 332                         /* break out of two loops */
 333                         goto endrefs;
 334                     }
 335                                         
 336                     /* erase the reference */
 337                     while (--screenline >= displine[disprefs]) {
 338                         move(screenline, 0);
 339                         clrtoeol();
 340                     }
 341                     ++screenline;
 342                                          
 343                     /* go back to the beginning of this reference */
 344                     --nextline;
 345                     seekline(nextline);
 346                     goto endrefs;
 347                 }
 348                 /* indent the continued source line */
 349                 move(screenline, COLS - width);
 350             } /* for(ever) */
 351         } /* for(reference output lines) */
 352     endrefs:
 353         /* position the cursor for the message */
 354         i = FLDLINE - 1;
 355         if (screenline < i) {
 356             addch('\n');
 357         }
 358         else {
 359             move(i, 0);
 360         }
 361         /* check for more references */
 362         i = totallines - nextline + 1;
 363         bottomline = nextline;
 364         if (i > 0) {
 365             s = "s";
 366             if (i == 1) {
 367                 s = "";
 368             }
 369             printw("* %d more line%s - press the space bar to display more *", i, s);
 370         }
 371         /* if this is the last page of references */
 372         else if (topline > 1 && nextline > totallines) {
 373             addstr("* Press the space bar to display the first lines again *");
 374         }
 375     }
 376     /* display the input fields */
 377     move(FLDLINE, 0);
 378     for (i = 0; i < FIELDS; ++i) {
 379         printw("%s %s:\n", fields[i].text1, fields[i].text2);
 380     }
 381     /* display any prompt */
 382     if (changing == YES) {
 383         move(PRLINE, 0);
 384         addstr(selprompt);
 385     }
 386     drawscrollbar(topline, nextline);   /* display the scrollbar */
 387     refresh();
 388 }
 389 
 390 /** set the cursor position for the field */
 391 void
 392 setfield(void)
 393 {
 394         fldline = FLDLINE + field;
 395         fldcolumn = strlen(fields[field].text1) + strlen(fields[field].text2) + 3;
 396 }
 397 
 398 /** move to the current input field */
 399 
 400 void
 401 atfield(void)
 402 {
 403         move(fldline, fldcolumn);
 404 }
 405 
 406 /** move to the changing lines prompt */
 407 
 408 void
 409 atchange(void)
 410 {
 411         move(PRLINE, (int) sizeof(selprompt) - 1);
 412 }
 413 
 414 /** @fn BOOL search(void)
 415  *      search for the symbol or text pattern
 416  */
 417 
 418 /*ARGSUSED*/
 419 static RETSIGTYPE
 420 jumpback(int sig)
 421 {
 422         /* HBB NEW 20031008: try whether reinstating signal handler
 423          * helps... */
 424         signal(sig, jumpback);
 425         siglongjmp(env, 1);
 426 }
 427 
 428 BOOL
 429 search(void)
 430 {
 431         char    *findresult = NULL;     /* find function output */
 432         sighandler_t savesig;           /* old value of signal */
 433         FP      f;                      /* searching function */
 434         int     c;
 435 #ifdef _WIN32
 436         DWORD   savemode;
 437 #endif
 438         
 439         /* open the references found file for writing */
 440         if (writerefsfound() == NO) {
 441                 return(NO);
 442         }
 443 #ifdef _WIN32
 444         /* close it again, otherwise the redirection won't work */
 445         (void) fclose(refsfound);
 446         /* remember the current console mode, since the system */
 447         /* call resets it, thus preventing ctrl(c) from working */
 448         GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &savemode);
 449 #endif
 450         /* find the pattern - stop on an interrupt */
 451         if (linemode == NO) {
 452                 postmsg("Searching ...");
 453         }
 454         searchcount = 0;
 455         savesig = signal(SIGINT, jumpback);
 456         if (sigsetjmp(env, 1) == 0) {
 457                 f = fields[field].findfcn;
 458                 findresult = (*f)(Pattern);
 459         }
 460         signal(SIGINT, savesig);
 461 
 462 #ifdef _WIN32
 463         SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), savemode);
 464 #else
 465         /* reopen the references found file for reading */
 466         (void) fclose(refsfound);
 467 #endif
 468         if ((refsfound = myfopen(temp1, "r")) == NULL) {
 469                 cannotopen(temp1);
 470                 return(NO);
 471         }
 472         nextline = 1;
 473         totallines = 0;
 474         disprefs = 0;
 475         
 476         /* see if it is empty */
 477         if ((c = getc(refsfound)) == EOF) {
 478                 if (findresult != NULL) {
 479                         (void) snprintf(lastmsg, sizeof(lastmsg), "Could not find the %s: %s [%s]",
 480                                        fields[field].text2, Pattern, findresult);
 481                 } else {
 482                         (void) snprintf(lastmsg, sizeof(lastmsg), "Could not find the %s: %s", 
 483                                        fields[field].text2, Pattern);
 484                 }
 485                 return(NO);
 486         }
 487         /* put back the character read */
 488         (void) ungetc(c, refsfound);
 489 
 490         /* HBB 20041027: this used to hold a copy of the code of 
 491          * countrefs(), but with the crucial display width adjustments
 492          * missing.  Just call the real thing instead! */
 493         countrefs();
 494         return(YES);
 495 }
 496 
 497 /** display search progress with default custom format */
 498 
 499 void
 500 progress(char *what, long current, long max)
 501 {
 502         static  long    start;
 503         long    now;
 504         char    msg[MSGLEN + 1];
 505         int     i;
 506 
 507         /* save the start time */
 508         if (searchcount == 0) {
 509                 start = time(NULL);
 510         }
 511         if ((now = time(NULL)) - start >= 1)
 512         {
 513                 if (linemode == NO)
 514                 {
 515                         move(MSGLINE, 0);
 516                         clrtoeol();
 517                         addstr(what);
 518                         snprintf(msg, sizeof(msg), "%ld", current);
 519                         move(MSGLINE, (COLS / 2) - (strlen(msg) / 2));
 520                         addstr(msg);
 521                         snprintf(msg, sizeof(msg), "%ld", max);
 522                         move(MSGLINE, COLS - strlen(msg));
 523                         addstr(msg);
 524                         refresh();
 525                 }
 526                 else if (verbosemode == YES)
 527                 {
 528                         snprintf(msg, sizeof(msg), "> %s %ld of %ld", what, current, max);
 529                 }
 530 
 531                 start = now;
 532                 if ((linemode == NO) && (incurses == YES))
 533                 {
 534                         move(MSGLINE, 0);
 535                         i = (float)COLS * (float)current / (float)max;
 536 
 537                         standout();
 538                         for (; i > 0; i--)
 539                                 addch(inch());
 540                         standend();
 541                         refresh();
 542                 }
 543                 else
 544                         if (linemode == NO || verbosemode == YES)
 545                                 postmsg(msg);
 546         }
 547         ++searchcount;
 548 }
 549 
 550 /** print error message on system call failure */
 551 
 552 void
 553 myperror(char *text) 
 554 {
 555         char    msg[MSGLEN + 1];        /* message */
 556         char    *s;
 557 
 558         s = "Unknown error";
 559 #ifdef HAVE_STRERROR
 560         s = strerror(errno);
 561 #else
 562         if (errno < sys_nerr) {
 563                 s = sys_errlist[errno];
 564         }
 565 #endif
 566         (void) snprintf(msg, sizeof(msg), "%s: %s", text, s);
 567         postmsg(msg);
 568 }
 569 
 570 /** postmsg clears the message line and prints the message */
 571 
 572 /* VARARGS */
 573 void
 574 postmsg(char *msg) 
 575 {
 576         if (linemode == YES || incurses == NO) {
 577                 (void) printf("%s\n", msg);
 578                 fflush(stdout);
 579         }
 580         else {
 581                 clearmsg();
 582                 addstr(msg);
 583                 refresh();
 584         }
 585         (void) strncpy(lastmsg, msg, sizeof(lastmsg) - 1);
 586 }
 587 
 588 /** clearmsg clears the first message line */
 589 
 590 void
 591 clearmsg(void)
 592 {
 593         if (linemode == NO) {
 594                 move(MSGLINE, 0);
 595                 clrtoeol();
 596         }
 597 }
 598 
 599 /** clearmsg2 clears the second message line */
 600 
 601 void
 602 clearmsg2(void)
 603 {
 604         if (linemode == NO) {
 605                 move(MSGLINE + 1, 0);
 606                 clrtoeol();
 607         }
 608 }
 609 
 610 /** postmsg2 clears the second message line and prints the message */
 611 
 612 void
 613 postmsg2(char *msg) 
 614 {
 615         if (linemode == YES) {
 616                 (void) printf("%s\n", msg);
 617         }
 618         else {
 619                 clearmsg2();
 620                 addstr(msg);
 621                 refresh();
 622         }
 623 }
 624 
 625 /** display an error mesg - @NAME{stdout} or on second msg line */
 626 void
 627 posterr(char *msg, ...) 
 628 {
 629     va_list ap;
 630     char errbuf[MSGLEN];
 631     
 632     va_start(ap, msg);
 633     if (linemode == YES || incurses == NO)
 634     {
 635         (void) vfprintf(stderr, msg, ap); 
 636         (void) fputc('\n', stderr);
 637     } else {
 638         vsnprintf(errbuf, sizeof(errbuf), msg, ap);
 639         postmsg2(errbuf); 
 640     }
 641 }
 642 
 643 /** display a fatal error mesg -- @NAME{stderr} @STRONG{*after*} shutting down curses */
 644 void
 645 postfatal(const char *msg, ...)
 646 {
 647         va_list ap;
 648 
 649         /* restore the terminal to its original mode */
 650         if (incurses == YES) {
 651                 exitcurses();
 652         }
 653 
 654         /* display fatal error messages */
 655         va_start(ap, msg);
 656         vfprintf(stderr,msg,ap);
 657 
 658         /* shut down */
 659         myexit(1);
 660 }
 661 
 662 /** position references found file at specified @a line */
 663 
 664 void
 665 seekline(unsigned int line) 
 666 {
 667         int     c;
 668 
 669         /* verify that there is a references found file */
 670         if (refsfound == NULL) {
 671                 return;
 672         }
 673         /* go to the beginning of the file */
 674         rewind(refsfound);
 675         
 676         /* find the requested line */
 677         nextline = 1;
 678         while (nextline < line && (c = getc(refsfound)) != EOF) {
 679                 if (c == '\n') {
 680                         nextline++;
 681                 }
 682         }
 683 }
 684 
 685 /** get the @NAME{OGS} subsystem and book names */
 686 
 687 void
 688 ogsnames(char *file, char **subsystem, char **book)
 689 {
 690         static  char    buf[PATHLEN + 1];
 691         char    *s, *slash;
 692 
 693         *subsystem = *book = "";
 694         (void) strcpy(buf,file);
 695         s = buf;
 696         if (*s == '/') {
 697                 ++s;
 698         }
 699         while ((slash = strchr(s, '/')) != NULL) {
 700                 *slash = '\0';
 701                 if ((int)strlen(s) >= 3 && strncmp(slash - 3, ".ss", 3) == 0) {
 702                         *subsystem = s;
 703                         s = slash + 1;
 704                         if ((slash = strchr(s, '/')) != NULL) {
 705                                 *book = s;
 706                                 *slash = '\0';
 707                         }
 708                         break;
 709                 }
 710                 s = slash + 1;
 711         }
 712 }
 713 
 714 /** get the requested @a path @a components */
 715 
 716 char *
 717 pathcomponents(char *path, int components)
 718 {
 719         int     i;
 720         char    *s;
 721         
 722         s = path + strlen(path) - 1;
 723         for (i = 0; i < components; ++i) {
 724                 while (s > path && *--s != '/') {
 725                         ;
 726                 }
 727         }
 728         if (s > path && *s == '/') {
 729                 ++s;
 730         }
 731         return(s);
 732 }
 733 
 734 /** open the references found file for writing */
 735 
 736 BOOL
 737 writerefsfound(void)
 738 {
 739         if (refsfound == NULL) {
 740                 if ((refsfound = myfopen(temp1, "wb")) == NULL) {
 741                         cannotopen(temp1);
 742                         return(NO);
 743                 }
 744         } else {
 745                 (void) fclose(refsfound);
 746                 if ( (refsfound = myfopen(temp1, "wb")) == NULL) {
 747                         postmsg("Cannot reopen temporary file");
 748                         return(NO);
 749                 }
 750         }
 751         return(YES);
 752 }

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