eustags.c
Go to the documentation of this file.
00001 /* Tags file maker to go with GNUmacs
00002    Copyright (C) 1984, 1987, 1988 Free Software Foundation, Inc. and Ken Arnold
00003 
00004                            NO WARRANTY
00005 
00006   BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
00007 NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW.  EXCEPT
00008 WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
00009 RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
00010 WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
00011 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
00012 FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
00013 AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE
00014 DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
00015 CORRECTION.
00016 
00017  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
00018 STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
00019 WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
00020 LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
00021 OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
00022 USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
00023 DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
00024 A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
00025 PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
00026 DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
00027 
00028                 GENERAL PUBLIC LICENSE TO COPY
00029 
00030   1. You may copy and distribute verbatim copies of this source file
00031 as you receive it, in any medium, provided that you conspicuously
00032 and appropriately publish on each copy a valid copyright notice
00033 "Copyright (C) 1986 Free Software Foundation"; and include
00034 following the copyright notice a verbatim copy of the above disclaimer
00035 of warranty and of this License.
00036 
00037   2. You may modify your copy or copies of this source file or
00038 any portion of it, and copy and distribute such modifications under
00039 the terms of Paragraph 1 above, provided that you also do the following:
00040 
00041     a) cause the modified files to carry prominent notices stating
00042     that you changed the files and the date of any change; and
00043 
00044     b) cause the whole of any work that you distribute or publish,
00045     that in whole or in part contains or is a derivative of this
00046     program or any part thereof, to be licensed at no charge to all
00047     third parties on terms identical to those contained in this
00048     License Agreement (except that you may choose to grant more extensive
00049     warranty protection to some or all third parties, at your option).
00050 
00051     c) You may charge a distribution fee for the physical act of
00052     transferring a copy, and you may at your option offer warranty
00053     protection in exchange for a fee.
00054 
00055 Mere aggregation of another unrelated program with this program (or its
00056 derivative) on a volume of a storage or distribution medium does not bring
00057 the other program under the scope of these terms.
00058 
00059   3. You may copy and distribute this program (or a portion or derivative
00060 of it, under Paragraph 2) in object code or executable form under the terms
00061 of Paragraphs 1 and 2 above provided that you also do one of the following:
00062 
00063     a) accompany it with the complete corresponding machine-readable
00064     source code, which must be distributed under the terms of
00065     Paragraphs 1 and 2 above; or,
00066 
00067     b) accompany it with a written offer, valid for at least three
00068     years, to give any third party free (except for a nominal
00069     shipping charge) a complete machine-readable copy of the
00070     corresponding source code, to be distributed under the terms of
00071     Paragraphs 1 and 2 above; or,
00072 
00073     c) accompany it with the information you received as to where the
00074     corresponding source code may be obtained.  (This alternative is
00075     allowed only for noncommercial distribution and only if you
00076     received the program in object code or executable form alone.)
00077 
00078 For an executable file, complete source code means all the source code for
00079 all modules it contains; but, as a special exception, it need not include
00080 source code for modules which are standard libraries that accompany the
00081 operating system on which the executable file runs.
00082 
00083   4. You may not copy, sublicense, distribute or transfer this program
00084 except as expressly provided under this License Agreement.  Any attempt
00085 otherwise to copy, sublicense, distribute or transfer this program is void and
00086 your rights to use the program under this License agreement shall be
00087 automatically terminated.  However, parties who have received computer
00088 software programs from you with this License Agreement will not have
00089 their licenses terminated so long as such parties remain in full compliance.
00090 
00091 In other words, you are welcome to use, share and improve this program.
00092 You are forbidden to forbid anyone else to use, share and improve
00093 what you give them.   Help stamp out software-hoarding!  */
00094 
00095 #include <stdio.h>
00096 #include <ctype.h>
00097 
00098 /* Define the symbol ETAGS to make the program "etags",
00099  which makes emacs-style tag tables by default.
00100  Define CTAGS to make the program "ctags" compatible with the usual one.
00101  Define neither one to get behavior that depends
00102  on the name with which the program is invoked
00103  (but we don't normally compile it that way).  */
00104 
00105 /* On VMS, CTAGS is not useful, so always do ETAGS.  */
00106 #ifdef VMS
00107 #ifndef ETAGS
00108 #define ETAGS
00109 #endif
00110 #endif
00111 
00112 /* Exit codes for success and failure.  */
00113 
00114 #ifdef VMS
00115 #define GOOD    (1)
00116 #define BAD     (0)
00117 #else
00118 #define GOOD    (0)
00119 #define BAD     (1)
00120 #endif
00121 
00122 #define reg     register
00123 #define logical char
00124 
00125 #define TRUE    (1)
00126 #define FALSE   (0)
00127 
00128 #define iswhite(arg)    (_wht[arg])     /* T if char is white           */
00129 #define begtoken(arg)   (_btk[arg])     /* T if char can start token    */
00130 #define intoken(arg)    (_itk[arg])     /* T if char can be in token    */
00131 #define endtoken(arg)   (_etk[arg])     /* T if char ends tokens        */
00132 #define isgood(arg)     (_gd[arg])      /* T if char can be after ')'   */
00133 
00134 #define max(I1,I2)      (I1 > I2 ? I1 : I2)
00135 
00136 /* cause token checking for typedef, struct, union, enum to distinguish
00137    keywords from identifier-prefixes (e.g. struct vs struct_tag).  */
00138 #define istoken(s, tok, len) (!strncmp(s,tok,len) && endtoken(*((s)+(len))))
00139 
00140 struct  nd_st {                 /* sorting structure                    */
00141         char    *name;                  /* function or type name        */
00142         char    *file;                  /* file name                    */
00143         logical f;                      /* use pattern or line no       */
00144         int     lno;                    /* line number tag is on        */
00145         long    cno;                    /* character number line starts on */
00146         char    *pat;                   /* search pattern               */
00147         logical been_warned;            /* set if noticed dup           */
00148         struct  nd_st   *left,*right;   /* left and right sons          */
00149 };
00150 
00151 long    ftell();
00152 typedef struct  nd_st   NODE;
00153 
00154 int number; /* tokens found so far on line starting with # (including #) */
00155 logical gotone,                         /* found a func already on line */
00156                                         /* boolean "func" (see init)    */
00157         _wht[0177],_etk[0177],_itk[0177],_btk[0177],_gd[0177];
00158 
00159         /* typedefs are recognized using a simple finite automata,
00160          * tydef is its state variable.
00161          */
00162 typedef enum {none, begin, tag_ok, middle, end } TYST;
00163 
00164 TYST tydef = none;
00165 
00166 char    searchar = '/';                 /* use /.../ searches           */
00167 
00168 int     lineno;                 /* line number of current line */
00169 long    charno;                 /* current character number */
00170 long    linecharno;             /* character number of start of line */
00171 
00172 char    *curfile,               /* current input file name              */
00173         *outfile= 0,            /* output file                          */
00174         *white  = " \f\t\n",    /* white chars                          */
00175         *endtk  = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?",
00176                                 /* token ending chars                   */
00177         *begtk  = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$",
00178                                 /* token starting chars                 */
00179         *intk   = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789",
00180                                 /* valid in-token chars                 */
00181         *notgd  = ",;";         /* non-valid after-function chars       */
00182 
00183 int     file_num = 0;           /* current file number                  */
00184 int     aflag = 0;              /* -a: append to tags */
00185 int     tflag = 0;              /* -t: create tags for typedefs */
00186 int     uflag = 0;              /* -u: update tags */
00187 int     wflag = 0;              /* -w: suppress warnings */
00188 int     vflag = 0;              /* -v: create vgrind style index output */
00189 int     xflag = 0;              /* -x: create cxref style output */
00190 int     eflag = 0;              /* -e: emacs style output */
00191 
00192 /* Name this program was invoked with.  */
00193 char *progname;
00194 
00195 FILE    *inf,                   /* ioptr for current input file         */
00196         *outf;                  /* ioptr for tags file                  */
00197 
00198 NODE    *head;                  /* the head of the sorted binary tree   */
00199 
00200 char *savestr();
00201 char *savenstr ();
00202 // char *rindex();
00203 //char *index();
00204 char *concat ();
00205 void initbuffer ();
00206 long readline ();
00207 
00208 /* A `struct linebuffer' is a structure which holds a line of text.
00209  `readline' reads a line from a stream into a linebuffer
00210  and works regardless of the length of the line.  */
00211 
00212 struct linebuffer
00213   {
00214     long size;
00215     char *buffer;
00216   };
00217 
00218 struct linebuffer lb, lb1;
00219 
00220 #if 0  /* VMS now provides the `system' function.  */
00221 #ifdef VMS
00222 
00223 #include <descrip.h>
00224 
00225 void
00226 system (buf)
00227      char *buf;
00228 {
00229   struct dsc$descriptor_s command =
00230     {
00231       strlen(buf), DSC$K_DTYPE_T, DSC$K_CLASS_S, buf
00232     };
00233 
00234   LIB$SPAWN(&command);
00235 }
00236 #endif /* VMS */
00237 #endif /* 0 */
00238 
00239 main(ac,av)
00240      int        ac;
00241      char       *av[];
00242 {
00243   char cmd[100];
00244   int i;
00245   int fflag = 0;
00246   char *this_file;
00247 #ifdef VMS
00248   char got_err;
00249 
00250   extern char *gfnames();
00251   extern char *massage_name();
00252 #endif
00253 
00254   progname = av[0];
00255 
00256 #ifdef ETAGS
00257   eflag = 1;
00258 #else
00259 #ifdef CTAGS
00260   eflag = 0;
00261 #else
00262   {
00263     char *subname = rindex (progname, '/');
00264     if (subname++ == NULL)
00265       subname = progname;
00266     eflag = ! strcmp(subname, "ctags");
00267   }
00268 #endif
00269 #endif
00270 
00271   while (ac > 1 && av[1][0] == '-')
00272     {
00273       for (i=1; av[1][i]; i++)
00274         {
00275           switch(av[1][i])
00276             {
00277 #ifndef VMS  /* These options are useful only with ctags,
00278                 and VMS can't input them, so just omit them.  */
00279             case 'B':
00280               searchar='?';
00281               eflag = 0;
00282               break;
00283             case 'F':
00284               searchar='/';
00285               eflag = 0;
00286               break;
00287 #endif
00288             case 'a':
00289               aflag++;
00290               break;
00291             case 'e':
00292               eflag++;
00293               break;
00294             case 'f':
00295               if (fflag > 0)
00296                 {
00297                   fprintf(stderr,
00298                           "%s: -f flag may only be given once\n", progname);
00299                   goto usage;
00300                 }
00301               fflag++, ac--; av++;
00302               if (ac <= 1 || av[1][0] == '\0')
00303                 {
00304                   fprintf(stderr,
00305                           "%s: -f flag must be followed by a filename\n",
00306                           progname);
00307                   goto usage;
00308                 }
00309               outfile = av[1];
00310               goto end_loop;
00311             case 't':
00312               tflag++;
00313               break;
00314 #ifndef VMS
00315             case 'u':
00316               uflag++;
00317               eflag = 0;
00318               break;
00319 #endif
00320             case 'w':
00321               wflag++;
00322               break;
00323             case 'v':
00324               vflag++;
00325               xflag++;
00326               eflag = 0;
00327               break;
00328             case 'x':
00329               xflag++;
00330               eflag = 0;
00331               break;
00332             default:
00333               goto usage;
00334             }
00335         }
00336     end_loop: ;
00337       ac--; av++;
00338     }
00339 
00340   if (ac <= 1)
00341     {
00342     usage:
00343 #ifdef VMS
00344       fprintf (stderr, "Usage: %s [-aetwvx] [-f outfile] file ...\n", progname);
00345 #else
00346       fprintf (stderr, "Usage: %s [-BFaetuwvx] [-f outfile] file ...\n", progname);
00347 #endif
00348       exit(BAD);
00349     }
00350 
00351   if (outfile == 0)
00352     {
00353       outfile = eflag ? "TAGS" : "tags";
00354     }
00355 
00356   init();                       /* set up boolean "functions"           */
00357 
00358   initbuffer (&lb);
00359   initbuffer (&lb1);
00360   /*
00361    * loop through files finding functions
00362    */
00363   if (eflag)
00364     {
00365       outf = fopen (outfile, aflag ? "a" : "w");
00366       if (!outf)
00367         {
00368           fprintf (stderr, "%s: ", progname);
00369           perror (outfile);
00370           exit (BAD);
00371         }
00372     }
00373 
00374   file_num = 1;
00375 #ifdef VMS
00376   for (ac--, av++;
00377        (this_file = gfnames (&ac, &av, &got_err)) != NULL; file_num++)
00378     {
00379       if (got_err)
00380         {
00381           error("Can't find file %s\n", this_file);
00382           ac--, av++;
00383         }
00384       else
00385         {
00386           this_file = massage_name (this_file);
00387 #else     
00388   for (; file_num < ac; file_num++)
00389     {
00390       this_file = av[file_num];
00391       if (1)
00392         {
00393 #endif
00394           find_entries (this_file);
00395           if (eflag)
00396             {
00397               fprintf (outf, "\f\n%s,%d\n",
00398                        this_file, total_size_of_entries (head));
00399               put_entries (head);
00400               free_tree (head);
00401               head = NULL;
00402             }
00403         }
00404     }
00405 
00406   if (eflag)
00407     {
00408       fclose (outf);
00409       exit (GOOD);
00410     }
00411 
00412   if (xflag)
00413     {
00414       put_entries(head);
00415       exit(GOOD);
00416     }
00417   if (uflag)
00418     {
00419       for (i=1; i<ac; i++)
00420         {
00421           sprintf(cmd,
00422                   "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
00423                   outfile, av[i], outfile);
00424           system(cmd);
00425         }
00426       aflag++;
00427     }
00428   outf = fopen(outfile, aflag ? "a" : "w");
00429   if (outf == NULL)
00430     {
00431       fprintf (stderr, "%s: ", outfile);
00432       perror(outfile);
00433       exit(BAD);
00434     }
00435   put_entries(head);
00436   fclose(outf);
00437 #ifndef VMS
00438   if (uflag)
00439     {
00440       sprintf(cmd, "sort %s -o %s", outfile, outfile);
00441       system(cmd);
00442     }
00443 #endif
00444   exit(GOOD);
00445 }
00446 
00447 /*
00448  * This routine sets up the boolean psuedo-functions which work
00449  * by seting boolean flags dependent upon the corresponding character
00450  * Every char which is NOT in that string is not a white char.  Therefore,
00451  * all of the array "_wht" is set to FALSE, and then the elements
00452  * subscripted by the chars in "white" are set to TRUE.  Thus "_wht"
00453  * of a char is TRUE if it is the string "white", else FALSE.
00454  */
00455 init()
00456 {
00457 
00458   reg char *sp;
00459   reg int i;
00460 
00461   for (i = 0; i < 0177; i++)
00462     {
00463       _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
00464       _gd[i] = TRUE;
00465     }
00466   for (sp = white; *sp; sp++)
00467     _wht[*sp] = TRUE;
00468   for (sp = endtk; *sp; sp++)
00469     _etk[*sp] = TRUE;
00470   for (sp = intk; *sp; sp++)
00471     _itk[*sp] = TRUE;
00472   for (sp = begtk; *sp; sp++)
00473     _btk[*sp] = TRUE;
00474   for (sp = notgd; *sp; sp++)
00475     _gd[*sp] = FALSE;
00476   _wht[0] = _wht['\n'];
00477   _etk[0] = _etk['\n'];
00478   _btk[0] = _btk['\n'];
00479   _itk[0] = _itk['\n'];
00480   _gd[0] = _gd['\n'];
00481 }
00482 
00483 /*
00484  * This routine opens the specified file and calls the function
00485  * which finds the function and type definitions.
00486  */
00487 find_entries (file)
00488      char *file;
00489 {
00490   char *cp;
00491 
00492   if ((inf=fopen(file,"r")) == NULL)
00493     {
00494       fprintf (stderr, "%s: ", progname);
00495       perror(file);
00496       return;
00497     }
00498   curfile = savestr(file);
00499   cp = rindex(file, '.');
00500   /* .tex, .aux or .bbl implies LaTeX source code */
00501   if (cp && (!strcmp (cp + 1, "tex") || !strcmp (cp + 1, "aux")
00502              || !strcmp (cp + 1, "bbl")))
00503     {
00504       TEX_funcs(inf);
00505       fclose(inf);
00506       return;
00507     }
00508   /* .l or .el or .lisp (or .cl or .clisp or ...) implies lisp source code */
00509   if (cp && (!strcmp (cp + 1, "l") ||
00510              !strcmp (cp + 1, "el") ||
00511              !strcmp (cp + 1, "lsp") ||
00512              !strcmp (cp + 1, "lisp") ||
00513              !strcmp (cp + 1, "cl") ||
00514              !strcmp (cp + 1, "clisp")))
00515     {
00516       L_funcs(inf);
00517       fclose(inf);
00518       return;
00519     }
00520   /* .scm or .sm or .scheme implies scheme source code */
00521   if (cp && (!strcmp (cp + 1, "sm")
00522              || !strcmp (cp + 1, "scm")
00523              || !strcmp (cp + 1, "scheme")
00524              || !strcmp (cp + 1, "t")
00525              || !strcmp (cp + 1, "sch")
00526              || !strcmp (cp + 1, "SM")
00527              || !strcmp (cp + 1, "SCM")
00528              /* The `SCM' or `scm' prefix with a version number */
00529              || (cp[-1] == 'm' && cp[-2] == 'c' && cp[-3] == 's')
00530              || (cp[-1] == 'M' && cp[-2] == 'C' && cp[-3] == 'S')))
00531     {
00532       Scheme_funcs(inf);
00533       fclose(inf);
00534       return;
00535     }
00536   /* if not a .c or .h or .y file, try fortran */
00537   if (cp && (cp[1] != 'c' && cp[1] != 'h' && cp[1] != 'y')
00538       && cp[2] == '\0')
00539     {
00540       if (PF_funcs(inf) != 0)
00541         {
00542           fclose(inf);
00543           return;
00544         }
00545       rewind(inf);      /* no fortran tags found, try C */
00546     }
00547   C_entries();
00548   fclose(inf);
00549 }
00550 
00551 /* Record a tag on the current line.
00552   name is the tag name,
00553   f is nonzero to use a pattern, zero to use line number instead. */
00554 
00555 pfnote (name, f, linestart, linelen, lno, cno)
00556      char *name;
00557      logical f;                 /* f == TRUE when function */
00558      char *linestart;
00559      int linelen;
00560      int lno;
00561      long cno;
00562 {
00563   register char *fp;
00564   register NODE *np;
00565   char *altname;
00566   char tem[51];
00567 
00568   if ((np = (NODE *) malloc (sizeof (NODE))) == NULL)
00569     {
00570       fprintf(stderr, "%s: too many entries to sort\n", progname);
00571       put_entries(head);
00572       free_tree(head);
00573       head = NULL;
00574       np = (NODE *) xmalloc(sizeof (NODE));
00575     }
00576   /* Change name "main" to M<thisfilename>. */
00577   if (!eflag && !xflag && !strcmp(name, "main"))
00578     {
00579       fp = rindex(curfile, '/');
00580       if (fp == 0)
00581         fp = curfile;
00582       else
00583         fp++;
00584       altname = concat ("M", fp, "");
00585       fp = rindex(altname, '.');
00586       if (fp && fp[2] == 0)
00587         *fp = 0;
00588       name = altname;
00589     }
00590   np->name = savestr(name);
00591   np->file = curfile;
00592   np->f = f;
00593   np->lno = lno;
00594   np->cno = cno;
00595   np->left = np->right = 0;
00596   if (eflag)
00597     {
00598       linestart[linelen] = 0;
00599     }
00600   else if (xflag == 0)
00601     {
00602       sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart);
00603       linestart = tem;
00604     }
00605   np->pat = savestr (linestart);
00606   if (head == NULL)
00607     head = np;
00608   else
00609     add_node(np, head);
00610 }
00611 
00612 free_tree(node)
00613      NODE *node;
00614 {
00615   while (node)
00616     {
00617       free_tree(node->right);
00618       free(node);
00619       node = node->left;
00620     }
00621 }
00622 
00623 add_node(node, cur_node)
00624      NODE *node,*cur_node;
00625 {
00626   register int dif;
00627 
00628   dif = strcmp(node->name, cur_node->name);
00629 
00630   /* If this tag name matches an existing one, then
00631      unless -e was given, do not add the node, but maybe print a warning */
00632   if (!eflag && !dif)
00633     {
00634       if (node->file == cur_node->file)
00635         {
00636           if (!wflag)
00637             {
00638               fprintf(stderr,"%s: Duplicate entry in file %s, line %d: %s\n",
00639                       progname, node->file,lineno,node->name);
00640               fprintf(stderr,"Second entry ignored\n");
00641             }
00642           return;
00643         }
00644       if (!cur_node->been_warned)
00645         if (!wflag)
00646           fprintf(stderr,"%s: Duplicate entry in files %s and %s: %s (Warning only)\n",
00647                   progname, node->file, cur_node->file, node->name);
00648       cur_node->been_warned = TRUE;
00649       return;
00650     } 
00651 
00652   /* Actually add the node */
00653   if (dif < 0) 
00654     {
00655       if (cur_node->left != NULL)
00656         add_node(node,cur_node->left);
00657       else
00658         cur_node->left = node;
00659       return;
00660     }
00661   if (cur_node->right != NULL)
00662     add_node(node,cur_node->right);
00663   else
00664     cur_node->right = node;
00665 }
00666 
00667 put_entries(node)
00668      reg NODE *node;
00669 {
00670   reg char *sp;
00671 
00672   if (node == NULL)
00673     return;
00674 
00675   /* Output subentries that precede this one */
00676   put_entries (node->left);
00677 
00678   /* Output this entry */
00679 
00680   if (eflag)
00681     {
00682       fprintf (outf, "%s%c%d,%d\n",
00683                node->pat, 0177, node->lno, node->cno);
00684     }
00685   else if (!xflag)
00686     {
00687       fprintf (outf, "%s\t%s\t",
00688                node->name, node->file);
00689 
00690       if (node->f)
00691         {               /* a function */
00692           putc (searchar, outf);
00693           putc ('^', outf);
00694 
00695           for (sp = node->pat; *sp; sp++)
00696             {
00697               if (*sp == '\\' || *sp == searchar)
00698                 putc ('\\', outf);
00699               putc (*sp, outf);
00700             }
00701           putc (searchar, outf);
00702         }
00703       else
00704         {               /* a typedef; text pattern inadequate */
00705           fprintf (outf, "%d", node->lno);
00706         }
00707       putc ('\n', outf);
00708     }
00709   else if (vflag)
00710     fprintf (stdout, "%s %s %d\n",
00711              node->name, node->file, (node->lno+63)/64);
00712   else
00713     fprintf (stdout, "%-16s%4d %-16s %s\n",
00714              node->name, node->lno, node->file, node->pat);
00715 
00716   /* Output subentries that follow this one */
00717   put_entries (node->right);
00718 }
00719 
00720 /* Return total number of characters that put_entries will output for
00721  the nodes in the subtree of the specified node.
00722  Works only if eflag is set, but called only in that case.  */
00723 
00724 total_size_of_entries(node)
00725      reg NODE *node;
00726 {
00727   reg int total = 0;
00728   reg long num;
00729 
00730   if (node == NULL)
00731     return 0;
00732 
00733   /* Count subentries that precede this one */
00734   total = total_size_of_entries (node->left);
00735 
00736   /* Count subentries that follow this one */
00737   total += total_size_of_entries (node->right);
00738 
00739   /* Count this entry */
00740 
00741   total += strlen (node->pat) + 3;
00742 
00743   num = node->lno;
00744   while (num)
00745     {
00746       total++;
00747       num /= 10;
00748     }
00749 
00750   num = node->cno;
00751   if (!num) total++;
00752   while (num)
00753     {
00754       total++;
00755       num /= 10;
00756     }
00757   return total;
00758 }
00759 
00760 /*
00761  * This routine finds functions and typedefs in C syntax and adds them
00762  * to the list.
00763  */
00764 #ifdef VMS
00765 long vmslinecharno;
00766 #define VMS_SET_LINECHARNO      (vmslinecharno = ftell(inf))
00767 #else
00768 #define VMS_SET_LINECHARNO
00769 #endif
00770 
00771 #define CNL_SAVE_NUMBER \
00772 { \
00773   VMS_SET_LINECHARNO; \
00774   linecharno = charno; lineno++; \
00775   charno += 1 + readline (&lb, inf); \
00776   lp = lb.buffer; \
00777 }
00778 
00779 #define CNL \
00780 { \
00781   CNL_SAVE_NUMBER; \
00782   number = 0; \
00783 }
00784 
00785 C_entries ()
00786 {
00787   register int c;
00788   register char *token, *tp, *lp;
00789   logical incomm, inquote, inchar, midtoken;
00790   int level;
00791   char tok[BUFSIZ];
00792 
00793   lineno = 0;
00794   charno = 0;
00795   lp = lb.buffer;
00796   *lp = 0;
00797 
00798   number = 0;
00799   gotone = midtoken = inquote = inchar = incomm = FALSE;
00800   level = 0;
00801 
00802   while (!feof (inf))
00803     {
00804       c = *lp++;
00805       if (c == 0)
00806         {
00807           CNL;
00808           gotone = FALSE;
00809         }
00810       if (c == '\\')
00811         {
00812           c = *lp++;
00813           if (c == 0)
00814             CNL_SAVE_NUMBER;
00815           c = ' ';
00816         } 
00817       else if (incomm)
00818         {
00819           if (c == '*')
00820             {
00821               while ((c = *lp++) == '*')
00822                 continue;
00823               if (c == 0)
00824                 CNL;
00825               if (c == '/')
00826                 incomm = FALSE;
00827             }
00828         }
00829       else if (inquote)
00830         {
00831           /*
00832           * Too dumb to know about \" not being magic, but
00833           * they usually occur in pairs anyway.
00834           */
00835           if (c == '"')
00836             inquote = FALSE;
00837           continue;
00838         }
00839       else if (inchar)
00840         {
00841           if (c == '\'')
00842             inchar = FALSE;
00843           continue;
00844         }
00845       else switch (c)
00846         {
00847         case '"':
00848           inquote = TRUE;
00849           continue;
00850         case '\'':
00851           inchar = TRUE;
00852           continue;
00853         case '/':
00854           if (*lp == '*')
00855             {
00856               lp++;
00857               incomm = TRUE;
00858             }
00859           continue;
00860         case '#':
00861           if (lp == lb.buffer + 1)
00862             number = 1;
00863           continue;
00864         case '{':
00865           if (tydef == tag_ok)
00866             {
00867               tydef=middle;
00868             }
00869           level++;
00870           continue;
00871         case '}':
00872           if (lp == lb.buffer + 1)
00873             level = 0;  /* reset */
00874           else
00875             level--;
00876           if (!level && tydef==middle)
00877             {
00878               tydef=end;
00879             }
00880           continue;
00881         }
00882       if (!level && !inquote && !incomm && gotone == FALSE)
00883         {
00884           if (midtoken)
00885             {
00886               if (endtoken(c))
00887                 {
00888                   int f;
00889                   char *buf = lb.buffer;
00890                   int endpos = lp - lb.buffer;
00891                   char *lp1 = lp;
00892                   int line = lineno;
00893                   long linestart = linecharno;
00894 #ifdef VMS
00895                   long vmslinestart = vmslinecharno;
00896 #endif
00897                   int tem = consider_token (&lp1, token, &f, level);
00898                   lp = lp1;
00899                   if (tem)
00900                     {
00901                       if (linestart != linecharno)
00902                         {
00903 #ifdef VMS
00904                           getline (vmslinestart);
00905 #else
00906                           getline (linestart);
00907 #endif
00908                           strncpy (tok, token + (lb1.buffer - buf),
00909                                    tp-token+1);
00910                           tok[tp-token+1] = 0;
00911                           pfnote(tok, f, lb1.buffer, endpos, line, linestart);
00912                         }
00913                       else
00914                         {
00915                           strncpy (tok, token, tp-token+1);
00916                           tok[tp-token+1] = 0;
00917                           pfnote(tok, f, lb.buffer, endpos, line, linestart);
00918                         }
00919                       gotone = f;       /* function */
00920                     }
00921                   midtoken = FALSE;
00922                   token = lp - 1;
00923                 }
00924               else if (intoken(c))
00925                 tp++;
00926             }
00927           else if (begtoken(c))
00928             {
00929               token = tp = lp - 1;
00930               midtoken = TRUE;
00931             }
00932         }
00933       if (c == ';'  &&  tydef==end)     /* clean with typedefs */
00934         tydef=none;
00935     }
00936 }
00937 
00938 /*
00939  * This routine  checks to see if the current token is
00940  * at the start of a function, or corresponds to a typedef
00941  * It updates the input line * so that the '(' will be
00942  * in it when it returns.
00943  */
00944 consider_token (lpp, token, f, level)
00945      char **lpp, *token;
00946      int *f, level;
00947 {
00948   reg char *lp = *lpp;
00949   reg char c;
00950   static logical next_token_is_func;
00951   logical firsttok;     /* T if have seen first token in ()'s */
00952   int bad, win;
00953 
00954   *f = 1;                       /* a function */
00955   c = lp[-1];
00956   bad = FALSE;
00957   if (!number)
00958     {           /* space is not allowed in macro defs   */
00959       while (iswhite(c))
00960         {
00961           c = *lp++;
00962           if (c == 0)
00963             {
00964               if (feof (inf))
00965                 break;
00966               CNL;
00967             }
00968         }
00969       /* the following tries to make it so that a #define a b(c)        */
00970       /* doesn't count as a define of b.                                */
00971     }
00972   else
00973     {
00974       number++;
00975       if (number >= 4  || (number==2 && strncmp (token, "define", 6)))
00976         {
00977           gotone = TRUE;
00978         badone:
00979           bad = TRUE;
00980           goto ret;
00981         }
00982     }
00983   /* check for the typedef cases                */
00984   if (tflag && istoken(token, "typedef", 7))
00985     {
00986       tydef=begin;
00987       goto badone;
00988     }
00989   if (tydef==begin && (istoken(token, "struct", 6) ||
00990                        istoken(token, "union", 5) || istoken(token, "enum", 4)))
00991   {
00992     tydef=tag_ok;      
00993     goto badone;
00994   }
00995   if (tydef==tag_ok)
00996     {
00997       tydef=middle;
00998       goto badone;
00999     }
01000   if (tydef==begin)             /* e.g. typedef ->int<- */
01001     {
01002       tydef=end;
01003       goto badone;
01004     }
01005   if (tydef==middle && level == 0) /* e.g. typedef struct tag ->struct_t<- */
01006     {
01007       tydef=end;
01008     }
01009   if (tydef==end)
01010     {
01011       *f = 0;
01012       win = 1;
01013       goto ret;
01014     }
01015   /* Detect GNUmacs's function-defining macros. */
01016   if (!number && !strncmp (token, "DEF", 3))
01017          
01018     {
01019       next_token_is_func = 1;
01020       goto badone;
01021     }
01022   if (next_token_is_func)
01023     {
01024       next_token_is_func = 0;
01025       win = 1;
01026       goto ret;
01027     }
01028   if (c != '(')
01029     goto badone;
01030   firsttok = FALSE;
01031   while ((c = *lp++) != ')')
01032     {
01033       if (c == 0)
01034         {
01035           if (feof (inf))
01036             break;
01037           CNL;
01038         }
01039       /*
01040         * This line used to confuse ctags:
01041         *       int     (*oldhup)();
01042         * This fixes it. A nonwhite char before the first
01043         * token, other than a / (in case of a comment in there)
01044         * makes this not a declaration.
01045         */
01046       if (begtoken(c) || c=='/') firsttok++;
01047       else if (!iswhite(c) && !firsttok) goto badone;
01048     }
01049   while (iswhite (c = *lp++))
01050     {
01051       if (c == 0)
01052         {
01053           if (feof (inf))
01054             break;
01055           CNL;
01056         }
01057     }
01058   win = isgood (c);
01059 ret:
01060   *lpp = lp - 1;
01061   return !bad && win;
01062 }
01063 
01064 getline (atchar)
01065      long atchar;
01066 {
01067   long saveftell = ftell (inf);
01068 
01069   fseek (inf, atchar, 0);
01070   readline (&lb1, inf);
01071   fseek (inf, saveftell, 0);
01072 }
01073 
01074 /* Fortran parsing */
01075 
01076 char    *dbp;
01077 int     pfcnt;
01078 
01079 PF_funcs(fi)
01080      FILE *fi;
01081 {
01082   lineno = 0;
01083   charno = 0;
01084   pfcnt = 0;
01085 
01086   while (!feof (fi))
01087     {
01088       lineno++;
01089       linecharno = charno;
01090       charno += readline (&lb, fi) + 1;
01091       dbp = lb.buffer;
01092       if (*dbp == '%') dbp++ ;  /* Ratfor escape to fortran */
01093       while (isspace(*dbp))
01094         dbp++;
01095       if (*dbp == 0)
01096         continue;
01097       switch (*dbp |' ')
01098         {
01099         case 'i':
01100           if (tail("integer"))
01101             takeprec();
01102           break;
01103         case 'r':
01104           if (tail("real"))
01105             takeprec();
01106           break;
01107         case 'l':
01108           if (tail("logical"))
01109             takeprec();
01110           break;
01111         case 'c':
01112           if (tail("complex") || tail("character"))
01113             takeprec();
01114           break;
01115         case 'd':
01116           if (tail("double"))
01117             {
01118               while (isspace(*dbp))
01119                 dbp++;
01120               if (*dbp == 0)
01121                 continue;
01122               if (tail("precision"))
01123                 break;
01124               continue;
01125             }
01126           break;
01127         }
01128       while (isspace(*dbp))
01129         dbp++;
01130       if (*dbp == 0)
01131         continue;
01132       switch (*dbp|' ')
01133         {
01134         case 'f':
01135           if (tail("function"))
01136             getit();
01137           continue;
01138         case 's':
01139           if (tail("subroutine"))
01140             getit();
01141           continue;
01142         case 'p':
01143           if (tail("program"))
01144             {
01145               getit();
01146               continue;
01147             }
01148           if (tail("procedure"))
01149             getit();
01150           continue;
01151         }
01152     }
01153   return (pfcnt);
01154 }
01155 
01156 tail(cp)
01157      char *cp;
01158 {
01159   register int len = 0;
01160 
01161   while (*cp && (*cp&~' ') == ((*(dbp+len))&~' '))
01162     cp++, len++;
01163   if (*cp == 0)
01164     {
01165       dbp += len;
01166       return (1);
01167     }
01168   return (0);
01169 }
01170 
01171 takeprec()
01172 {
01173   while (isspace(*dbp))
01174     dbp++;
01175   if (*dbp != '*')
01176     return;
01177   dbp++;
01178   while (isspace(*dbp))
01179     dbp++;
01180   if (!isdigit(*dbp))
01181     {
01182       --dbp;            /* force failure */
01183       return;
01184     }
01185   do
01186     dbp++;
01187   while (isdigit(*dbp));
01188 }
01189 
01190 getit()
01191 {
01192   register char *cp;
01193   char c;
01194   char nambuf[BUFSIZ];
01195 
01196   while (isspace(*dbp))
01197     dbp++;
01198   if (*dbp == 0 || !isalpha(*dbp))
01199     return;
01200   for (cp = dbp+1; *cp && (isalpha(*cp) || isdigit(*cp)); cp++)
01201     continue;
01202   c = cp[0];
01203   cp[0] = 0;
01204   strcpy(nambuf, dbp);
01205   cp[0] = c;
01206   pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
01207   pfcnt++;
01208 }
01209 
01210 /*
01211  * lisp tag functions
01212  * just look for (def or (DEF
01213  */
01214 
01215 L_funcs (fi)
01216      FILE *fi;
01217 {
01218   lineno = 0;
01219   charno = 0;
01220   pfcnt = 0;
01221 
01222   while (!feof (fi))
01223     {
01224       lineno++;
01225       linecharno = charno;
01226       charno += readline (&lb, fi) + 1;
01227       dbp = lb.buffer;
01228       while (isspace(*dbp)) dbp++;
01229       if (dbp[0] == '(' && 
01230           (dbp[1] == 'D' || dbp[1] == 'd') &&
01231             (dbp[2] == 'E' || dbp[2] == 'e') &&
01232               (dbp[3] == 'F' || dbp[3] == 'f'))
01233         {
01234           while (!isspace(*dbp)) dbp++;
01235           while (isspace(*dbp)) dbp++;
01236           L_getit();
01237         }
01238       if (dbp[0] == '(' && 
01239           (dbp[1] == ':'))
01240         {
01241           while (!isspace(*dbp)) dbp++;
01242           while (isspace(*dbp)) dbp++;
01243           L_getit();
01244         }
01245 
01246     }
01247 }
01248 
01249 L_getit()
01250 {
01251   register char *cp;
01252   char c;
01253   char nambuf[BUFSIZ];
01254 
01255   if (*dbp == 0) return;
01256   for (cp = dbp+1; *cp && *cp != '(' && *cp != ' '; cp++)
01257     continue;
01258   c = cp[0];
01259   cp[0] = 0;
01260   strcpy(nambuf, dbp);
01261   cp[0] = c;
01262   pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
01263   pfcnt++;
01264 }
01265 
01266 /*
01267  * Scheme tag functions
01268  * look for (def... xyzzy
01269  * look for (def... (xyzzy
01270  * look for (def ... ((...(xyzzy ....
01271  * look for (set! xyzzy
01272  */
01273 
01274 static get_scheme ();
01275 Scheme_funcs (fi)
01276      FILE *fi;
01277 {
01278   lineno = 0;
01279   charno = 0;
01280   pfcnt = 0;
01281 
01282   while (!feof (fi))
01283     {
01284       lineno++;
01285       linecharno = charno;
01286       charno += readline (&lb, fi) + 1;
01287       dbp = lb.buffer;
01288       if (dbp[0] == '(' && 
01289           (dbp[1] == 'D' || dbp[1] == 'd') &&
01290             (dbp[2] == 'E' || dbp[2] == 'e') &&
01291               (dbp[3] == 'F' || dbp[3] == 'f'))
01292         {
01293           while (!isspace(*dbp)) dbp++;
01294           /* Skip over open parens and white space */
01295           while (*dbp && (isspace(*dbp) || *dbp == '(')) dbp++;
01296           get_scheme ();
01297         }
01298       if (dbp[0] == '(' && 
01299           (dbp[1] == 'S' || dbp[1] == 's') &&
01300             (dbp[2] == 'E' || dbp[2] == 'e') &&
01301               (dbp[3] == 'T' || dbp[3] == 't') &&
01302                 (dbp[4] == '!' || dbp[4] == '!') &&
01303                   (isspace(dbp[5])))
01304         {
01305           while (!isspace(*dbp)) dbp++;
01306           /* Skip over white space */
01307           while (isspace(*dbp)) dbp++;
01308           get_scheme ();
01309         }
01310     }
01311 }
01312 
01313 static
01314 get_scheme()
01315 {
01316   register char *cp;
01317   char c;
01318   char nambuf[BUFSIZ];
01319 
01320   if (*dbp == 0) return;
01321   /* Go till you get to white space or a syntactic break */
01322   for (cp = dbp+1; *cp && *cp != '(' && *cp != ')' && !isspace(*cp); cp++)
01323     continue;
01324   /* Null terminate the string there. */
01325   c = cp[0];
01326   cp[0] = 0;
01327   /* Copy the string */
01328   strcpy(nambuf, dbp);
01329   /* Unterminate the string */
01330   cp[0] = c;
01331   /* Announce the change */
01332   pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
01333   pfcnt++;
01334 }
01335 
01336 /* Find tags in TeX and LaTeX input files.  */
01337 
01338 /* TEX_toktab is a table of TeX control sequences that define tags.
01339    Each TEX_tabent records one such control sequence.  */
01340 
01341 struct TEX_tabent
01342 {
01343   char *name;
01344   int len;
01345 };
01346 
01347 struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
01348 
01349 /* Default set of control sequences to put into TEX_toktab.
01350    The value of environment var TEXTAGS is prepended to this.  */
01351 
01352 static char *TEX_defenv =
01353   ":chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
01354 
01355 struct TEX_tabent *TEX_decode_env (); 
01356 
01357 static char TEX_esc = '\\';
01358 static char TEX_opgrp = '{';
01359 static char TEX_clgrp = '}';
01360 
01361 /*
01362  * TeX/LaTeX scanning loop.
01363  */
01364 
01365 TEX_funcs (fi)
01366     FILE *fi;
01367 {
01368   char *lasthit;
01369 
01370   lineno = 0;
01371   charno = 0;
01372   pfcnt = 0;
01373 
01374   /* Select either \ or ! as escape character.  */
01375   TEX_mode (fi);
01376 
01377   /* Initialize token table once from environment. */
01378   if (!TEX_toktab)
01379     TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
01380 
01381   while (!feof (fi))
01382     {
01383       lineno++;
01384       linecharno = charno;
01385       charno += readline (&lb, fi) + 1;
01386       dbp = lb.buffer;
01387       lasthit = dbp;
01388 
01389       while (!feof (fi))
01390         {       /* Scan each line in file */
01391           lineno++;
01392           linecharno = charno;
01393           charno += readline (&lb, fi) + 1;
01394           dbp = lb.buffer;
01395           lasthit = dbp;
01396           while (dbp = index (dbp, TEX_esc)) /* Look at each escape in line */
01397             {
01398               register int i;
01399 
01400               if (! *(++dbp))
01401                 break;
01402               linecharno += dbp - lasthit;
01403               lasthit = dbp;
01404               i = TEX_Token (lasthit);
01405               if (0 <= i)
01406                 {
01407                   TEX_getit (lasthit, TEX_toktab[i].len);
01408                   break;                /* We only save a line once */
01409                 }
01410             }
01411         }
01412     }
01413 }
01414 
01415 #define TEX_LESC '\\'
01416 #define TEX_SESC '!'
01417 
01418 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping */
01419 /* chars accordingly. */
01420 
01421 TEX_mode (f)
01422      FILE *f;
01423 {
01424   int c;
01425 
01426   while ((c = getc (f)) != EOF)
01427     if (c == TEX_LESC || c == TEX_SESC)
01428       break;
01429 
01430   if (c == TEX_LESC)
01431     {
01432       TEX_esc = TEX_LESC;
01433       TEX_opgrp = '{';
01434       TEX_clgrp = '}';
01435     } 
01436   else
01437     {
01438       TEX_esc = TEX_SESC;
01439       TEX_opgrp = '<';
01440       TEX_clgrp = '>';
01441     }
01442   rewind (f);
01443 }
01444 
01445 /* Read environment and prepend it to the default string. */
01446 /* Build token table. */
01447 
01448 struct TEX_tabent *
01449 TEX_decode_env (evarname, defenv)
01450      char *evarname;
01451      char *defenv;
01452 {
01453   register char *env, *p;
01454   extern char *savenstr (), *index ();
01455 
01456   struct TEX_tabent *tab;
01457   int size, i;
01458 
01459   /* Append deafult string to environment. */
01460   env = (char *) getenv (evarname);
01461   if (!env)
01462     env = defenv;
01463   else
01464     env = concat (env, defenv, "");
01465 
01466   /* Allocate a token table */
01467   for (size = 1, p=env; p;)
01468     if ((p = index (p, ':')) && *(++p))
01469       size++;
01470   tab = (struct TEX_tabent *) xmalloc (size * sizeof (struct TEX_tabent));
01471 
01472   /* Unpack environment string into token table. Be careful about */
01473   /* zero-length strings (leading ':', "::" and trailing ':') */
01474   for (i = 0; *env;)
01475     {
01476       p = index (env, ':');
01477       if (!p)                   /* End of environment string. */
01478         p = env + strlen (env);
01479       if (p - env > 0)
01480         {       /* Only non-zero strings. */
01481           tab[i].name = savenstr (env, p - env);
01482           tab[i].len = strlen (tab[i].name);
01483           i++;
01484         }
01485       if (*p)
01486         env = p + 1;
01487       else
01488         {
01489           tab[i].name = NULL;   /* Mark end of table. */
01490           tab[i].len = 0;
01491           break;
01492         }
01493     }
01494   return tab;
01495 }
01496 
01497 /* Record a tag defined by a TeX command of length LEN and starting at NAME.
01498    The name being defined actually starts at (NAME + LEN + 1).
01499    But we seem to include the TeX command in the tag name.  */
01500 
01501 TEX_getit (name, len)
01502     char *name;
01503     int len;
01504 {
01505   char *p = name + len;
01506   char nambuf[BUFSIZ];
01507 
01508   if (*name == 0) return;
01509 
01510   /* Let tag name extend to next group close (or end of line) */
01511   while (*p && *p != TEX_clgrp)
01512     p++;
01513   strncpy (nambuf, name, p - name);
01514   nambuf[p - name] = 0;
01515 
01516   pfnote (nambuf, TRUE, lb.buffer, strlen (lb.buffer), lineno, linecharno);
01517   pfcnt++;
01518 }
01519 
01520 /* If the text at CP matches one of the tag-defining TeX command names,
01521    return the index of that command in TEX_toktab.
01522    Otherwise return -1.  */
01523 
01524 /* Keep the capital `T' in `Token' for dumb truncating compilers
01525    (this distinguishes it from `TEX_toktab' */
01526 TEX_Token (cp)
01527     char *cp;
01528 {
01529   int i;
01530 
01531   for (i = 0; TEX_toktab[i].len > 0; i++)
01532     if (strncmp (TEX_toktab[i].name, cp, TEX_toktab[i].len) == 0)
01533       return i;
01534   return -1;
01535 }
01536 
01537 /* Initialize a linebuffer for use */
01538 
01539 void
01540 initbuffer (linebuffer)
01541      struct linebuffer *linebuffer;
01542 {
01543   linebuffer->size = 200;
01544   linebuffer->buffer = (char *) xmalloc (200);
01545 }
01546 
01547 /* Read a line of text from `stream' into `linebuffer'.
01548  Return the length of the line.  */
01549 
01550 long
01551 readline (linebuffer, stream)
01552      struct linebuffer *linebuffer;
01553      register FILE *stream;
01554 {
01555   char *buffer = linebuffer->buffer;
01556   register char *p = linebuffer->buffer;
01557   register char *pend = p + linebuffer->size;
01558 
01559   while (1)
01560     {
01561       int c = getc (stream);
01562       if (p == pend)
01563         {
01564           linebuffer->size *= 2;
01565           buffer = (char *) xrealloc (buffer, linebuffer->size);
01566           p += buffer - linebuffer->buffer;
01567           pend = buffer + linebuffer->size;
01568           linebuffer->buffer = buffer;
01569         }
01570       if (c < 0 || c == '\n')
01571         {
01572           *p = 0;
01573           break;
01574         }
01575       *p++ = c;
01576     }
01577 
01578   return p - buffer;
01579 }
01580 
01581 char *
01582 savestr(cp)
01583      char *cp;
01584 {
01585   return savenstr (cp, strlen (cp));
01586 }
01587 
01588 char *
01589 savenstr(cp, len)
01590     char *cp;
01591     int len;
01592 {
01593   register char *dp;
01594 
01595   dp = (char *) xmalloc (len + 1);
01596   strncpy (dp, cp, len);
01597   dp[len] = '\0';
01598   return dp;
01599 }
01600 
01601 /*
01602  * Return the ptr in sp at which the character c last
01603  * appears; NULL if not found
01604  *
01605  * Identical to v7 rindex, included for portability.
01606  */
01607 
01608 char *
01609 rindex(sp, c)
01610      char *sp, c;
01611 {
01612   char *r;
01613 
01614   r = NULL;
01615   do
01616     {
01617       if (*sp == c)
01618         r = sp;
01619     } while (*sp++);
01620   return(r);
01621 }
01622 
01623 /*
01624  * Return the ptr in sp at which the character c first
01625  * appears; NULL if not found
01626  *
01627  * Identical to v7 index, included for portability.
01628  */
01629 
01630 char *
01631 index(sp, c)
01632      register char *sp, c;
01633 {
01634   do
01635     {
01636       if (*sp == c)
01637         return (sp);
01638     } while (*sp++);
01639   return (NULL);
01640 }
01641 
01642 /* Print error message and exit.  */
01643 
01644 fatal (s1, s2)
01645      char *s1, *s2;
01646 {
01647   error (s1, s2);
01648   exit (BAD);
01649 }
01650 
01651 /* Print error message.  `s1' is printf control string, `s2' is arg for it. */
01652 
01653 error (s1, s2)
01654      char *s1, *s2;
01655 {
01656   fprintf (stderr, "%s: ", progname);
01657   fprintf (stderr, s1, s2);
01658   fprintf (stderr, "\n");
01659 }
01660 
01661 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3.  */
01662 
01663 char *
01664 concat (s1, s2, s3)
01665      char *s1, *s2, *s3;
01666 {
01667   int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
01668   char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
01669 
01670   strcpy (result, s1);
01671   strcpy (result + len1, s2);
01672   strcpy (result + len1 + len2, s3);
01673   *(result + len1 + len2 + len3) = 0;
01674 
01675   return result;
01676 }
01677 
01678 /* Like malloc but get fatal error if memory is exhausted.  */
01679 
01680 int
01681 xmalloc (size)
01682      int size;
01683 {
01684   int result = malloc (size);
01685   if (!result)
01686     fatal ("virtual memory exhausted", 0);
01687   return result;
01688 }
01689 
01690 int
01691 xrealloc (ptr, size)
01692      char *ptr;
01693      int size;
01694 {
01695   int result = realloc (ptr, size);
01696   if (!result)
01697     fatal ("virtual memory exhausted");
01698   return result;
01699 }


euslisp
Author(s): Toshihiro Matsui
autogenerated on Thu Sep 3 2015 10:36:19