1 /* Tags file maker to go with GNUmacs
2 Copyright (C) 1984, 1987, 1988 Free Software Foundation, Inc. and Ken Arnold
6 BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
7 NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
8 WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
9 RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
10 WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
11 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
12 FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
13 AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
14 DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
17 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
18 STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
19 WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
20 LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
21 OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
22 USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
23 DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
24 A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
25 PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
26 DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
28 GENERAL PUBLIC LICENSE TO COPY
30 1. You may copy and distribute verbatim copies of this source file
31 as you receive it, in any medium, provided that you conspicuously
32 and appropriately publish on each copy a valid copyright notice
33 "Copyright (C) 1986 Free Software Foundation"; and include
34 following the copyright notice a verbatim copy of the above disclaimer
35 of warranty and of this License.
37 2. You may modify your copy or copies of this source file or
38 any portion of it, and copy and distribute such modifications under
39 the terms of Paragraph 1 above, provided that you also do the following:
41 a) cause the modified files to carry prominent notices stating
42 that you changed the files and the date of any change; and
44 b) cause the whole of any work that you distribute or publish,
45 that in whole or in part contains or is a derivative of this
46 program or any part thereof, to be licensed at no charge to all
47 third parties on terms identical to those contained in this
48 License Agreement (except that you may choose to grant more extensive
49 warranty protection to some or all third parties, at your option).
51 c) You may charge a distribution fee for the physical act of
52 transferring a copy, and you may at your option offer warranty
53 protection in exchange for a fee.
55 Mere aggregation of another unrelated program with this program (or its
56 derivative) on a volume of a storage or distribution medium does not bring
57 the other program under the scope of these terms.
59 3. You may copy and distribute this program (or a portion or derivative
60 of it, under Paragraph 2) in object code or executable form under the terms
61 of Paragraphs 1 and 2 above provided that you also do one of the following:
63 a) accompany it with the complete corresponding machine-readable
64 source code, which must be distributed under the terms of
65 Paragraphs 1 and 2 above; or,
67 b) accompany it with a written offer, valid for at least three
68 years, to give any third party free (except for a nominal
69 shipping charge) a complete machine-readable copy of the
70 corresponding source code, to be distributed under the terms of
71 Paragraphs 1 and 2 above; or,
73 c) accompany it with the information you received as to where the
74 corresponding source code may be obtained. (This alternative is
75 allowed only for noncommercial distribution and only if you
76 received the program in object code or executable form alone.)
78 For an executable file, complete source code means all the source code for
79 all modules it contains; but, as a special exception, it need not include
80 source code for modules which are standard libraries that accompany the
81 operating system on which the executable file runs.
83 4. You may not copy, sublicense, distribute or transfer this program
84 except as expressly provided under this License Agreement. Any attempt
85 otherwise to copy, sublicense, distribute or transfer this program is void and
86 your rights to use the program under this License agreement shall be
87 automatically terminated. However, parties who have received computer
88 software programs from you with this License Agreement will not have
89 their licenses terminated so long as such parties remain in full compliance.
91 In other words, you are welcome to use, share and improve this program.
92 You are forbidden to forbid anyone else to use, share and improve
93 what you give them. Help stamp out software-hoarding! */
98 /* Define the symbol ETAGS to make the program "etags",
99 which makes emacs-style tag tables by default.
100 Define CTAGS to make the program "ctags" compatible with the usual one.
101 Define neither one to get behavior that depends
102 on the name with which the program is invoked
103 (but we don't normally compile it that way). */
105 /* On VMS, CTAGS is not useful, so always do ETAGS. */
112 /* Exit codes for success and failure. */
133 #define iswhite(arg) (_wht[arg]) /* T if char is white */
134 #define begtoken(arg) (_btk[arg]) /* T if char can start token */
135 #define intoken(arg) (_itk[arg]) /* T if char can be in token */
136 #define endtoken(arg) (_etk[arg]) /* T if char ends tokens */
137 #define isgood(arg) (_gd[arg]) /* T if char can be after ')' */
139 #define max(I1,I2) (I1 > I2 ? I1 : I2)
141 /* cause token checking for typedef, struct, union, enum to distinguish
142 keywords from identifier-prefixes (e.g. struct vs struct_tag). */
143 #define istoken(s, tok, len) (!strncmp(s,tok,len) && endtoken(*((s)+(len))))
145 struct nd_st { /* sorting structure */
146 char *name; /* function or type name */
147 char *file; /* file name */
148 logical f; /* use pattern or line no */
149 int lno; /* line number tag is on */
150 long cno; /* character number line starts on */
151 char *pat; /* search pattern */
152 logical been_warned; /* set if noticed dup */
153 struct nd_st *left,*right; /* left and right sons */
157 typedef struct nd_st NODE;
159 int number; /* tokens found so far on line starting with # (including #) */
160 logical gotone, /* found a func already on line */
161 /* boolean "func" (see init) */
162 _wht[0177],_etk[0177],_itk[0177],_btk[0177],_gd[0177];
164 /* typedefs are recognized using a simple finite automata,
165 * tydef is its state variable.
167 typedef enum {none, begin, tag_ok, middle, end } TYST;
171 char searchar = '/'; /* use /.../ searches */
173 int lineno; /* line number of current line */
174 long charno; /* current character number */
175 long linecharno; /* character number of start of line */
177 char *curfile, /* current input file name */
178 *outfile= 0, /* output file */
179 *white = " \f\t\n", /* white chars */
180 *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?",
181 /* token ending chars */
182 *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$",
183 /* token starting chars */
184 *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789",
185 /* valid in-token chars */
186 *notgd = ",;"; /* non-valid after-function chars */
188 int file_num = 0; /* current file number */
189 int aflag = 0; /* -a: append to tags */
190 int tflag = 0; /* -t: create tags for typedefs */
191 int uflag = 0; /* -u: update tags */
192 int wflag = 0; /* -w: suppress warnings */
193 int vflag = 0; /* -v: create vgrind style index output */
194 int xflag = 0; /* -x: create cxref style output */
195 int eflag = 0; /* -e: emacs style output */
197 /* Name this program was invoked with. */
200 FILE *inf, /* ioptr for current input file */
201 *outf; /* ioptr for tags file */
203 NODE *head; /* the head of the sorted binary tree */
213 /* A `struct linebuffer' is a structure which holds a line of text.
214 `readline' reads a line from a stream into a linebuffer
215 and works regardless of the length of the line. */
223 struct linebuffer lb, lb1;
225 #if 0 /* VMS now provides the `system' function. */
234 struct dsc$descriptor_s command =
236 strlen(buf), DSC$K_DTYPE_T, DSC$K_CLASS_S, buf
255 extern char *gfnames();
256 extern char *massage_name();
268 char *subname = rindex (progname, '/');
269 if (subname++ == NULL)
271 eflag = ! strcmp(subname, "ctags");
276 while (ac > 1 && av[1][0] == '-')
278 for (i=1; av[1][i]; i++)
282 #ifndef VMS /* These options are useful only with ctags,
283 and VMS can't input them, so just omit them. */
303 "%s: -f flag may only be given once\n", progname);
307 if (ac <= 1 || av[1][0] == '\0')
310 "%s: -f flag must be followed by a filename\n",
349 fprintf (stderr, "Usage: %s [-aetwvx] [-f outfile] file ...\n", progname);
351 fprintf (stderr, "Usage: %s [-BFaetuwvx] [-f outfile] file ...\n", progname);
358 outfile = eflag ? "TAGS" : "tags";
361 init(); /* set up boolean "functions" */
366 * loop through files finding functions
370 outf = fopen (outfile, aflag ? "a" : "w");
373 fprintf (stderr, "%s: ", progname);
382 (this_file = gfnames (&ac, &av, &got_err)) != NULL; file_num++)
386 error("Can't find file %s\n", this_file);
391 this_file = massage_name (this_file);
393 for (; file_num < ac; file_num++)
395 this_file = av[file_num];
399 find_entries (this_file);
402 fprintf (outf, "\f\n%s,%d\n",
403 this_file, total_size_of_entries (head));
427 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
428 outfile, av[i], outfile);
433 outf = fopen(outfile, aflag ? "a" : "w");
436 fprintf (stderr, "%s: ", outfile);
445 sprintf(cmd, "sort %s -o %s", outfile, outfile);
453 * This routine sets up the boolean psuedo-functions which work
454 * by seting boolean flags dependent upon the corresponding character
455 * Every char which is NOT in that string is not a white char. Therefore,
456 * all of the array "_wht" is set to FALSE, and then the elements
457 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
458 * of a char is TRUE if it is the string "white", else FALSE.
466 for (i = 0; i < 0177; i++)
468 _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
471 for (sp = white; *sp; sp++)
473 for (sp = endtk; *sp; sp++)
475 for (sp = intk; *sp; sp++)
477 for (sp = begtk; *sp; sp++)
479 for (sp = notgd; *sp; sp++)
481 _wht[0] = _wht['\n'];
482 _etk[0] = _etk['\n'];
483 _btk[0] = _btk['\n'];
484 _itk[0] = _itk['\n'];
489 * This routine opens the specified file and calls the function
490 * which finds the function and type definitions.
497 if ((inf=fopen(file,"r")) == NULL)
499 fprintf (stderr, "%s: ", progname);
503 curfile = savestr(file);
504 cp = rindex(file, '.');
505 /* .tex, .aux or .bbl implies LaTeX source code */
506 if (cp && (!strcmp (cp + 1, "tex") || !strcmp (cp + 1, "aux")
507 || !strcmp (cp + 1, "bbl")))
513 /* .l or .el or .lisp (or .cl or .clisp or ...) implies lisp source code */
514 if (cp && (!strcmp (cp + 1, "l") ||
515 !strcmp (cp + 1, "el") ||
516 !strcmp (cp + 1, "lsp") ||
517 !strcmp (cp + 1, "lisp") ||
518 !strcmp (cp + 1, "cl") ||
519 !strcmp (cp + 1, "clisp")))
525 /* .scm or .sm or .scheme implies scheme source code */
526 if (cp && (!strcmp (cp + 1, "sm")
527 || !strcmp (cp + 1, "scm")
528 || !strcmp (cp + 1, "scheme")
529 || !strcmp (cp + 1, "t")
530 || !strcmp (cp + 1, "sch")
531 || !strcmp (cp + 1, "SM")
532 || !strcmp (cp + 1, "SCM")
533 /* The `SCM' or `scm' prefix with a version number */
534 || (cp[-1] == 'm' && cp[-2] == 'c' && cp[-3] == 's')
535 || (cp[-1] == 'M' && cp[-2] == 'C' && cp[-3] == 'S')))
541 /* .M implies Mcode source code */
542 if (cp && !strcmp (cp + 1, "M"))
549 /* if not a .c or .h or .y file, try fortran */
550 if (cp && (cp[1] != 'c' && cp[1] != 'h' && cp[1] != 'y')
553 if (PF_funcs(inf) != 0)
558 rewind(inf); /* no fortran tags found, try C */
564 /* Record a tag on the current line.
565 name is the tag name,
566 f is nonzero to use a pattern, zero to use line number instead. */
568 pfnote (name, f, linestart, linelen, lno, cno)
570 logical f; /* f == TRUE when function */
581 if ((np = (NODE *) malloc (sizeof (NODE))) == NULL)
583 fprintf(stderr, "%s: too many entries to sort\n", progname);
587 np = (NODE *) xmalloc(sizeof (NODE));
589 /* Change name "main" to M<thisfilename>. */
590 if (!eflag && !xflag && !strcmp(name, "main"))
592 fp = rindex(curfile, '/');
597 altname = concat ("M", fp, "");
598 fp = rindex(altname, '.');
599 if (fp && fp[2] == 0)
603 np->name = savestr(name);
608 np->left = np->right = 0;
611 linestart[linelen] = 0;
615 sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart);
618 np->pat = savestr (linestart);
630 free_tree(node->right);
636 add_node(node, cur_node)
637 NODE *node,*cur_node;
641 dif = strcmp(node->name, cur_node->name);
643 /* If this tag name matches an existing one, then
644 unless -e was given, do not add the node, but maybe print a warning */
647 if (node->file == cur_node->file)
651 fprintf(stderr,"%s: Duplicate entry in file %s, line %d: %s\n",
652 progname, node->file,lineno,node->name);
653 fprintf(stderr,"Second entry ignored\n");
657 if (!cur_node->been_warned)
659 fprintf(stderr,"%s: Duplicate entry in files %s and %s: %s (Warning only)\n",
660 progname, node->file, cur_node->file, node->name);
661 cur_node->been_warned = TRUE;
665 /* Actually add the node */
668 if (cur_node->left != NULL)
669 add_node(node,cur_node->left);
671 cur_node->left = node;
674 if (cur_node->right != NULL)
675 add_node(node,cur_node->right);
677 cur_node->right = node;
688 /* Output subentries that precede this one */
689 put_entries (node->left);
691 /* Output this entry */
695 fprintf (outf, "%s%c%d,%d\n",
696 node->pat, 0177, node->lno, node->cno);
700 fprintf (outf, "%s\t%s\t",
701 node->name, node->file);
705 putc (searchar, outf);
708 for (sp = node->pat; *sp; sp++)
710 if (*sp == '\\' || *sp == searchar)
714 putc (searchar, outf);
717 { /* a typedef; text pattern inadequate */
718 fprintf (outf, "%d", node->lno);
723 fprintf (stdout, "%s %s %d\n",
724 node->name, node->file, (node->lno+63)/64);
726 fprintf (stdout, "%-16s%4d %-16s %s\n",
727 node->name, node->lno, node->file, node->pat);
729 /* Output subentries that follow this one */
730 put_entries (node->right);
733 /* Return total number of characters that put_entries will output for
734 the nodes in the subtree of the specified node.
735 Works only if eflag is set, but called only in that case. */
737 total_size_of_entries(node)
746 /* Count subentries that precede this one */
747 total = total_size_of_entries (node->left);
749 /* Count subentries that follow this one */
750 total += total_size_of_entries (node->right);
752 /* Count this entry */
754 total += strlen (node->pat) + 3;
774 * This routine finds functions and typedefs in C syntax and adds them
779 #define VMS_SET_LINECHARNO (vmslinecharno = ftell(inf))
781 #define VMS_SET_LINECHARNO
784 #define CNL_SAVE_NUMBER \
786 VMS_SET_LINECHARNO; \
787 linecharno = charno; lineno++; \
788 charno += 1 + readline (&lb, inf); \
801 register char *token, *tp, *lp;
802 logical incomm, inquote, inchar, midtoken;
812 gotone = midtoken = inquote = inchar = incomm = FALSE;
834 while ((c = *lp++) == '*')
845 * Too dumb to know about \" not being magic, but
846 * they usually occur in pairs anyway.
874 if (lp == lb.buffer + 1)
885 if (lp == lb.buffer + 1)
886 level = 0; /* reset */
889 if (!level && tydef==middle)
895 if (!level && !inquote && !incomm && gotone == FALSE)
902 char *buf = lb.buffer;
903 int endpos = lp - lb.buffer;
906 long linestart = linecharno;
908 long vmslinestart = vmslinecharno;
910 int tem = consider_token (&lp1, token, &f, level);
914 if (linestart != linecharno)
917 getline (vmslinestart);
921 strncpy (tok, token + (lb1.buffer - buf),
924 pfnote(tok, f, lb1.buffer, endpos, line, linestart);
928 strncpy (tok, token, tp-token+1);
930 pfnote(tok, f, lb.buffer, endpos, line, linestart);
932 gotone = f; /* function */
940 else if (begtoken(c))
946 if (c == ';' && tydef==end) /* clean with typedefs */
952 * This routine checks to see if the current token is
953 * at the start of a function, or corresponds to a typedef
954 * It updates the input line * so that the '(' will be
955 * in it when it returns.
957 consider_token (lpp, token, f, level)
963 static logical next_token_is_func;
964 logical firsttok; /* T if have seen first token in ()'s */
967 *f = 1; /* a function */
971 { /* space is not allowed in macro defs */
985 /* the following tries to make it so that a #define a b(c) */
986 /* doesn't count as a define of b. */
989 if (number >= 4 || (number==2 && strncmp (token, "define", 6)==0))
991 /* Force the next symbol to be recognised, even if it is #define a b(c)! */
992 if(number == 2) next_token_is_func = 1;
1000 /* check for the typedef cases */
1001 if (tflag && istoken(token, "typedef", 7))
1006 if (tydef==begin && (istoken(token, "struct", 6) ||
1007 istoken(token, "union", 5) || istoken(token, "enum", 4)))
1017 if (tydef==begin) /* e.g. typedef ->int<- */
1022 if (tydef==middle && level == 0) /* e.g. typedef struct tag ->struct_t<- */
1032 /* Detect GNUmacs's function-defining macros. */
1033 if (!number && !strncmp (token, "DEF", 3))
1036 next_token_is_func = 1;
1039 if (next_token_is_func)
1041 next_token_is_func = 0;
1048 while ((c = *lp++) != ')')
1057 * This line used to confuse ctags:
1059 * This fixes it. A nonwhite char before the first
1060 * token, other than a / (in case of a comment in there)
1061 * makes this not a declaration.
1063 if (begtoken(c) || c=='/') firsttok++;
1064 else if (!iswhite(c) && !firsttok) goto badone;
1066 while (iswhite (c = *lp++))
1084 long saveftell = ftell (inf);
1086 fseek (inf, atchar, 0);
1087 readline (&lb1, inf);
1088 fseek (inf, saveftell, 0);
1091 /* Fortran parsing */
1106 linecharno = charno;
1107 charno += readline (&lb, fi) + 1;
1109 if (*dbp == '%') dbp++ ; /* Ratfor escape to fortran */
1110 while (isspace(*dbp))
1117 if (tail("integer"))
1125 if (tail("logical"))
1129 if (tail("complex") || tail("character"))
1135 while (isspace(*dbp))
1139 if (tail("precision"))
1145 while (isspace(*dbp))
1152 if (tail("function"))
1156 if (tail("subroutine"))
1160 if (tail("program"))
1165 if (tail("procedure"))
1176 register int len = 0;
1178 while (*cp && (*cp&~' ') == ((*(dbp+len))&~' '))
1190 while (isspace(*dbp))
1195 while (isspace(*dbp))
1199 --dbp; /* force failure */
1204 while (isdigit(*dbp));
1211 char nambuf[BUFSIZ];
1213 while (isspace(*dbp))
1215 if (*dbp == 0 || !isalpha(*dbp))
1217 for (cp = dbp+1; *cp && (isalpha(*cp) || isdigit(*cp)); cp++)
1221 strcpy(nambuf, dbp);
1223 pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
1228 * lisp tag functions
1229 * just look for (def or (DEF
1242 linecharno = charno;
1243 charno += readline (&lb, fi) + 1;
1245 if (dbp[0] == '(' &&
1246 (dbp[1] == 'D' || dbp[1] == 'd') &&
1247 (dbp[2] == 'E' || dbp[2] == 'e') &&
1248 (dbp[3] == 'F' || dbp[3] == 'f'))
1250 while (!isspace(*dbp)) dbp++;
1251 while (isspace(*dbp)) dbp++;
1261 char nambuf[BUFSIZ];
1263 if (*dbp == 0) return;
1264 for (cp = dbp+1; *cp && *cp != '(' && *cp != ' '; cp++)
1268 strcpy(nambuf, dbp);
1270 pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
1275 * Scheme tag functions
1276 * look for (def... xyzzy
1277 * look for (def... (xyzzy
1278 * look for (def ... ((...(xyzzy ....
1279 * look for (set! xyzzy
1282 static get_scheme ();
1293 linecharno = charno;
1294 charno += readline (&lb, fi) + 1;
1296 if (dbp[0] == '(' &&
1297 (dbp[1] == 'D' || dbp[1] == 'd') &&
1298 (dbp[2] == 'E' || dbp[2] == 'e') &&
1299 (dbp[3] == 'F' || dbp[3] == 'f'))
1301 while (!isspace(*dbp)) dbp++;
1302 /* Skip over open parens and white space */
1303 while (*dbp && (isspace(*dbp) || *dbp == '(')) dbp++;
1306 if (dbp[0] == '(' &&
1307 (dbp[1] == 'S' || dbp[1] == 's') &&
1308 (dbp[2] == 'E' || dbp[2] == 'e') &&
1309 (dbp[3] == 'T' || dbp[3] == 't') &&
1310 (dbp[4] == '!' || dbp[4] == '!') &&
1313 while (!isspace(*dbp)) dbp++;
1314 /* Skip over white space */
1315 while (isspace(*dbp)) dbp++;
1326 char nambuf[BUFSIZ];
1328 if (*dbp == 0) return;
1329 /* Go till you get to white space or a syntactic break */
1330 for (cp = dbp+1; *cp && *cp != '(' && *cp != ')' && !isspace(*cp); cp++)
1332 /* Null terminate the string there. */
1335 /* Copy the string */
1336 strcpy(nambuf, dbp);
1337 /* Unterminate the string */
1339 /* Announce the change */
1340 pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
1343 static get_mcode ();
1354 linecharno = charno;
1355 charno += readline (&lb, fi) + 1;
1360 /* Skip over white space */
1361 while (isspace(*dbp)) dbp++;
1372 char nambuf[BUFSIZ];
1374 if (*dbp == 0) return;
1375 /* Go till you get to white space or a syntactic break */
1376 for (cp = dbp; *cp && *cp != ':' && *cp != ';' && !isspace(*cp); cp++)
1381 /* Null terminate the string there. */
1384 /* Copy the string */
1385 strcpy(nambuf, dbp);
1386 /* Unterminate the string */
1388 /* Announce the change */
1389 pfnote(nambuf, TRUE, lb.buffer, strlen(lb.buffer), lineno, linecharno);
1399 /* Find tags in TeX and LaTeX input files. */
1401 /* TEX_toktab is a table of TeX control sequences that define tags.
1402 Each TEX_tabent records one such control sequence. */
1410 struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
1412 /* Default set of control sequences to put into TEX_toktab.
1413 The value of environment var TEXTAGS is prepended to this. */
1415 static char *TEX_defenv =
1416 ":chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
1418 struct TEX_tabent *TEX_decode_env ();
1420 static char TEX_esc = '\\';
1421 static char TEX_opgrp = '{';
1422 static char TEX_clgrp = '}';
1425 * TeX/LaTeX scanning loop.
1437 /* Select either \ or ! as escape character. */
1440 /* Initialize token table once from environment. */
1442 TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
1447 linecharno = charno;
1448 charno += readline (&lb, fi) + 1;
1453 { /* Scan each line in file */
1455 linecharno = charno;
1456 charno += readline (&lb, fi) + 1;
1459 while (dbp = index (dbp, TEX_esc)) /* Look at each escape in line */
1465 linecharno += dbp - lasthit;
1467 i = TEX_Token (lasthit);
1470 TEX_getit (lasthit, TEX_toktab[i].len);
1471 break; /* We only save a line once */
1478 #define TEX_LESC '\\'
1479 #define TEX_SESC '!'
1481 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping */
1482 /* chars accordingly. */
1489 while ((c = getc (f)) != EOF)
1490 if (c == TEX_LESC || c == TEX_SESC)
1508 /* Read environment and prepend it to the default string. */
1509 /* Build token table. */
1512 TEX_decode_env (evarname, defenv)
1516 register char *env, *p;
1517 extern char *savenstr (), *index ();
1519 struct TEX_tabent *tab;
1522 /* Append deafult string to environment. */
1523 env = (char *) getenv (evarname);
1527 env = concat (env, defenv, "");
1529 /* Allocate a token table */
1530 for (size = 1, p=env; p;)
1531 if ((p = index (p, ':')) && *(++p))
1533 tab = (struct TEX_tabent *) xmalloc (size * sizeof (struct TEX_tabent));
1535 /* Unpack environment string into token table. Be careful about */
1536 /* zero-length strings (leading ':', "::" and trailing ':') */
1539 p = index (env, ':');
1540 if (!p) /* End of environment string. */
1541 p = env + strlen (env);
1543 { /* Only non-zero strings. */
1544 tab[i].name = savenstr (env, p - env);
1545 tab[i].len = strlen (tab[i].name);
1552 tab[i].name = NULL; /* Mark end of table. */
1560 /* Record a tag defined by a TeX command of length LEN and starting at NAME.
1561 The name being defined actually starts at (NAME + LEN + 1).
1562 But we seem to include the TeX command in the tag name. */
1564 TEX_getit (name, len)
1568 char *p = name + len;
1569 char nambuf[BUFSIZ];
1571 if (*name == 0) return;
1573 /* Let tag name extend to next group close (or end of line) */
1574 while (*p && *p != TEX_clgrp)
1576 strncpy (nambuf, name, p - name);
1577 nambuf[p - name] = 0;
1579 pfnote (nambuf, TRUE, lb.buffer, strlen (lb.buffer), lineno, linecharno);
1583 /* If the text at CP matches one of the tag-defining TeX command names,
1584 return the index of that command in TEX_toktab.
1585 Otherwise return -1. */
1587 /* Keep the capital `T' in `Token' for dumb truncating compilers
1588 (this distinguishes it from `TEX_toktab' */
1594 for (i = 0; TEX_toktab[i].len > 0; i++)
1595 if (strncmp (TEX_toktab[i].name, cp, TEX_toktab[i].len) == 0)
1600 /* Initialize a linebuffer for use */
1603 initbuffer (linebuffer)
1604 struct linebuffer *linebuffer;
1606 linebuffer->size = 200;
1607 linebuffer->buffer = (char *) xmalloc (200);
1610 /* Read a line of text from `stream' into `linebuffer'.
1611 Return the length of the line. */
1614 readline (linebuffer, stream)
1615 struct linebuffer *linebuffer;
1616 register FILE *stream;
1618 char *buffer = linebuffer->buffer;
1619 register char *p = linebuffer->buffer;
1620 register char *pend = p + linebuffer->size;
1624 int c = getc (stream);
1627 linebuffer->size *= 2;
1628 buffer = (char *) xrealloc (buffer, linebuffer->size);
1629 p += buffer - linebuffer->buffer;
1630 pend = buffer + linebuffer->size;
1631 linebuffer->buffer = buffer;
1633 if (c < 0 || c == '\n')
1648 return savenstr (cp, strlen (cp));
1658 dp = (char *) xmalloc (len + 1);
1659 strncpy (dp, cp, len);
1665 * Return the ptr in sp at which the character c last
1666 * appears; NULL if not found
1668 * Identical to v7 rindex, included for portability.
1673 register char *sp, c;
1687 * Return the ptr in sp at which the character c first
1688 * appears; NULL if not found
1690 * Identical to v7 index, included for portability.
1695 register char *sp, c;
1705 /* Print error message and exit. */
1714 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
1719 fprintf (stderr, "%s: ", progname);
1720 fprintf (stderr, s1, s2);
1721 fprintf (stderr, "\n");
1724 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
1730 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
1731 char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
1733 strcpy (result, s1);
1734 strcpy (result + len1, s2);
1735 strcpy (result + len1 + len2, s3);
1736 *(result + len1 + len2 + len3) = 0;
1741 /* Like malloc but get fatal error if memory is exhausted. */
1747 int result = malloc (size);
1749 fatal ("virtual memory exhausted", 0);
1754 xrealloc (ptr, size)
1758 int result = realloc (ptr, size);
1760 fatal ("virtual memory exhausted");