home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #19 / NN_1992_19.iso / spool / comp / sources / misc / 3876 < prev    next >
Encoding:
Text File  |  1992-08-26  |  57.2 KB  |  2,468 lines

  1. Newsgroups: comp.sources.misc
  2. Path: sparky!kent
  3. From: kendall@centerline.com (Sam Kendall)
  4. Subject:  v31i126:  tags++ - etags/ctags for C and C++, version 1.1, Part03/03
  5. Message-ID: <1992Aug26.144953.3334@sparky.imd.sterling.com>
  6. Followup-To: comp.sources.d
  7. X-Md4-Signature: 4c558c7738cb58c873c2b49f8889da9f
  8. Sender: kent@sparky.imd.sterling.com (Kent Landfield)
  9. Organization: CenterLine Software, Inc.
  10. References: <csm-v31i124=tags++.094745@sparky.IMD.Sterling.COM>
  11. Date: Wed, 26 Aug 1992 14:49:53 GMT
  12. Approved: kent@sparky.imd.sterling.com
  13. Lines: 2453
  14.  
  15. Submitted-by: kendall@centerline.com (Sam Kendall)
  16. Posting-number: Volume 31, Issue 126
  17. Archive-name: tags++/part03
  18. Environment: UNIX, GNU Emacs, vi
  19.  
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line, then unpack
  22. # it by saving it into a file and typing "sh file".  To overwrite existing
  23. # files, type "sh file -c".  You can also feed this as standard input via
  24. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  25. # will see the following message at the end:
  26. #        "End of archive 3 (of 3)."
  27. # Contents:  etags.c
  28. # Wrapped by kendall@pen on Tue Aug 25 13:34:20 1992
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f 'etags.c' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'etags.c'\"
  32. else
  33. echo shar: Extracting \"'etags.c'\" \(54188 characters\)
  34. sed "s/^X//" >'etags.c' <<'END_OF_FILE'
  35. X/* $Id: etags.c,v 1.25 1992/06/04 21:00:52 kendall Exp $ */
  36. X/* Tags file maker to go with GNUmacs
  37. X   Copyright (C) 1984, 1987, 1988 Free Software Foundation, Inc. and Ken Arnold
  38. X
  39. X   This program is free software; you can redistribute it and/or modify
  40. X   it under the terms of the GNU General Public License as published by
  41. X   the Free Software Foundation; either version 2 of the License, or
  42. X   (at your option) any later version.
  43. X
  44. X   This program is distributed in the hope that it will be useful,
  45. X   but WITHOUT ANY WARRANTY; without even the implied warranty of
  46. X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  47. X   GNU General Public License for more details.
  48. X
  49. X   You should have received a copy of the GNU General Public License
  50. X   along with this program; if not, write to the Free Software
  51. X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  52. X   Or contact Sam Kendall, CenterLine Software Inc., 10 Fawcett Street,
  53. X   Cambridge, MA 02138  USA.  Email is kendall@CenterLine.COM or
  54. X   uunet!saber!kendall.
  55. X*/
  56. X
  57. X/*
  58. X * Authors:
  59. X *    Ctags originally by Ken Arnold.
  60. X *    FORTRAN added by Jim Kleckner.
  61. X *    Bill Joy added Pascal and -x.
  62. X *    Ed Pelegri-Llopart added C typedefs.
  63. X *    Gnu Emacs TAGS format and modifications by RMS?
  64. X *    Sam Kendall added C++.
  65. X */
  66. X
  67. X#include <stdio.h>
  68. X#include <ctype.h>
  69. X
  70. Xextern char *malloc (), *realloc ();
  71. Xextern char *getenv ();
  72. Xextern char *strchr (), *strrchr ();
  73. Xextern char *strcpy (), *strncpy ();
  74. Xextern int   strcmp ();
  75. X
  76. X/* Define the symbol ETAGS to make the program "etags",
  77. X which makes emacs-style tag tables by default.
  78. X Define CTAGS to make the program "ctags" compatible with the usual one.
  79. X Define neither one to get behavior that depends
  80. X on the name with which the program is invoked; this is the default. */
  81. X
  82. X#if !defined(ETAGS) && !defined(CTAGS)
  83. X/* If neither is defined, program can be run as either. */
  84. X#define ETAGS
  85. X#define CTAGS
  86. X#endif
  87. X
  88. X/* On VMS, CTAGS is not useful, so always do ETAGS.  */
  89. X#ifdef VMS
  90. X#ifndef ETAGS
  91. X#define ETAGS
  92. X#endif
  93. X#endif
  94. X
  95. X/* Exit codes for success and failure.  */
  96. X#ifdef VMS
  97. X#define    GOOD    (1)
  98. X#define BAD    (0)
  99. X#else
  100. X#define    GOOD    (0)
  101. X#define    BAD    (1)
  102. X#endif
  103. X
  104. X/*
  105. X * The FILEPOS abstract type, which represents a position in a file,
  106. X * plus the following accessor functions:
  107. X *
  108. X *    long GET_CHARNO (pos)
  109. X *                returns absolute char number.
  110. X *    long GET_COOKIE (pos)
  111. X *                returns ftell () cookie.
  112. X *    void SET_FILEPOS (pos, fp, charno)
  113. X *        FILE *fp; long charno;
  114. X *                sets `pos' from the current file
  115. X *                position of `fp' and from `charno',
  116. X *                which must be the absolute character
  117. X *                number corresponding to the current
  118. X *                position of `fp'.
  119. X *
  120. X * The `pos' parameter is an lvalue expression of type FILEPOS.
  121. X * Parameters to the accessor functions are evaluated 0 or more times,
  122. X * and so must have no side effects.
  123. X *
  124. X * FILEPOS objects can also be assigned and passed to and from
  125. X * functions in the normal C manner.
  126. X *
  127. X * Implementation notes: the `+ 0' is to enforce rvalue-ness.
  128. X */
  129. X#ifdef VMS
  130. Xtypedef struct { long cookie; long charno; } FILEPOS;
  131. X# define GET_CHARNO(pos)    ((pos).charno + 0)
  132. X# define GET_COOKIE(pos)    ((pos).cookie + 0)
  133. X# define SET_FILEPOS(pos, fp, cno) \
  134. X    ((void) ((pos).cookie = ftell (fp), (pos).charno = (cno)))
  135. X#else
  136. X# ifndef DEBUG
  137. X    /* UNIX real implementation */
  138. Xtypedef long FILEPOS;
  139. X#  define GET_CHARNO(pos)    ((pos) + 0)
  140. X#  define GET_COOKIE(pos)    GET_CHARNO (pos)
  141. X#  define SET_FILEPOS(pos, fp, cno)    ((void) ((pos) = (cno)))
  142. X# else
  143. X    /* UNIX debugging implementation */
  144. Xtypedef struct { long charno; } FILEPOS;
  145. X#  define GET_CHARNO(pos)    ((pos).charno + 0)
  146. X#  define GET_COOKIE(pos)    GET_CHARNO (pos)
  147. X#  define SET_FILEPOS(pos, fp, cno)                    \
  148. X    ((void) ((pos).charno = (cno),                    \
  149. X         (cno) != ftell (fp) ? (error ("SET_FILEPOS inconsistency"), 0) \
  150. X                      : 0))
  151. X# endif
  152. X#endif
  153. X
  154. X#define streq(s, t)    (strcmp (s, t) == 0)
  155. X#define strneq(s, t, n)    (strncmp (s, t, n) == 0)
  156. X#define    reg    register
  157. X#define    logical    char
  158. X
  159. X#define    TRUE    1
  160. X#define    FALSE    0
  161. X
  162. X#define    iswhite(arg)    (_wht[arg])    /* T if char is white        */
  163. X#define    begtoken(arg)    (_btk[arg])    /* T if char can start token    */
  164. X#define    intoken(arg)    (_itk[arg])    /* T if char can be in token    */
  165. X#define    endtoken(arg)    (_etk[arg])    /* T if char ends tokens    */
  166. X#define    isgood(arg)    (_gd[arg])    /* T if char can be after ')'    */
  167. X
  168. X#define    max(I1,I2)    ((I1) > (I2) ? (I1) : (I2))
  169. X
  170. Xstruct    nd_st {            /* sorting structure            */
  171. X    char    *name;            /* function or type name    */
  172. X    char    *file;            /* file name            */
  173. X    logical is_func;        /* use pattern or line no    */
  174. X    logical rewritten;        /* list name separately        */
  175. X    logical    been_warned;        /* set if noticed dup        */
  176. X    int    lno;            /* line number tag is on    */
  177. X    long    cno;            /* character number line starts on */
  178. X    char    *pat;            /* search pattern        */
  179. X    struct    nd_st    *left,*right;    /* left and right sons        */
  180. X};
  181. X
  182. Xlong    ftell ();
  183. Xtypedef    struct    nd_st    NODE;
  184. X
  185. Xlogical gotone,                /* found a func already on line    */
  186. X                    /* boolean "func" (see init)    */
  187. X    _wht[0177],_etk[0177],_itk[0177],_btk[0177],_gd[0177];
  188. X
  189. X
  190. Xvoid    init ();
  191. Xvoid    find_entries ();
  192. Xvoid    pfnote ();
  193. Xvoid    free_tree ();
  194. Xvoid    add_node ();
  195. Xvoid    put_entries ();
  196. Xint    total_size_of_entries ();
  197. Xvoid    C_entries ();
  198. Xlogical    consider_token ();
  199. Xvoid    getline ();
  200. Xint    PF_funcs ();
  201. Xlogical    tail ();
  202. Xvoid    takeprec ();
  203. Xvoid    getit ();
  204. Xvoid    L_funcs ();
  205. Xvoid    L_getit ();
  206. Xvoid    Scheme_funcs ();
  207. Xvoid    TEX_funcs ();
  208. Xvoid    initbuffer ();
  209. Xlong    readline ();
  210. Xchar    *savestr ();
  211. Xchar    *savenstr ();
  212. Xvoid    fatal ();
  213. Xvoid    error ();
  214. Xchar    *concat    ();
  215. Xvoid    initbuffer ();
  216. Xchar    *xmalloc ();
  217. Xchar    *xrealloc ();
  218. X
  219. X/*
  220. X * MACRO
  221. X *    xnew -- allocate storage
  222. X *
  223. X * SYNOPSIS
  224. X *    Type *xnew (int n, Type);
  225. X */
  226. X#define xnew(n, Type)    ((Type *) xmalloc ((n) * sizeof (Type)))
  227. X
  228. X
  229. X
  230. X/*
  231. X *    Symbol table stuff.
  232. X *
  233. X * Should probably be implemented with hash table; linked list for now.
  234. X */
  235. X
  236. Xenum sym_type { st_none, st_C_struct, st_C_enum, st_C_define, st_C_typedef };
  237. X
  238. Xstruct stab_entry {
  239. X    char *        sym;
  240. X    int        symlen;
  241. X    enum sym_type    type;
  242. X    struct stab_entry * next;
  243. X};
  244. X
  245. Xtypedef struct stab_entry    Stab_entry;
  246. Xtypedef Stab_entry *        Stab;
  247. X
  248. X/*
  249. X * NAME
  250. X *    Stab, Stab_entry, stab_create, stab_search, stab_find -- symbol table
  251. X *
  252. X * SYNOPSIS
  253. X *    Types: Stab, Stab_entry, enum sym_type
  254. X *
  255. X *    Stab * stab_create ()
  256. X *
  257. X *    Stab_entry * stab_find (stab, sym)
  258. X *    Stab *stab;
  259. X *    char *sym;
  260. X *
  261. X *    Stab_entry * stab_search (stab, sym)
  262. X *    Stab *stab;
  263. X *    char *sym;
  264. X *
  265. X * DESCRIPTION
  266. X *    stab_create creates a Stab, a symbol table object, and returns a
  267. X *    pointer to it.  stab_find finds a symbol in a Stab; it returns a
  268. X *    pointer to the Stab_entry if found, otherwise NULL.  stab_search
  269. X *    is like stab_find, except that it creates a new Stab_entry,
  270. X *    initialized with type = st_none, if one did not exist already
  271. X *    (it never returns NULL).
  272. X *
  273. X *    A Stab_entry is a structure that contains at least the following
  274. X *    members:
  275. X *
  276. X *        char *name;        // must not be modified
  277. X *        enum sym_type type;    // should be set
  278. X *
  279. X *    The type field is initially set to st_none; it should be set to
  280. X *    something else by the caller of stab_search.  Other possible values
  281. X *    of an enum sym_type can be added.
  282. X */
  283. X
  284. XStab *
  285. Xstab_create ()
  286. X{
  287. X  Stab *sp;
  288. X  sp = xnew (1, Stab);
  289. X  *sp = NULL;    /* a Stab starts out as a null Stab_entry* */
  290. X  return sp;
  291. X}
  292. X
  293. XStab_entry *
  294. Xstab_find (stab, sym, symlen)
  295. X     Stab *stab;
  296. X     register char *sym;
  297. X     register int symlen;
  298. X{
  299. X  register Stab_entry *se;
  300. X  for ( se = *stab; se != NULL; se = se->next ) {
  301. X    if (se->symlen == symlen && strneq (se->sym, sym, symlen))
  302. X      return se;
  303. X  }
  304. X
  305. X  return NULL;
  306. X}
  307. X
  308. XStab_entry *
  309. Xstab_search (stab, sym, symlen)
  310. X     register Stab *stab;
  311. X     char *sym;
  312. X     int symlen;
  313. X{
  314. X  register Stab_entry *se;
  315. X  se = stab_find (stab, sym, symlen);
  316. X
  317. X  if (se == NULL) {
  318. X    /* make a new one */
  319. X    se = xnew (1, Stab_entry);
  320. X    se->sym = savenstr (sym, symlen);
  321. X    se->symlen = symlen;
  322. X    se->type = st_none;
  323. X    se->next = *stab;
  324. X    *stab = se;
  325. X  }
  326. X
  327. X  return se;
  328. X}
  329. X
  330. X/*
  331. X * NAME
  332. X *    stab_type -- type of a symbol table entry
  333. X *
  334. X * SYNOPSIS
  335. X *    enum sym_type stab_type (Stab_entry *se);
  336. X *
  337. X * WARNING
  338. X *    May evaluate its argument more than once.
  339. X */
  340. X
  341. X#define stab_type(se)    ((se)==NULL ? st_none : (se)->type)
  342. X    
  343. X
  344. X
  345. Xtypedef int LINENO;
  346. X
  347. Xtypedef struct {
  348. X     char *p;
  349. X     int len;
  350. X     FILEPOS linestart;
  351. X     LINENO lineno;
  352. X     logical rewritten;
  353. X} TOKEN;
  354. X
  355. X
  356. X    /* typedefs are recognized using a simple finite automaton.
  357. X     * tydef is its state variable.
  358. X     */
  359. Xtypedef enum {none, begin, middle, end } TYST;
  360. X
  361. XTYST tydef = none;
  362. X
  363. X
  364. X    /* struct tags for C++ are recognized using another simple
  365. X     * finite automaton.  `structdef' is its state variable.
  366. X     * This machinery is only invoked for C++; otherwise structdef
  367. X     * should remain snone.  However, this machinery can easily be
  368. X     * adapted to find structure tags in normal C code.
  369. X     */
  370. Xtypedef enum {
  371. X     snone,        /* nothing seen yet */
  372. X     skeyseen,        /* struct-like keyword seen */
  373. X     stagseen,        /* struct-like tag seen */
  374. X     scolonseen,    /* colon seen after struct-like tag */
  375. X     sinbody        /* in a class body: recognize member func defs */
  376. X     } STRUCTST;
  377. XSTRUCTST structdef = snone;
  378. X/*
  379. X * When structdef is stagseen, scolonseen, or sinbody, structtag is the
  380. X * struct tag, and structkey is the preceding struct-like keyword.
  381. X */
  382. Xchar structtag[512];
  383. XStab_entry *structkey;
  384. X
  385. X/*
  386. X * Yet another little state machine to deal with preprocessor lines.
  387. X */
  388. Xtypedef enum {
  389. X  dnone,        /* nothing seen */
  390. X  dsharpseen,        /* '#' seen as first char on line */
  391. X  ddefineseen,        /* '#' and 'define' seen */
  392. X  dignorerest        /* ignore rest of line */
  393. X  } DEFINEST;
  394. XDEFINEST definedef;
  395. X
  396. X/*
  397. X * LEVEL_OK_FOR_FUNCDEF allows C++ function definition within class body.
  398. X * Currently tydef and structdef stuff (typedefs and struct definitions) are
  399. X * only noticed when level==0, but that may change.
  400. X *
  401. X * Note that this macro may only be evaluated inside C_entries().  It is
  402. X * for self-documentation only.
  403. X */
  404. X#define LEVEL_OK_FOR_FUNCDEF()                    \
  405. X    (level==0 || c_ext && level==1 && structdef==sinbody)
  406. X
  407. X/* C extensions.  Currently all listed extensions are C++ dialects, so
  408. X * `c_ext' is used as an abbreviation for `c_ext&C_PLPL'.  If a non-C++
  409. X * dialect is added, this must change.
  410. X */
  411. X#define C_PLPL    0x1    /* C++ */
  412. X#define C_STAR    0x3    /* C* */
  413. X
  414. Xchar    searchar = '/';            /* use /.../ searches         */
  415. X
  416. XLINENO    lineno;            /* line number of current line */
  417. Xlong    charno;            /* current character number */
  418. XFILEPOS    linepos;        /* start of line (C only) */
  419. XFILEPOS    prev_linepos;        /* start of previous line (C only) */
  420. X
  421. Xlong    linecharno;        /* charno of start of line; not used by C, but
  422. X                 * by every other language.
  423. X                 */
  424. X
  425. Xchar    *curfile,        /* current input file name        */
  426. X    *outfile,        /* output file                */
  427. X    *white    = " \f\t\n",    /* white chars                */
  428. X    *endtk    = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?",
  429. X                /* token ending chars            */
  430. X    *begtk    = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$",
  431. X                /* token starting chars            */
  432. X    *intk    = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789",
  433. X                /* valid in-token chars            */
  434. X    *notgd    = ",;";        /* non-valid after-function chars    */
  435. X
  436. Xint    file_num;        /* current file number            */
  437. Xint    aflag;            /* -a: append to tags */
  438. Xint    eflag;            /* emacs style output (no -e option any more) */
  439. X/* The following three default to 1 for etags, but to 0 for ctags.  */
  440. Xint    tflag;            /* -t: create tags for typedefs */
  441. Xint    strflag;        /* -T: create tags for typedefs, level */
  442. X                /* 0 struct/enum/union decls, and C++ */
  443. X                /* member functions */
  444. Xint    constantflag;        /* -d: create tags for C #define and enum */
  445. X                /* constants. Default under etags.  Enum */
  446. X                /* constants not implemented. */
  447. X                /* -D: opposite of -d.  Default under ctags. */
  448. Xint    uflag;            /* -u: update tags */
  449. Xint    vflag;            /* -v: create vgrind style index output */
  450. Xint    wflag;            /* -w: suppress warnings */
  451. Xint    xflag;            /* -x: create cxref style output */
  452. Xint    Cflag = TRUE;        /* .[hc] means C++, not C (default) */
  453. Xint    noindentflag;        /* -S: ignore indentation in C */
  454. Xint    iflag;            /* -i: treat all spec'd files as
  455. X                   included sub-tag-tables.  */
  456. X
  457. X/* Name this program was invoked with.  */
  458. Xchar *progname;
  459. X
  460. XFILE    *inf,            /* ioptr for current input file        */
  461. X    *outf;            /* ioptr for tags file            */
  462. X
  463. XNODE    *head;            /* the head of the binary tree of tags    */
  464. X
  465. X/* A `struct linebuffer' is a structure which holds a line of text.
  466. X `readline' reads a line from a stream into a linebuffer
  467. X and works regardless of the length of the line.  */
  468. X
  469. Xstruct linebuffer
  470. X  {
  471. X    long size;
  472. X    char *buffer;
  473. X  };
  474. X
  475. Xstruct linebuffer lb;    /* the current line */
  476. Xstruct linebuffer lb1;    /* sometimes, a previous line in which a token lies */
  477. Xstruct linebuffer filename_lb;    /* used to read in filenames */
  478. X
  479. X#if 0  /* VMS now provides the `system' function.  */
  480. X#ifdef VMS
  481. X
  482. X#include descrip
  483. X
  484. Xsystem (buf)
  485. X     char *buf;
  486. X{
  487. X  struct dsc$descriptor_s command =
  488. X    {
  489. X      strlen (buf), DSC$K_DTYPE_T, DSC$K_CLASS_S, buf
  490. X    };
  491. X
  492. X  LIB$SPAWN (&command);
  493. X}
  494. X#endif /* VMS */
  495. X#endif /* 0 */
  496. X
  497. X
  498. Xmain (argc,argv)
  499. X     int    argc;
  500. X     char    *argv[];
  501. X{
  502. X  char cmd[100];
  503. X  int i;
  504. X  int outfflag = 0;
  505. X  char *this_file;
  506. X#ifdef VMS
  507. X  char got_err;
  508. X
  509. X  extern char *gfnames ();
  510. X  extern char *massage_name ();
  511. X#endif
  512. X
  513. X  progname = argv[0];
  514. X
  515. X#ifndef CTAGS
  516. X  eflag = 1;
  517. X#else
  518. X#ifndef ETAGS
  519. X  eflag = 0;
  520. X#else
  521. X  /* Be ctags only if we are run as "ctags" or close to it. */
  522. X  {
  523. X    char *subname = strrchr (argv[0], '/');
  524. X    subname = subname ? subname + 1 : argv[0];
  525. X    /* allow, for example, "ctags", "ctags-new", or "nctags" */
  526. X    eflag = !(strneq (subname, "ctags", 5) || strneq (subname+1, "ctags", 5));
  527. X  }
  528. X#endif
  529. X#endif
  530. X
  531. X  /*
  532. X   * If etags, always find typedefs and structure tags.  Why not?
  533. X   * Also default is to find macro constants.
  534. X   */
  535. X  if (eflag)
  536. X    tflag = strflag = constantflag = 1;
  537. X
  538. X  for ( ; argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0'; argc--, argv++)
  539. X    {
  540. X      for (i=1; argv[1][i]; i++)
  541. X    {
  542. X      switch (argv[1][i])
  543. X        {
  544. X          /* Common options. */
  545. X        case 'a':
  546. X          aflag++;
  547. X          break;
  548. X        case 'd':
  549. X          constantflag = 1;
  550. X          break;
  551. X        case 'D':
  552. X          constantflag = 0;
  553. X          break;
  554. X        case 'o':
  555. X          if (outfflag)
  556. X        {
  557. X          fprintf (stderr,
  558. X               "%s: -o flag may only be given once\n", progname);
  559. X          goto usage;
  560. X        }
  561. X          outfflag++, argc--; argv++;
  562. X          if (argc <= 1 || argv[1][0] == '\0')
  563. X        {
  564. X          fprintf (stderr,
  565. X               "%s: -o flag must be followed by a filename\n",
  566. X               progname);
  567. X          goto usage;
  568. X        }
  569. X          outfile = argv[1];
  570. X          goto next_arg;
  571. X        case 'S':
  572. X          noindentflag++;
  573. X          break;
  574. X        case 't':
  575. X          tflag++;
  576. X          break;
  577. X        case 'T':
  578. X          tflag++;
  579. X          strflag++;
  580. X          break;
  581. X
  582. X          /* Etags options */
  583. X        case 'i':
  584. X          iflag++;
  585. X          if (!eflag) goto usage;
  586. X          break;
  587. X
  588. X          /* Ctags options. */
  589. X        case 'B':
  590. X          searchar='?';
  591. X          if (eflag) goto usage;
  592. X          break;
  593. X        case 'F':
  594. X          searchar='/';
  595. X          if (eflag) goto usage;
  596. X          break;
  597. X        case 'u':
  598. X          uflag++;
  599. X          if (eflag) goto usage;
  600. X          break;
  601. X        case 'v':
  602. X          vflag++;
  603. X          /*FALLTHRU*/
  604. X        case 'x':
  605. X          xflag++;
  606. X          if (eflag) goto usage;
  607. X          break;
  608. X        case 'w':
  609. X          wflag++;
  610. X          if (eflag) goto usage;
  611. X          break;
  612. X
  613. X        default:
  614. X          goto usage;
  615. X        }
  616. X    }
  617. X    next_arg: ;
  618. X    }
  619. X
  620. X  if (argc <= 1)
  621. X    {
  622. X    usage:
  623. X      fprintf (stderr, "Usage:\n");
  624. X#if defined(ETAGS) || (!defined(ETAGS) && !defined(CTAGS))
  625. X      if (eflag)
  626. X      fprintf (stderr, "\tetags [-a] [-o tagsfile] file ...\n");
  627. X#endif
  628. X#if defined(CTAGS) || (!defined(ETAGS) && !defined(CTAGS))
  629. X      if (!eflag)
  630. X      fprintf (stderr, "\tctags [-aBdFtTuwvx] [-o tagsfile] file ...\n");
  631. X#endif
  632. X      exit (BAD);
  633. X    }
  634. X
  635. X  if (outfile == 0)
  636. X    {
  637. X      outfile = eflag ? "TAGS" : "tags";
  638. X    }
  639. X
  640. X  init ();            /* set up boolean "functions"        */
  641. X
  642. X  initbuffer (&lb);
  643. X  initbuffer (&lb1);
  644. X  initbuffer (&filename_lb);
  645. X  /*
  646. X   * loop through files finding functions
  647. X   */
  648. X  if (eflag)
  649. X    {
  650. X      if (streq (outfile, "-"))
  651. X    outf = stdout;
  652. X      else
  653. X    outf = fopen (outfile, aflag ? "a" : "w");
  654. X      if (!outf)
  655. X    {
  656. X      perror (outfile);
  657. X      exit (1);
  658. X    }
  659. X    }
  660. X
  661. X  file_num = 1;
  662. X#ifdef VMS
  663. X  for (argc--, argv++;
  664. X       (this_file = gfnames (&argc, &argv, &got_err)) != NULL; file_num++)
  665. X    {
  666. X      if (got_err)
  667. X    {
  668. X      error ("Can't find file %s\n", this_file);
  669. X      argc--, argv++;
  670. X    }
  671. X      else
  672. X    {
  673. X      this_file = massage_name (this_file);
  674. X# if 0
  675. X    }}  /* solely to balance out the ifdef'd parens above */
  676. X# endif
  677. X#else     
  678. X  for (; file_num < argc; file_num++)
  679. X    {
  680. X      this_file = argv[file_num];
  681. X      if (1)
  682. X    {
  683. X#endif
  684. X      /* Input file named "-" means read file names from stdin
  685. X         and use them.  */
  686. X      if (streq (this_file, "-"))
  687. X        {
  688. X          while (! feof (stdin))
  689. X        {
  690. X            (void) readline (&filename_lb, stdin);
  691. X            if (strlen(filename_lb.buffer) > 0)
  692. X              process_file (filename_lb.buffer);
  693. X        }
  694. X        }
  695. X      else
  696. X        process_file (this_file);
  697. X    }
  698. X    }
  699. X
  700. X  if (eflag)
  701. X    {
  702. X      (void) fclose (outf);
  703. X      exit (0);
  704. X    }
  705. X
  706. X  if (xflag)
  707. X    {
  708. X      put_entries (head);
  709. X      exit (GOOD);
  710. X    }
  711. X  if (uflag)    /* uflag cannot be set under VMS */
  712. X    {
  713. X      for (i=1; i<argc; i++)
  714. X    {
  715. X      sprintf (cmd,
  716. X           "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
  717. X           outfile, argv[i], outfile);
  718. X      (void) system (cmd);
  719. X    }
  720. X      aflag++;
  721. X    }
  722. X  outf = fopen (outfile, aflag ? "a" : "w");
  723. X  if (outf == NULL)
  724. X    {
  725. X      perror (outfile);
  726. X      exit (GOOD);
  727. X    }
  728. X  put_entries (head);
  729. X  (void) fclose (outf);
  730. X  if (uflag)
  731. X    {
  732. X      sprintf (cmd, "sort %s -o %s", outfile, outfile);
  733. X      (void) system (cmd);
  734. X    }
  735. X  exit (GOOD);
  736. X}
  737. X
  738. X
  739. X/*
  740. X * This routine is called on each file argument.
  741. X */
  742. Xprocess_file (file)
  743. X     char *file;
  744. X{
  745. X  if (streq (file, outfile) && ! streq (outfile, "-"))
  746. X    {
  747. X      fprintf (stderr, "Skipping inclusion of %s in self.\n", file);
  748. X      return;
  749. X    }
  750. X  if (iflag)
  751. X    {
  752. X      fprintf (outf, "\f\n%s,include\n", file);
  753. X      return;
  754. X    }
  755. X  if (eflag)
  756. X    {
  757. X      char *cp = strrchr (file, '/');
  758. X      if (cp)  ++cp;  else  cp = file;
  759. X      if (streq (cp, outfile)) /*file == "TAGS"*/
  760. X    {
  761. X      fprintf (outf, "\f\n%s,include\n", file);
  762. X      return;
  763. X    }
  764. X    }
  765. X  find_entries (file);
  766. X  if (eflag)
  767. X    {
  768. X      fprintf (outf, "\f\n%s,%d\n",
  769. X           file, total_size_of_entries (head));
  770. X      put_entries (head);
  771. X      free_tree (head);
  772. X      head = NULL;
  773. X    }
  774. X}
  775. X
  776. X/*
  777. X * This routine sets up the boolean psuedo-functions which work
  778. X * by seting boolean flags dependent upon the corresponding character
  779. X * Every char which is NOT in that string is not a white char.  Therefore,
  780. X * all of the array "_wht" is set to FALSE, and then the elements
  781. X * subscripted by the chars in "white" are set to TRUE.  Thus "_wht"
  782. X * of a char is TRUE if it is the string "white", else FALSE.
  783. X */
  784. Xvoid
  785. Xinit ()
  786. X{
  787. X  reg char *sp;
  788. X  reg int i;
  789. X
  790. X  for (i = 0; i < 0177; i++)
  791. X    {
  792. X      _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
  793. X      _gd[i] = TRUE;
  794. X    }
  795. X  for (sp = white; *sp; sp++)
  796. X    _wht[*sp] = TRUE;
  797. X  for (sp = endtk; *sp; sp++)
  798. X    _etk[*sp] = TRUE;
  799. X  for (sp = intk; *sp; sp++)
  800. X    _itk[*sp] = TRUE;
  801. X  for (sp = begtk; *sp; sp++)
  802. X    _btk[*sp] = TRUE;
  803. X  for (sp = notgd; *sp; sp++)
  804. X    _gd[*sp] = FALSE;
  805. X  _wht[0] = _wht['\n'];
  806. X  _etk[0] = _etk['\n'];
  807. X  _btk[0] = _btk['\n'];
  808. X  _itk[0] = _itk['\n'];
  809. X  _gd[0] = _gd['\n'];
  810. X}
  811. X
  812. X/*
  813. X * This routine opens the specified file and calls the function
  814. X * which finds the function and type definitions.
  815. X */
  816. Xvoid
  817. Xfind_entries (file)
  818. X     char *file;
  819. X{
  820. X  char *cp;
  821. X
  822. X  inf = fopen (file, "r");
  823. X  if (inf == NULL)
  824. X    {
  825. X      perror (file);
  826. X      return;
  827. X    }
  828. X  curfile = savestr (file);
  829. X  cp = strrchr (file, '.');
  830. X  /* .tex, .aux or .bbl implies LaTeX source code */
  831. X  if (cp && (streq (cp + 1, "tex") || streq (cp + 1, "aux")
  832. X         || streq (cp + 1, "bbl")))
  833. X    {
  834. X      TEX_funcs (inf);
  835. X      goto close_and_return;
  836. X    }
  837. X  /* .l or .el or .lisp (or .cl or .clisp or ...) implies lisp source code */
  838. X  if (cp && (streq (cp + 1, "l") ||
  839. X         streq (cp + 1, "el") ||
  840. X         streq (cp + 1, "lsp") ||
  841. X         streq (cp + 1, "lisp") ||
  842. X         streq (cp + 1, "cl") ||
  843. X         streq (cp + 1, "clisp")))
  844. X    {
  845. X      L_funcs (inf);
  846. X      goto close_and_return;
  847. X    }
  848. X  /* .scm or .sm or .scheme or ... implies scheme source code */
  849. X  if (cp && (streq (cp + 1, "sm") ||
  850. X         streq (cp + 1, "scm") ||
  851. X         streq (cp + 1, "scheme") ||
  852. X         streq (cp + 1, "t") ||
  853. X         streq (cp + 1, "sch") ||
  854. X         streq (cp + 1, "SM") ||
  855. X         streq (cp + 1, "SCM") ||
  856. X             /* The `SCM' or `scm' prefix with a version number */
  857. X             (cp[-1] == 'm' && cp[-2] == 'c' && cp[-3] == 's') ||
  858. X             (cp[-1] == 'M' && cp[-2] == 'C' && cp[-3] == 'S')))
  859. X    {
  860. X      Scheme_funcs (inf);
  861. X      fclose (inf);
  862. X      return;
  863. X    }
  864. X  /* Assume that ".s" or ".a" is assembly code. -wolfgang.  */
  865. X  if (cp && (cp[1] == 's' || cp[1] == 'a') && cp[2] == '\0')
  866. X    {
  867. X      Asm_funcs (inf);
  868. X      fclose (inf);
  869. X      return;
  870. X    }
  871. X  /* .[HC]  .[hci]xx  .[hc]c  .[hc]pp: a C++ file */
  872. X  if (cp && (streq (cp + 1, "H") ||
  873. X         streq (cp + 1, "C") ||
  874. X         streq (cp + 1, "hxx") ||
  875. X         streq (cp + 1, "cxx") ||
  876. X         streq (cp + 1, "ixx") ||
  877. X         streq (cp + 1, "hc") ||
  878. X         streq (cp + 1, "cc") ||
  879. X         streq (cp + 1, "hpp") ||
  880. X         streq (cp + 1, "cpp")))
  881. X    {
  882. X      C_entries (C_PLPL);    /* C++ */
  883. X      goto close_and_return;
  884. X    }
  885. X  /* .cs or .hs: a C* file */
  886. X  if (cp && (cp[1] == 'c' || cp[1] == 'h') && cp[2] == 's' && cp[3] == '\0')
  887. X    {
  888. X      C_entries (C_STAR);
  889. X      goto close_and_return;
  890. X    }
  891. X  /* if not a .c or .h or .y file, try fortran */
  892. X  else if (cp && (cp[1] != 'c' && cp[1] != 'h' && cp[1] != 'y')
  893. X      && cp[2] == '\0')
  894. X    {
  895. X      if (PF_funcs (inf) != 0)
  896. X    goto close_and_return;
  897. X      rewind (inf);    /* no fortran tags found, try C */
  898. X    }
  899. X  C_entries (Cflag ? C_PLPL : 0);
  900. X
  901. X  close_and_return:
  902. X  (void) fclose (inf);
  903. X}
  904. X
  905. X/* Record a tag. */
  906. X/* Should take a TOKEN* instead!! */
  907. X
  908. Xvoid
  909. Xpfnote (name, is_func, rewritten, linestart, linelen, lno, cno)
  910. X     char *name;    /* tag name */
  911. X     logical is_func;    /* function or type name? */
  912. X     logical rewritten; /* tag different from text of definition? */
  913. X     char *linestart;
  914. X     int linelen;
  915. X     int lno;
  916. X     long cno;
  917. X{
  918. X  register char *fp;
  919. X  register NODE *np;
  920. X  char tem[51];
  921. X  char c;
  922. X
  923. X  np = (NODE *) malloc (sizeof (NODE));
  924. X  if (np == NULL)
  925. X    {
  926. X      if (!eflag)
  927. X    {
  928. X      /* It's okay to output early in etags -- it only disrupts the
  929. X       * character count of the tag entries, which is no longer used
  930. X       * by tags.el anyway.
  931. X       */
  932. X      error ("too many entries to sort");
  933. X    }
  934. X      put_entries (head);
  935. X      free_tree (head);
  936. X      head = NULL;
  937. X      np = xnew (1, NODE);
  938. X    }
  939. X  /* If ctags mode, change name "main" to M<thisfilename>. */
  940. X  if (!eflag && !xflag && streq (name, "main"))
  941. X    {
  942. X      fp = strrchr (curfile, '/');
  943. X      name = concat ("M", fp==0 ? curfile : fp+1, "");
  944. X      fp = strrchr (name, '.');
  945. X      if (fp && fp[1] != '\0' && fp[2] == '\0')
  946. X    *fp = 0;
  947. X      rewritten = TRUE;
  948. X    }
  949. X  np->name = savestr (name);
  950. X  np->file = curfile;
  951. X  np->is_func = is_func;
  952. X  np->rewritten = rewritten;
  953. X  np->lno = lno;
  954. X  /* UNCOMMENT THE +1 HERE: */
  955. X  np->cno = cno /* + 1 */;    /* our char numbers are 0-base; emacs's are 1-base */
  956. X  np->left = np->right = 0;
  957. X  if (eflag)
  958. X    {
  959. X      c = linestart[linelen];
  960. X      linestart[linelen] = 0;
  961. X    }
  962. X  else if (xflag == 0)
  963. X    {
  964. X      sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart);
  965. X      linestart = tem;
  966. X    }
  967. X  np->pat = savestr (linestart);
  968. X  if (eflag)
  969. X    {
  970. X      linestart[linelen] = c;
  971. X    }
  972. X
  973. X  add_node (np, &head);
  974. X}
  975. X
  976. X/*
  977. X * free_tree ()
  978. X *    recurse on left children, iterate on right children.
  979. X */
  980. Xvoid
  981. Xfree_tree (node)
  982. X     register NODE *node;
  983. X{
  984. X  while (node)
  985. X    {
  986. X      register NODE *node_right = node->right;
  987. X      free_tree (node->left);
  988. X      free (node->name);
  989. X      free (node->pat);
  990. X      free ((char *) node);
  991. X      node = node_right;
  992. X    }
  993. X}
  994. X
  995. X/*
  996. X * add_node ()
  997. X *    Adds a node to the tree of nodes.  In etags mode, we don't keep
  998. X *    it sorted; we just keep a linear list.  In ctags mode, maintain
  999. X *    an ordered tree, with no attempt at balancing.
  1000. X *
  1001. X *    add_node is the only function allowed to add nodes, so it can
  1002. X *    maintain state.
  1003. X */
  1004. Xvoid
  1005. Xadd_node (node, cur_node_p)
  1006. X     NODE *node, **cur_node_p;
  1007. X{
  1008. X  register int dif;
  1009. X  register NODE *cur_node = *cur_node_p;
  1010. X  static NODE *last_node = NULL;    /* careful */
  1011. X
  1012. X  if (cur_node == NULL)
  1013. X    {
  1014. X      *cur_node_p = node;
  1015. X      last_node = node;
  1016. X      return;
  1017. X    }
  1018. X
  1019. X  if (eflag)
  1020. X    {
  1021. X      /* Etags Mode */
  1022. X      if (!last_node)
  1023. X      fatal ("internal error in add_node");
  1024. X      last_node->right = node;
  1025. X      last_node = node;
  1026. X    }
  1027. X  else
  1028. X    {
  1029. X      /* Ctags Mode */
  1030. X      dif = strcmp (node->name, cur_node->name);
  1031. X
  1032. X      /*
  1033. X       * If this tag name matches an existing one, then
  1034. X       * do not add the node, but maybe print a warning.
  1035. X       */
  1036. X      if (!dif)
  1037. X    {
  1038. X      if (node->file == cur_node->file)
  1039. X        {
  1040. X          if (!wflag)
  1041. X        {
  1042. X          fprintf (stderr,"Duplicate entry in file %s, line %d: %s\n",
  1043. X               node->file,lineno,node->name);
  1044. X          fprintf (stderr,"Second entry ignored\n");
  1045. X        }
  1046. X          return;
  1047. X        }
  1048. X      if (!cur_node->been_warned && !wflag)
  1049. X        {
  1050. X          fprintf (stderr,
  1051. X               "Duplicate entry in files %s and %s: %s (Warning only)\n",
  1052. X               node->file, cur_node->file, node->name);
  1053. X        }
  1054. X      cur_node->been_warned = TRUE;
  1055. X      return;
  1056. X    } 
  1057. X
  1058. X      /* Actually add the node */
  1059. X      add_node (node, dif < 0 ? &cur_node->left : &cur_node->right);
  1060. X    }
  1061. X}
  1062. X
  1063. Xvoid
  1064. Xput_entries (node)
  1065. X     reg NODE *node;
  1066. X{
  1067. X  reg char *sp;
  1068. X
  1069. X  if (node == NULL)
  1070. X    return;
  1071. X
  1072. X  /* Output subentries that precede this one */
  1073. X  put_entries (node->left);
  1074. X
  1075. X  /* Output this entry */
  1076. X
  1077. X  if (eflag)
  1078. X    {
  1079. X      if (node->rewritten)
  1080. X    {
  1081. X      fprintf (outf, "%s\177%d,%d,\001%s\n",
  1082. X           node->pat, node->lno, node->cno, node->name);
  1083. X    }
  1084. X      else
  1085. X    {
  1086. X      fprintf (outf, "%s\177%d,%d\n",
  1087. X           node->pat, node->lno, node->cno);
  1088. X    }
  1089. X    }
  1090. X  else if (!xflag)
  1091. X    {
  1092. X      fprintf (outf, "%s\t%s\t",
  1093. X           node->name, node->file);
  1094. X
  1095. X      if (node->is_func)
  1096. X    {        /* a function */
  1097. X      putc (searchar, outf);
  1098. X      putc ('^', outf);
  1099. X
  1100. X      for (sp = node->pat; *sp; sp++)
  1101. X        {
  1102. X          if (*sp == '\\' || *sp == searchar)
  1103. X        putc ('\\', outf);
  1104. X          putc (*sp, outf);
  1105. X        }
  1106. X      putc (searchar, outf);
  1107. X    }
  1108. X      else
  1109. X    {        /* a typedef; text pattern inadequate */
  1110. X      fprintf (outf, "%d", node->lno);
  1111. X    }
  1112. X      putc ('\n', outf);
  1113. X    }
  1114. X  else if (vflag)
  1115. X    fprintf (stdout, "%s %s %d\n",
  1116. X         node->name, node->file, (node->lno+63)/64);
  1117. X  else
  1118. X    fprintf (stdout, "%-16s%4d %-16s %s\n",
  1119. X         node->name, node->lno, node->file, node->pat);
  1120. X
  1121. X  /* Output subentries that follow this one */
  1122. X  put_entries (node->right);
  1123. X}
  1124. X
  1125. X/* Length of a number's decimal representation. */
  1126. Xint
  1127. Xnumber_len (num)
  1128. X     long num;
  1129. X{
  1130. X  int len = 0;
  1131. X  if (!num)
  1132. X    return 1;
  1133. X  for (; num; num /= 10)
  1134. X    ++len;
  1135. X  return len;
  1136. X}
  1137. X  
  1138. X/*
  1139. X * Return total number of characters that put_entries will output for
  1140. X * the nodes in the subtree of the specified node.  Works only if eflag
  1141. X * is set, but called only in that case.  This count is irrelevant with
  1142. X * the new tags.el, but is still supplied for backward compatibility.
  1143. X */
  1144. Xint
  1145. Xtotal_size_of_entries (node)
  1146. X     reg NODE *node;
  1147. X{
  1148. X  reg int total;
  1149. X
  1150. X  if (node == NULL)
  1151. X    return 0;
  1152. X
  1153. X  total = 0;
  1154. X  for ( ; node; node = node->right)
  1155. X    {
  1156. X      /* Count left subentries. */
  1157. X      total += total_size_of_entries (node->left);
  1158. X
  1159. X      /* Count this entry */
  1160. X      total += strlen (node->pat) + 1;
  1161. X      total += number_len ((long) node->lno) + 1 + number_len (node->cno) + 1;
  1162. X      if (node->rewritten)
  1163. X    total += 2 + strlen (node->name); /* ,\001name */
  1164. X    }
  1165. X
  1166. X  return total;
  1167. X}
  1168. X
  1169. X/*
  1170. X * The C symbol tables.
  1171. X */
  1172. X
  1173. XStab *C_stab, *C_PLPL_stab, *C_STAR_stab;
  1174. X
  1175. X/*
  1176. X * SYNOPSIS
  1177. X *    Stab *get_C_stab (int c_ext);
  1178. X */
  1179. X#define get_C_stab(c_ext) ((c_ext&C_STAR) ? C_STAR_stab :        \
  1180. X               c_ext ? C_PLPL_stab :            \
  1181. X               C_stab)
  1182. X
  1183. Xvoid
  1184. Xadd_keyword (stab, sym, type)
  1185. X     Stab *stab;
  1186. X     char *sym;
  1187. X     enum sym_type type;
  1188. X{
  1189. X  stab_search (stab, sym, strlen (sym))->type = type;
  1190. X}
  1191. X
  1192. XStab *
  1193. XC_create_stab (c_ext)
  1194. X     int c_ext;
  1195. X{
  1196. X  Stab *stab;
  1197. X  
  1198. X  stab = stab_create ();
  1199. X
  1200. X  /* C, C++ and C* */
  1201. X  if (c_ext&C_PLPL)
  1202. X    add_keyword (stab, "class", st_C_struct);
  1203. X  if (c_ext&C_STAR)
  1204. X    add_keyword (stab, "domain", st_C_struct);
  1205. X  add_keyword (stab, "union", st_C_struct);
  1206. X  add_keyword (stab, "struct", st_C_struct);
  1207. X  add_keyword (stab, "enum", st_C_enum);
  1208. X  add_keyword (stab, "typedef", st_C_typedef);
  1209. X  add_keyword (stab, "define", st_C_define);
  1210. X
  1211. X  return stab;
  1212. X}
  1213. X
  1214. Xvoid
  1215. XC_create_stabs ()
  1216. X{
  1217. X  C_stab = C_create_stab (0);
  1218. X  C_PLPL_stab = C_create_stab (C_PLPL);
  1219. X  C_STAR_stab = C_create_stab (C_STAR|C_PLPL);
  1220. X}
  1221. X
  1222. X/*
  1223. X * C_entries ()
  1224. X *    This routine finds functions and typedefs in C syntax and adds them
  1225. X *    to the list.
  1226. X */
  1227. X
  1228. X#define CNL_SAVE_DEFINEDEF                        \
  1229. X{                                    \
  1230. X  prev_linepos = linepos;                        \
  1231. X  SET_FILEPOS (linepos, inf, charno);                    \
  1232. X  lineno++;                                \
  1233. X  charno += readline (&lb, inf);                    \
  1234. X  lp = lb.buffer;                            \
  1235. X}
  1236. X
  1237. X#define CNL                                \
  1238. X{                                    \
  1239. X  CNL_SAVE_DEFINEDEF;                            \
  1240. X  definedef = dnone;                            \
  1241. X}
  1242. X
  1243. Xvoid
  1244. XC_entries (c_ext)
  1245. X     int c_ext;        /* extension of C? */
  1246. X{
  1247. X  register int c;    /* latest char read; '\0' for end of line */
  1248. X  register int tokoff;    /* offset in line of beginning of latest token */
  1249. X  register int toklen;    /* length of latest token */
  1250. X  register char *lp;    /* pointer one beyond the character `c' */
  1251. X  logical incomm, inquote, inchar, midtoken;
  1252. X  int level;        /* current curly brace level */
  1253. X  char tokb[BUFSIZ];
  1254. X
  1255. X  lineno = 0;
  1256. X  charno = 0;
  1257. X  lp = lb.buffer;
  1258. X  *lp = 0;
  1259. X
  1260. X  definedef = dnone;
  1261. X  gotone = midtoken = inquote = inchar = incomm = FALSE;
  1262. X  level = 0;
  1263. X
  1264. X  C_create_stabs ();
  1265. X
  1266. X  while (! feof (inf))
  1267. X    {
  1268. X      c = *lp++;
  1269. X      if (c == 0)
  1270. X    {
  1271. X      CNL;
  1272. X      gotone = FALSE;
  1273. X    }
  1274. X      if (c == '\\')
  1275. X    {
  1276. X      c = *lp++;
  1277. X      if (c == 0)
  1278. X        {
  1279. X          CNL_SAVE_DEFINEDEF;
  1280. X        }
  1281. X      c = ' ';
  1282. X    } 
  1283. X      else if (incomm)
  1284. X    {
  1285. X      if (c == '*')
  1286. X        {
  1287. X          while ((c = *lp++) == '*')
  1288. X        continue;
  1289. X          if (c == 0)
  1290. X        {
  1291. X          CNL;
  1292. X        }
  1293. X          if (c == '/')
  1294. X        incomm = FALSE;
  1295. X        }
  1296. X    }
  1297. X      else if (inquote)
  1298. X    {
  1299. X      /*
  1300. X      * Too dumb to know about \" not being magic, but
  1301. X      * they usually occur in pairs anyway.
  1302. X      */
  1303. X      if (c == '"')
  1304. X        inquote = FALSE;
  1305. X      continue;
  1306. X    }
  1307. X      else if (inchar)
  1308. X    {
  1309. X      if (c == '\'')
  1310. X        inchar = FALSE;
  1311. X      continue;
  1312. X    }
  1313. X      else switch (c)
  1314. X    {
  1315. X    case '"':
  1316. X      inquote = TRUE;
  1317. X      continue;
  1318. X    case '\'':
  1319. X      inchar = TRUE;
  1320. X      continue;
  1321. X    case '/':
  1322. X      if (*lp == '*')
  1323. X        {
  1324. X          lp++;
  1325. X          incomm = TRUE;
  1326. X        }
  1327. X      else if (c_ext && *lp == '/')
  1328. X        {
  1329. X          CNL;    /* C++ comment: skip rest of line */
  1330. X        }
  1331. X      continue;
  1332. X    case '#':
  1333. X      if (lp == lb.buffer + 1 && definedef == dnone)
  1334. X        definedef = dsharpseen;
  1335. X      continue;
  1336. X
  1337. X    /*
  1338. X     * The next two are to help the strucdef state machine.
  1339. X     * They break when they are finished, so they don't interfere
  1340. X     * with anything else that is going on.
  1341. X     */
  1342. X        case ':':
  1343. X      if (structdef==stagseen)
  1344. X        structdef = scolonseen;
  1345. X      break;
  1346. X    /* Not a struct definition when semicolon seen in non-sinbody context. */
  1347. X    case ';':
  1348. X      if (structdef != snone && structdef != sinbody)
  1349. X        {
  1350. X          structdef = snone;
  1351. X          (void) strcpy (structtag, "<error 1>");
  1352. X        }
  1353. X      break;
  1354. X
  1355. X    case '{':
  1356. X      if (tydef == begin)
  1357. X        {
  1358. X          tydef = middle;
  1359. X        }
  1360. X      switch (structdef)
  1361. X        {
  1362. X        case skeyseen:        /* unnamed struct */
  1363. X          structtag[0] = '\0';
  1364. X          /* FALLTHRU */
  1365. X        case stagseen:
  1366. X        case scolonseen:        /* named struct */
  1367. X          structdef = sinbody;
  1368. X          break;
  1369. X        }
  1370. X      level++;
  1371. X      continue;
  1372. X    case '}':
  1373. X      if (!noindentflag && lp == lb.buffer + 1)
  1374. X        level = 0;    /* reset level if first column */
  1375. X      else if (level > 0)
  1376. X        level--;
  1377. X      if (level==0 && tydef==middle)
  1378. X        {
  1379. X          tydef=end;
  1380. X        }
  1381. X      if (level==0)
  1382. X        {
  1383. X          structdef = snone;
  1384. X          (void) strcpy (structtag, "<error 2>");
  1385. X        }
  1386. X      continue;
  1387. X    }
  1388. X      if (LEVEL_OK_FOR_FUNCDEF () && !inquote && !incomm && gotone == FALSE)
  1389. X    {
  1390. X      if (midtoken)
  1391. X        {
  1392. X          if (endtoken (c))
  1393. X        {
  1394. X          if (c_ext && c==':' && *lp==':' && intoken (*(lp+1)))
  1395. X            {
  1396. X              /*
  1397. X               * This handles :: in the middle, but not at beginning
  1398. X               * of an identifier.
  1399. X               */
  1400. X              lp += 2;
  1401. X              toklen += 3;
  1402. X            }
  1403. X          else
  1404. X            {
  1405. X              /*
  1406. X               * We've just finished lexing an identifier.
  1407. X               * Note that if `c' is '\0', `lb' is the NEXT
  1408. X               * line, `lp' points to the beginning of it, and
  1409. X               * old pointers into `lb.buffer' may no longer be
  1410. X               * valid, since `lb.buffer' may have been
  1411. X               * reallocated.  In this case (which corresponds
  1412. X               * to an identifier followed immediately by a
  1413. X               * newline), we re-read the line into lb1.
  1414. X               *
  1415. X               * This would be faster if the previous line's
  1416. X               * buffer were always saved.
  1417. X               */
  1418. X              logical is_func;
  1419. X              char *tok_linebuf;
  1420. X              TOKEN tok;
  1421. X              logical bingo, tok_at_end_of_line;
  1422. X              char *lp_tmp;    /* addressable */
  1423. X
  1424. X              if (c == '\0')
  1425. X            {
  1426. X              getline (GET_COOKIE (prev_linepos));
  1427. X              tok_linebuf = lb1.buffer;
  1428. X              tok_at_end_of_line = TRUE;
  1429. X              tok.linestart = prev_linepos;
  1430. X              tok.lineno = lineno - 1;
  1431. X            }
  1432. X              else
  1433. X            {
  1434. X              tok_linebuf = lb.buffer;
  1435. X              tok_at_end_of_line = FALSE;
  1436. X              tok.linestart = linepos;
  1437. X              tok.lineno = lineno;
  1438. X            }
  1439. X              tok.p = tok_linebuf + tokoff;
  1440. X              tok.len = toklen;
  1441. X              tok.rewritten = FALSE;
  1442. X              lp_tmp = lp;
  1443. X              bingo = consider_token (c, &lp_tmp, &tok,
  1444. X                          &is_func, c_ext, level);
  1445. X              lp = lp_tmp;
  1446. X              if (bingo)
  1447. X            {
  1448. X              if (GET_CHARNO (tok.linestart) != GET_CHARNO (linepos)
  1449. X                  && !tok_at_end_of_line)
  1450. X                {
  1451. X                  /*
  1452. X                   * Resynchronize tok.p to point into the right
  1453. X                   * linebuffer.
  1454. X                   */
  1455. X                  getline (GET_COOKIE (tok.linestart));
  1456. X                  if (!tok.rewritten)
  1457. X                tok.p = lb1.buffer + (tok.p - tok_linebuf);
  1458. X                  tok_linebuf = lb1.buffer;
  1459. X                }
  1460. X              if (structdef==sinbody && definedef==dnone && is_func)
  1461. X                {     /* function defined in C++ class body */
  1462. X                  sprintf (tokb, "%s::%.*s",
  1463. X                       structtag[0]=='\0' ? "_anonymous_"
  1464. X                                     : structtag,
  1465. X                       tok.len, tok.p);
  1466. X                  tok.rewritten = TRUE;
  1467. X                }
  1468. X              else
  1469. X                {
  1470. X                  sprintf (tokb, "%.*s", tok.len, tok.p);
  1471. X                }
  1472. X              pfnote (tokb, is_func, tok.rewritten, tok_linebuf,
  1473. X                  tokoff + toklen + (tok_at_end_of_line?0:1),
  1474. X                  tok.lineno, GET_CHARNO (tok.linestart));
  1475. X              gotone = is_func;    /* function */
  1476. X            }
  1477. X              midtoken = FALSE;
  1478. X            }
  1479. X            }
  1480. X          else if (intoken (c))
  1481. X        toklen++;
  1482. X        }
  1483. X      else if (begtoken (c))
  1484. X        {
  1485. X          tokoff = lp - 1 - lb.buffer;
  1486. X          toklen = 1;
  1487. X          midtoken = TRUE;
  1488. X        }
  1489. X    }
  1490. X      if (c == ';'  &&  tydef==end)    /* clean with typedefs */
  1491. X    tydef=none;
  1492. X    }
  1493. X}
  1494. X
  1495. X/*
  1496. X * consider_token ()
  1497. X *    checks to see if the current token is at the start of a
  1498. X *    function, or corresponds to a typedef.  It updates the input
  1499. X *    line pointer *LPP so that the '(' will be in it when it returns.
  1500. X *
  1501. X *    *IS_FUNC gets TRUE iff the token is a function.
  1502. X *    C_EXT is which language we are looking at.
  1503. X *
  1504. X *    In the future we will need some way to adjust where the end of
  1505. X *    the token is; for instance, implementing the C++ keyword
  1506. X *    `operator' properly will adjust the end of the token to be after
  1507. X *    whatever follows `operator'.
  1508. X *
  1509. X * Globals
  1510. X *    structdef    IN OUT
  1511. X *    definedef    IN OUT
  1512. X *    tydef        IN OUT
  1513. X */
  1514. X
  1515. Xlogical
  1516. Xconsider_token (c, lpp, tokp, is_func, c_ext, level)
  1517. X     reg char c;    /* IN: first char after the token */
  1518. X     char **lpp;    /* IN OUT: *lpp points to 2nd char after the token */
  1519. X     reg TOKEN *tokp;    /* IN */
  1520. X     logical *is_func;    /* OUT */
  1521. X     int c_ext;        /* IN */
  1522. X     int level;        /* IN */
  1523. X{
  1524. X  reg char *lp = *lpp;
  1525. X  /*
  1526. X   * next_token_is_func
  1527. X   *    set this to TRUE, and the next token considered is called a function.
  1528. X   */
  1529. X  static logical next_token_is_func;
  1530. X  logical firsttok;    /* TRUE if have seen first token in ()'s */
  1531. X  Stab_entry *tokse = stab_find (get_C_stab (c_ext), tokp->p, tokp->len);
  1532. X  enum sym_type toktype = stab_type (tokse);
  1533. X  *is_func = TRUE;            /* a function */
  1534. X
  1535. X  /*
  1536. X   * Advance the definedef state machine.  We set `gotone' for good measure;
  1537. X   * it's redundant.
  1538. X   */
  1539. X  switch (definedef)
  1540. X    {
  1541. X    case dnone:
  1542. X      /* We're not on a preprocessor line. */
  1543. X      break;
  1544. X    case dsharpseen:
  1545. X      if (toktype == st_C_define)
  1546. X    {
  1547. X      definedef = ddefineseen;
  1548. X      gotone = FALSE;
  1549. X    }
  1550. X      else
  1551. X    {
  1552. X      definedef = dignorerest;
  1553. X      gotone = TRUE;
  1554. X    }
  1555. X      goto badone;
  1556. X    case ddefineseen:
  1557. X      /*
  1558. X       * Make a tag for any macro.
  1559. X       * This will flub up if there is a newline immediately following
  1560. X       * the macro name.
  1561. X       */
  1562. X      *is_func = (c == '(');
  1563. X      definedef = dignorerest;
  1564. X      gotone = TRUE;
  1565. X      if (!*is_func && !constantflag)
  1566. X    goto badone;
  1567. X      goto goodone;
  1568. X    case dignorerest:
  1569. X      goto badone;
  1570. X    default:
  1571. X      error ("internal error: definedef value");
  1572. X    }
  1573. X
  1574. X  /*
  1575. X   * Skip whitespace and comments after the token.  This loop should
  1576. X   * also skip C++ comments.
  1577. X   */
  1578. X  while (1)
  1579. X    {
  1580. X      /* At whitespace => skip it.  */
  1581. X      if (iswhite (c))
  1582. X    {
  1583. X      c = *lp++;
  1584. X    }
  1585. X      /* At a comment => skip to end of comment.  */
  1586. X      else if (c == '/' && *lp == '*')
  1587. X    {
  1588. X      /* If we find a comment, skip it.  */
  1589. X      while (!(c == '*' && *lp == '/'))
  1590. X        {
  1591. X          c = *lp++;
  1592. X          if (c == 0)
  1593. X        {
  1594. X          if (feof (inf))
  1595. X            break;
  1596. X          CNL;
  1597. X        }
  1598. X        }
  1599. X      if (c == '*' && *lp == '/')
  1600. X        {
  1601. X          lp++;        /* lp now points past the '/' */
  1602. X          c = *lp++;    /* c is now the --whatever-- after the '/' */
  1603. X        }
  1604. X    }
  1605. X      else
  1606. X    break;
  1607. X
  1608. X      /* If we arrived at eof or eol, decide which one it is.
  1609. X     If it's eol, advance to the next line.  */
  1610. X
  1611. X      if (c == 0)
  1612. X    {
  1613. X      if (feof (inf))
  1614. X        break;
  1615. X      CNL;
  1616. X    }
  1617. X    }
  1618. X
  1619. X  /*
  1620. X   * If you have custom token types, or when configuration files can
  1621. X   * define custom token types, this switch will be larger.
  1622. X   */
  1623. X  switch (toktype)
  1624. X    {
  1625. X    case st_C_typedef:
  1626. X      if (tflag)
  1627. X    {
  1628. X      tydef = begin;
  1629. X      goto badone;
  1630. X    }
  1631. X      break;
  1632. X    }
  1633. X  
  1634. X  /*
  1635. X   * This structdef business is currently only invoked when level==0.
  1636. X   * It should be recursively invoked whatever the level, and a stack of
  1637. X   * states kept, to allow for definitions of structs within structs.
  1638. X   *
  1639. X   * This structdef business is NOT invoked when we are ctags and the
  1640. X   * file is plain C.  This is because a struct tag may have the same
  1641. X   * name as another tag, and this loses with ctags.
  1642. X   *
  1643. X   * This if statement deals with the tydef state machine as follows: if
  1644. X   * tydef==begin and token is struct/union/class/enum, goto badone.
  1645. X   * All the other code here is for the structdef state machine.
  1646. X   */
  1647. X  switch (toktype)
  1648. X    {
  1649. X    case st_C_struct:
  1650. X    case st_C_enum:
  1651. X      if (tydef==begin || (strflag && level==0 && structdef==snone))
  1652. X    {
  1653. X      structdef = skeyseen;
  1654. X      structkey = tokse;
  1655. X    }
  1656. X      goto badone;
  1657. X    }
  1658. X
  1659. X  if (structdef==skeyseen)
  1660. X    {
  1661. X      /* If next char is '{' or (for C++) ':', found a structure tag. */
  1662. X      if (c == '{' || c_ext && c == ':')
  1663. X    {
  1664. X      /*
  1665. X       * We should do this slightly differently for straight C:
  1666. X       * instead of defining `tag', as we now do, we should define
  1667. X       * `struct tag'.  (Do this only if the find-tag defaulting is
  1668. X       * done on a sophisticated per-mode basis, so that if the user
  1669. X       * says meta-. anywhere in `struct foo', the default comes out
  1670. X       * `struct foo', not `struct' or `foo'.)  This will require
  1671. X       * remembering which keyword (struct/union/class/enum) we saw, as a
  1672. X       * Stab_entry* -- this will also make it possible to merge the
  1673. X       * skeyseen and senumseen states, if we want.
  1674. X       */
  1675. X      if (stab_type (structkey) == st_C_struct)
  1676. X        {
  1677. X          (void) strncpy (structtag, tokp->p, tokp->len);
  1678. X          structtag[tokp->len] = '\0';    /* for struct/union/class */
  1679. X          structdef = stagseen;
  1680. X        }
  1681. X      else
  1682. X        {
  1683. X          structtag[0] = '\0';        /* for enum */
  1684. X        }
  1685. X      *is_func = FALSE;    /* not a function */
  1686. X      goto goodone;
  1687. X    }
  1688. X      else
  1689. X    {
  1690. X      /* Not a definition: reset structdef */
  1691. X      structdef = snone;
  1692. X      (void) strcpy (structtag, "<error 3>");
  1693. X    }
  1694. X      /* Now what?  And how does/should this stuff interact with tydef?? */
  1695. X      /* Also maybe reset lp to *lpp for benefit of the function finding code. */
  1696. X    }
  1697. X  if (tydef==begin)
  1698. X    {
  1699. X      tydef=end;
  1700. X      goto badone;
  1701. X    }
  1702. X  if (tydef==end)
  1703. X    {
  1704. X      *is_func = 0;
  1705. X      goto goodone;
  1706. X    }
  1707. X  /* Detect GNUmacs's function-defining macros. */
  1708. X  if (definedef == dnone && strneq (tokp->p, "DEF", 3))
  1709. X    {
  1710. X      next_token_is_func = TRUE;
  1711. X      goto badone;
  1712. X    }
  1713. X  if (next_token_is_func)
  1714. X    {
  1715. X      next_token_is_func = FALSE;
  1716. X      goto goodone;
  1717. X    }
  1718. X  if (c != '(')
  1719. X    goto badone;
  1720. X  firsttok = FALSE;
  1721. X  while ((c = *lp++) != ')')
  1722. X    {
  1723. X      if (c == 0)
  1724. X    {
  1725. X      if (feof (inf))
  1726. X        break;
  1727. X      CNL;
  1728. X    }
  1729. X      /*
  1730. X    * This line used to confuse ctags:
  1731. X    *    int    (*oldhup)();
  1732. X    * This fixes it. A nonwhite char before the first
  1733. X    * token, other than a / (in case of a comment in there)
  1734. X    * makes this not a declaration.
  1735. X    */
  1736. X      if (begtoken (c) || c=='/') firsttok++;
  1737. X      else if (! iswhite (c) && !firsttok) goto badone;
  1738. X    }
  1739. X  while (iswhite (c = *lp++))
  1740. X    {
  1741. X      if (c == 0)
  1742. X    {
  1743. X      if (feof (inf))
  1744. X        break;
  1745. X      CNL;
  1746. X    }
  1747. X    }
  1748. X  if (! isgood (c))
  1749. X    goto badone;
  1750. X
  1751. X goodone:
  1752. X  *lpp = lp - 1;
  1753. X  return TRUE;
  1754. X
  1755. X badone:
  1756. X  *lpp = lp - 1;
  1757. X  return FALSE;
  1758. X}
  1759. X
  1760. Xvoid
  1761. Xgetline (atcookie)
  1762. X     long atcookie;
  1763. X{
  1764. X  long saveftell = ftell (inf);
  1765. X
  1766. X  (void) fseek (inf, atcookie, 0);
  1767. X  (void) readline (&lb1, inf);
  1768. X  (void) fseek (inf, saveftell, 0);
  1769. X}
  1770. X
  1771. X/* Fortran parsing */
  1772. X
  1773. Xchar    *dbp;
  1774. Xint    pfcnt;
  1775. X
  1776. Xint
  1777. XPF_funcs (fi)
  1778. X     FILE *fi;
  1779. X{
  1780. X  lineno = 0;
  1781. X  charno = 0;
  1782. X  pfcnt = 0;
  1783. X
  1784. X  while (! feof (fi))
  1785. X    {
  1786. X      lineno++;
  1787. X      linecharno = charno;
  1788. X      charno += readline (&lb, fi);
  1789. X      dbp = lb.buffer;
  1790. X      if (*dbp == '%') dbp++ ;    /* Ratfor escape to fortran */
  1791. X      while (isspace (*dbp))
  1792. X    dbp++;
  1793. X      if (*dbp == 0)
  1794. X    continue;
  1795. X      switch (*dbp |' ')
  1796. X    {
  1797. X    case 'i':
  1798. X      if (tail ("integer"))
  1799. X        takeprec ();
  1800. X      break;
  1801. X    case 'r':
  1802. X      if (tail ("real"))
  1803. X        takeprec ();
  1804. X      break;
  1805. X    case 'l':
  1806. X      if (tail ("logical"))
  1807. X        takeprec ();
  1808. X      break;
  1809. X    case 'c':
  1810. X      if (tail ("complex") || tail ("character"))
  1811. X        takeprec ();
  1812. X      break;
  1813. X    case 'd':
  1814. X      if (tail ("double"))
  1815. X        {
  1816. X          while (isspace (*dbp))
  1817. X        dbp++;
  1818. X          if (*dbp == 0)
  1819. X        continue;
  1820. X          if (tail ("precision"))
  1821. X        break;
  1822. X          continue;
  1823. X        }
  1824. X      break;
  1825. X    }
  1826. X      while (isspace (*dbp))
  1827. X    dbp++;
  1828. X      if (*dbp == 0)
  1829. X    continue;
  1830. X      switch (*dbp|' ')
  1831. X    {
  1832. X    case 'f':
  1833. X      if (tail ("function"))
  1834. X        getit ();
  1835. X      continue;
  1836. X    case 's':
  1837. X      if (tail ("subroutine"))
  1838. X        getit ();
  1839. X      continue;
  1840. X    case 'p':
  1841. X      if (tail ("program"))
  1842. X        {
  1843. X          getit ();
  1844. X          continue;
  1845. X        }
  1846. X      if (tail ("procedure"))
  1847. X        getit ();
  1848. X      continue;
  1849. X    }
  1850. X    }
  1851. X  return (pfcnt);
  1852. X}
  1853. X
  1854. Xlogical
  1855. Xtail (cp)
  1856. X     char *cp;
  1857. X{
  1858. X  register int len = 0;
  1859. X
  1860. X  while (*cp && (*cp&~' ') == ((*(dbp+len))&~' '))
  1861. X    cp++, len++;
  1862. X  if (*cp == 0)
  1863. X    {
  1864. X      dbp += len;
  1865. X      return (1);
  1866. X    }
  1867. X  return (0);
  1868. X}
  1869. X
  1870. Xvoid
  1871. Xtakeprec ()
  1872. X{
  1873. X  while (isspace (*dbp))
  1874. X    dbp++;
  1875. X  if (*dbp != '*')
  1876. X    return;
  1877. X  dbp++;
  1878. X  while (isspace (*dbp))
  1879. X    dbp++;
  1880. X  if (! isdigit (*dbp))
  1881. X    {
  1882. X      --dbp;        /* force failure */
  1883. X      return;
  1884. X    }
  1885. X  do
  1886. X    dbp++;
  1887. X  while (isdigit (*dbp));
  1888. X}
  1889. X
  1890. Xvoid
  1891. Xgetit ()
  1892. X{
  1893. X  register char *cp;
  1894. X  char c;
  1895. X  char nambuf[BUFSIZ];
  1896. X
  1897. X  while (isspace (*dbp))
  1898. X    dbp++;
  1899. X  if (*dbp == 0 || (!isalpha(*dbp)) && (*dbp != '_'))
  1900. X    return;
  1901. X  for (cp = dbp+1; *cp && (isalpha(*cp) || isdigit(*cp) || (*cp == '_')); cp++)
  1902. X    continue;
  1903. X  c = cp[0];
  1904. X  cp[0] = 0;
  1905. X  (void) strcpy (nambuf, dbp);
  1906. X  cp[0] = c;
  1907. X  pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
  1908. X  pfcnt++;
  1909. X}
  1910. X
  1911. X/* Handle a file of assembler code.  */
  1912. X
  1913. XAsm_funcs (fi)
  1914. X     FILE *fi;
  1915. X{
  1916. X  int i;
  1917. X  register char c;
  1918. X
  1919. X  lineno = 0;
  1920. X  charno = 0;
  1921. X  pfcnt = 0;
  1922. X
  1923. X  while (! feof (fi))
  1924. X    {
  1925. X      lineno++;
  1926. X      linecharno = charno;
  1927. X      charno += readline (&lb, fi);
  1928. X      dbp = lb.buffer;
  1929. X
  1930. X      for (i = 0; ((c = dbp[i]) && !isspace(c)) && (c != ':') ; i++)
  1931. X    ;
  1932. X
  1933. X      if ((i > 0) && (c == ':'))
  1934. X    getit();
  1935. X    }
  1936. X}
  1937. X
  1938. X/*
  1939. X * lisp tag functions
  1940. X * just look for (def or (DEF
  1941. X */
  1942. X
  1943. Xvoid
  1944. XL_funcs (fi)
  1945. X     FILE *fi;
  1946. X{
  1947. X  lineno = 0;
  1948. X  charno = 0;
  1949. X  pfcnt = 0;
  1950. X
  1951. X  while (! feof (fi))
  1952. X    {
  1953. X      lineno++;
  1954. X      linecharno = charno;
  1955. X      charno += readline (&lb, fi);
  1956. X      dbp = lb.buffer;
  1957. X      if (dbp[0] == '(' && 
  1958. X      (dbp[1] == 'D' || dbp[1] == 'd') &&
  1959. X        (dbp[2] == 'E' || dbp[2] == 'e') &&
  1960. X          (dbp[3] == 'F' || dbp[3] == 'f'))
  1961. X    {
  1962. X      while (! isspace (*dbp)) dbp++;
  1963. X      while (isspace (*dbp)) dbp++;
  1964. X      L_getit ();
  1965. X    }
  1966. X    }
  1967. X}
  1968. X
  1969. Xvoid
  1970. XL_getit ()
  1971. X{
  1972. X  register char *cp;
  1973. X  char c;
  1974. X  char nambuf[BUFSIZ];
  1975. X
  1976. X  if (*dbp == 0) return;
  1977. X  for (cp = dbp+1; *cp && *cp != '(' && *cp != ' '; cp++)
  1978. X    continue;
  1979. X  c = cp[0];
  1980. X  cp[0] = 0;
  1981. X  (void) strcpy (nambuf, dbp);
  1982. X  cp[0] = c;
  1983. X  pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
  1984. X  pfcnt++;
  1985. X}
  1986. X
  1987. X/*
  1988. X * Scheme tag functions
  1989. X * look for (def... xyzzy
  1990. X * look for (def... (xyzzy
  1991. X * look for (def ... ((...(xyzzy ....
  1992. X * look for (set! xyzzy
  1993. X */
  1994. X
  1995. Xstatic void get_scheme ();
  1996. X
  1997. Xvoid
  1998. XScheme_funcs (fi)
  1999. X     FILE *fi;
  2000. X{
  2001. X  lineno = 0;
  2002. X  charno = 0;
  2003. X  pfcnt = 0;
  2004. X
  2005. X  while (! feof (fi))
  2006. X    {
  2007. X      lineno++;
  2008. X      linecharno = charno;
  2009. X      charno += readline (&lb, fi);
  2010. X      dbp = lb.buffer;
  2011. X      if (dbp[0] == '(' && 
  2012. X      (dbp[1] == 'D' || dbp[1] == 'd') &&
  2013. X        (dbp[2] == 'E' || dbp[2] == 'e') &&
  2014. X          (dbp[3] == 'F' || dbp[3] == 'f'))
  2015. X    {
  2016. X      while (! isspace (*dbp)) dbp++;
  2017. X          /* Skip over open parens and white space */
  2018. X          while (*dbp && (isspace (*dbp) || *dbp == '(')) dbp++;
  2019. X      get_scheme ();
  2020. X    }
  2021. X      if (dbp[0] == '(' && 
  2022. X      (dbp[1] == 'S' || dbp[1] == 's') &&
  2023. X        (dbp[2] == 'E' || dbp[2] == 'e') &&
  2024. X          (dbp[3] == 'T' || dbp[3] == 't') &&
  2025. X                (dbp[4] == '!' || dbp[4] == '!') &&
  2026. X                  (isspace (dbp[5])))
  2027. X    {
  2028. X      while (! isspace (*dbp)) dbp++;
  2029. X          /* Skip over white space */
  2030. X          while (isspace (*dbp)) dbp++;
  2031. X      get_scheme ();
  2032. X    }
  2033. X    }
  2034. X}
  2035. X
  2036. Xstatic void
  2037. Xget_scheme ()
  2038. X{
  2039. X  register char *cp;
  2040. X  char c;
  2041. X  char nambuf[BUFSIZ];
  2042. X
  2043. X  if (*dbp == 0) return;
  2044. X  /* Go till you get to white space or a syntactic break */
  2045. X  for (cp = dbp+1; *cp && *cp != '(' && *cp != ')' && ! isspace (*cp); cp++)
  2046. X    continue;
  2047. X  /* Null terminate the string there. */
  2048. X  c = cp[0];
  2049. X  cp[0] = 0;
  2050. X  /* Copy the string */
  2051. X  strcpy (nambuf, dbp);
  2052. X  /* Unterminate the string */
  2053. X  cp[0] = c;
  2054. X  /* Announce the change */
  2055. X  pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
  2056. X  pfcnt++;
  2057. X}
  2058. X
  2059. X/* Find tags in TeX and LaTeX input files.  */
  2060. X
  2061. X/* TEX_toktab is a table of TeX control sequences that define tags.
  2062. X   Each TEX_tabent records one such control sequence.
  2063. X   CONVERT THIS TO USE THE Stab TYPE!! */
  2064. X
  2065. Xstruct TEX_tabent
  2066. X{
  2067. X  char *name;
  2068. X  int len;
  2069. X};
  2070. X
  2071. Xstruct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
  2072. X
  2073. X/* Default set of control sequences to put into TEX_toktab.
  2074. X   The value of environment var TEXTAGS is prepended to this.  */
  2075. X
  2076. Xstatic char *TEX_defenv =
  2077. X  ":chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
  2078. X
  2079. Xvoid TEX_mode ();
  2080. Xstruct TEX_tabent *TEX_decode_env (); 
  2081. Xvoid TEX_getit ();
  2082. Xint TEX_Token ();
  2083. X
  2084. Xstatic char TEX_esc = '\\';
  2085. Xstatic char TEX_opgrp = '{';
  2086. Xstatic char TEX_clgrp = '}';
  2087. X
  2088. X/*
  2089. X * TeX/LaTeX scanning loop.
  2090. X */
  2091. X
  2092. Xvoid
  2093. XTEX_funcs (fi)
  2094. X    FILE *fi;
  2095. X{
  2096. X  char *lasthit;
  2097. X
  2098. X  lineno = 0;
  2099. X  charno = 0;
  2100. X  pfcnt = 0;
  2101. X
  2102. X  /* Select either \ or ! as escape character.  */
  2103. X  TEX_mode (fi);
  2104. X
  2105. X  /* Initialize token table once from environment. */
  2106. X  if (!TEX_toktab)
  2107. X    TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
  2108. X
  2109. X  while (! feof (fi))
  2110. X    {
  2111. X      lineno++;
  2112. X      linecharno = charno;
  2113. X      charno += readline (&lb, fi);
  2114. X      dbp = lb.buffer;
  2115. X      lasthit = dbp;
  2116. X
  2117. X      while (! feof (fi))
  2118. X    {    /* Scan each line in file */
  2119. X      lineno++;
  2120. X      linecharno = charno;
  2121. X      charno += readline (&lb, fi);
  2122. X      dbp = lb.buffer;
  2123. X      lasthit = dbp;
  2124. X      while (dbp = strchr (dbp, TEX_esc)) /* Look at each escape in line */
  2125. X        {
  2126. X          register int i;
  2127. X
  2128. X          if (! *(++dbp))
  2129. X        break;
  2130. X          linecharno += dbp - lasthit;
  2131. X          lasthit = dbp;
  2132. X          i = TEX_Token (lasthit);
  2133. X          if (0 <= i)
  2134. X        {
  2135. X          TEX_getit (lasthit, TEX_toktab[i].len);
  2136. X          break;        /* We only save a line once */
  2137. X        }
  2138. X        }
  2139. X    }
  2140. X    }
  2141. X}
  2142. X
  2143. X#define TEX_LESC '\\'
  2144. X#define TEX_SESC '!'
  2145. X
  2146. X/* Figure out whether TeX's escapechar is '\\' or '!' and set grouping */
  2147. X/* chars accordingly. */
  2148. X
  2149. Xvoid
  2150. XTEX_mode (f)
  2151. X     FILE *f;
  2152. X{
  2153. X  int c;
  2154. X
  2155. X  while ((c = getc (f)) != EOF)
  2156. X    if (c == TEX_LESC || c == TEX_SESC)
  2157. X      break;
  2158. X
  2159. X  if (c == TEX_LESC)
  2160. X    {
  2161. X      TEX_esc = TEX_LESC;
  2162. X      TEX_opgrp = '{';
  2163. X      TEX_clgrp = '}';
  2164. X    } 
  2165. X  else
  2166. X    {
  2167. X      TEX_esc = TEX_SESC;
  2168. X      TEX_opgrp = '<';
  2169. X      TEX_clgrp = '>';
  2170. X    }
  2171. X  rewind (f);
  2172. X}
  2173. X
  2174. X/* Read environment and prepend it to the default string. */
  2175. X/* Build token table. */
  2176. X
  2177. Xstruct TEX_tabent *
  2178. XTEX_decode_env (evarname, defenv)
  2179. X     char *evarname;
  2180. X     char *defenv;
  2181. X{
  2182. X  register char *env, *p;
  2183. X  extern char *savenstr (), *strchr ();
  2184. X
  2185. X  struct TEX_tabent *tab;
  2186. X  int size, i;
  2187. X
  2188. X  /* Append default string to environment. */
  2189. X  env = getenv (evarname);
  2190. X  if (!env)
  2191. X    env = defenv;
  2192. X  else
  2193. X    env = concat (env, defenv, "");
  2194. X
  2195. X  /* Allocate a token table */
  2196. X  for (size = 1, p=env; p;)
  2197. X    if ((p = strchr (p, ':')) && *(++p))
  2198. X      size++;
  2199. X  tab = xnew (size, struct TEX_tabent);
  2200. X
  2201. X  /* Unpack environment string into token table. Be careful about */
  2202. X  /* zero-length strings (leading ':', "::" and trailing ':') */
  2203. X  for (i = 0; *env;)
  2204. X    {
  2205. X      p = strchr (env, ':');
  2206. X      if (!p)            /* End of environment string. */
  2207. X    p = env + strlen (env);
  2208. X      if (p - env > 0)
  2209. X    {    /* Only non-zero strings. */
  2210. X      tab[i].name = savenstr (env, p - env);
  2211. X      tab[i].len = strlen (tab[i].name);
  2212. X      i++;
  2213. X    }
  2214. X      if (*p)
  2215. X    env = p + 1;
  2216. X      else
  2217. X    {
  2218. X      tab[i].name = NULL;    /* Mark end of table. */
  2219. X      tab[i].len = 0;
  2220. X      break;
  2221. X    }
  2222. X    }
  2223. X  return tab;
  2224. X}
  2225. X
  2226. X/* Record a tag defined by a TeX command of length LEN and starting at NAME.
  2227. X   The name being defined actually starts at (NAME + LEN + 1).
  2228. X   But we seem to include the TeX command in the tag name.  */
  2229. X
  2230. Xvoid
  2231. XTEX_getit (name, len)
  2232. X    char *name;
  2233. X    int len;
  2234. X{
  2235. X  char *p = name + len;
  2236. X  char nambuf[BUFSIZ];
  2237. X
  2238. X  if (*name == 0) return;
  2239. X
  2240. X  /* Let tag name extend to next group close (or end of line) */
  2241. X  while (*p && *p != TEX_clgrp)
  2242. X    p++;
  2243. X  (void) strncpy (nambuf, name, p - name);
  2244. X  nambuf[p - name] = 0;
  2245. X
  2246. X  pfnote (nambuf, TRUE, FALSE, lb.buffer, strlen (lb.buffer), lineno, linecharno);
  2247. X  pfcnt++;
  2248. X}
  2249. X
  2250. X/* If the text at CP matches one of the tag-defining TeX command names,
  2251. X   return the index of that command in TEX_toktab.
  2252. X   Otherwise return -1.  */
  2253. X
  2254. X/* Keep the capital `T' in `Token' for dumb truncating compilers
  2255. X   (this distinguishes it from `TEX_toktab' */
  2256. Xint
  2257. XTEX_Token (cp)
  2258. X    char *cp;
  2259. X{
  2260. X  int i;
  2261. X
  2262. X  for (i = 0; TEX_toktab[i].len > 0; i++)
  2263. X    if (strncmp (TEX_toktab[i].name, cp, TEX_toktab[i].len) == 0)
  2264. X      return i;
  2265. X  return -1;
  2266. X}
  2267. X
  2268. X/* Initialize a linebuffer for use */
  2269. X
  2270. Xvoid
  2271. Xinitbuffer (linebuffer)
  2272. X     struct linebuffer *linebuffer;
  2273. X{
  2274. X  linebuffer->size = 200;
  2275. X  linebuffer->buffer = xnew (200, char);
  2276. X}
  2277. X
  2278. X/*
  2279. X * Read a line of text from `stream' into `linebuffer'.
  2280. X * Return the number of characters read from `stream', which is the length of the
  2281. X * line including the newline, if any.
  2282. X */
  2283. Xlong
  2284. Xreadline (linebuffer, stream)
  2285. X     struct linebuffer *linebuffer;
  2286. X     register FILE *stream;
  2287. X{
  2288. X  char *buffer = linebuffer->buffer;
  2289. X  register char *p = linebuffer->buffer;
  2290. X  register char *pend = p + linebuffer->size;
  2291. X  int newline;    /* 1 if ended with newline, 0 if ended with EOF */
  2292. X
  2293. X  while (1)
  2294. X    {
  2295. X      register int c = getc (stream);
  2296. X      if (p == pend)
  2297. X    {
  2298. X      linebuffer->size *= 2;
  2299. X      buffer = (char *) xrealloc (buffer, linebuffer->size);
  2300. X      p += buffer - linebuffer->buffer;
  2301. X      pend = buffer + linebuffer->size;
  2302. X      linebuffer->buffer = buffer;
  2303. X    }
  2304. X      if (c < 0 || c == '\n')
  2305. X    {
  2306. X      *p = 0;
  2307. X      newline = (c == '\n' ? 1 : 0);
  2308. X      break;
  2309. X    }
  2310. X      *p++ = c;
  2311. X    }
  2312. X
  2313. X  return p - buffer + newline;
  2314. X}
  2315. X
  2316. Xchar *
  2317. Xsavestr (cp)
  2318. X     char *cp;
  2319. X{
  2320. X  return savenstr (cp, strlen (cp));
  2321. X}
  2322. X
  2323. Xchar *
  2324. Xsavenstr (cp, len)
  2325. X    char *cp;
  2326. X    int len;
  2327. X{
  2328. X  register char *dp;
  2329. X
  2330. X  dp = xnew (len + 1, char);
  2331. X  (void) strncpy (dp, cp, len);
  2332. X  dp[len] = '\0';
  2333. X  return dp;
  2334. X}
  2335. X
  2336. X#if 0
  2337. X/*
  2338. X * Return the ptr in sp at which the character c last
  2339. X * appears; NULL if not found
  2340. X *
  2341. X * Identical to ANSI C strrchr, included in case it's needed.
  2342. X */
  2343. X
  2344. Xchar *
  2345. Xstrrchr (sp, c)
  2346. X     register char *sp, c;
  2347. X{
  2348. X  register char *r;
  2349. X
  2350. X  r = NULL;
  2351. X  do
  2352. X    {
  2353. X      if (*sp == c)
  2354. X    r = sp;
  2355. X    } while (*sp++);
  2356. X  return (r);
  2357. X}
  2358. X
  2359. X/*
  2360. X * Return the ptr in sp at which the character c first
  2361. X * appears; NULL if not found
  2362. X *
  2363. X * Identical to ANSI C strchr, included for portability.
  2364. X */
  2365. X
  2366. Xchar *
  2367. Xstrchr (sp, c)
  2368. X     register char *sp, c;
  2369. X{
  2370. X  do
  2371. X    {
  2372. X      if (*sp == c)
  2373. X    return (sp);
  2374. X    } while (*sp++);
  2375. X  return (NULL);
  2376. X}
  2377. X
  2378. X#endif /* 0 */
  2379. X
  2380. X/* Print error message and exit.  */
  2381. X
  2382. X/* VARARGS1 */
  2383. Xvoid
  2384. Xfatal (s1, s2)
  2385. X     char *s1, *s2;
  2386. X{
  2387. X  error (s1, s2);
  2388. X  exit (1);
  2389. X}
  2390. X
  2391. X/* Print error message.  `s1' is printf control string, `s2' is arg for it. */
  2392. X
  2393. X/* VARARGS1 */
  2394. Xvoid
  2395. Xerror (s1, s2)
  2396. X     char *s1, *s2;
  2397. X{
  2398. X  fprintf (stderr, "%s: ", progname);
  2399. X  fprintf (stderr, s1, s2);
  2400. X  fprintf (stderr, "\n");
  2401. X}
  2402. X
  2403. X/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3.  */
  2404. X
  2405. Xchar *
  2406. Xconcat (s1, s2, s3)
  2407. X     char *s1, *s2, *s3;
  2408. X{
  2409. X  int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
  2410. X  char *result = xnew (len1 + len2 + len3 + 1, char);
  2411. X
  2412. X  (void) strcpy (result, s1);
  2413. X  (void) strcpy (result + len1, s2);
  2414. X  (void) strcpy (result + len1 + len2, s3);
  2415. X  *(result + len1 + len2 + len3) = 0;
  2416. X
  2417. X  return result;
  2418. X}
  2419. X
  2420. X/* Like malloc but get fatal error if memory is exhausted.  */
  2421. X
  2422. Xchar *
  2423. Xxmalloc (size)
  2424. X     int size;
  2425. X{
  2426. X  char *result = malloc (size);
  2427. X  if (!result)
  2428. X    fatal ("virtual memory exhausted", 0);
  2429. X  return result;
  2430. X}
  2431. X
  2432. Xchar *
  2433. Xxrealloc (ptr, size)
  2434. X     char *ptr;
  2435. X     int size;
  2436. X{
  2437. X  char *result = realloc (ptr, size);
  2438. X  if (!result)
  2439. X    fatal ("virtual memory exhausted");
  2440. X  return result;
  2441. X}
  2442. END_OF_FILE
  2443. if test 54188 -ne `wc -c <'etags.c'`; then
  2444.     echo shar: \"'etags.c'\" unpacked with wrong size!
  2445. fi
  2446. # end of 'etags.c'
  2447. fi
  2448. echo shar: End of archive 3 \(of 3\).
  2449. cp /dev/null ark3isdone
  2450. MISSING=""
  2451. for I in 1 2 3 ; do
  2452.     if test ! -f ark${I}isdone ; then
  2453.     MISSING="${MISSING} ${I}"
  2454.     fi
  2455. done
  2456. if test "${MISSING}" = "" ; then
  2457.     echo You have unpacked all 3 archives.
  2458.     rm -f ark[1-9]isdone
  2459. else
  2460.     echo You still need to unpack the following archives:
  2461.     echo "        " ${MISSING}
  2462. fi
  2463. ##  End of shell archive.
  2464. exit 0
  2465.  
  2466. exit 0 # Just in case...
  2467.