/usr.bin/ctags/ctags.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 322 lines · 237 code · 28 blank · 57 comment · 59 complexity · ceb14064a00a7ccabd6cae4de2b7120b MD5 · raw file

  1. /*
  2. * Copyright (c) 1987, 1993, 1994, 1995
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 4. Neither the name of the University nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. #ifndef lint
  30. static const char copyright[] =
  31. "@(#) Copyright (c) 1987, 1993, 1994, 1995\n\
  32. The Regents of the University of California. All rights reserved.\n";
  33. #endif
  34. #if 0
  35. #ifndef lint
  36. static char sccsid[] = "@(#)ctags.c 8.4 (Berkeley) 2/7/95";
  37. #endif
  38. #endif
  39. #include <sys/cdefs.h>
  40. #include <sys/types.h>
  41. #include <sys/wait.h>
  42. __FBSDID("$FreeBSD$");
  43. #include <err.h>
  44. #include <limits.h>
  45. #include <locale.h>
  46. #include <regex.h>
  47. #include <stdio.h>
  48. #include <stdlib.h>
  49. #include <string.h>
  50. #include <unistd.h>
  51. #include "ctags.h"
  52. /*
  53. * ctags: create a tags file
  54. */
  55. NODE *head; /* head of the sorted binary tree */
  56. /* boolean "func" (see init()) */
  57. bool _wht[256], _etk[256], _itk[256], _btk[256], _gd[256];
  58. FILE *inf; /* ioptr for current input file */
  59. FILE *outf; /* ioptr for tags file */
  60. long lineftell; /* ftell after getc( inf ) == '\n' */
  61. int lineno; /* line number of current line */
  62. int dflag; /* -d: non-macro defines */
  63. int tflag; /* -t: create tags for typedefs */
  64. int vflag; /* -v: vgrind style index output */
  65. int wflag; /* -w: suppress warnings */
  66. int xflag; /* -x: cxref style output */
  67. char *curfile; /* current input file name */
  68. char searchar = '/'; /* use /.../ searches by default */
  69. char lbuf[LINE_MAX];
  70. void init(void);
  71. void find_entries(char *);
  72. static void usage(void);
  73. int
  74. main(int argc, char **argv)
  75. {
  76. static const char *outfile = "tags"; /* output file */
  77. int aflag; /* -a: append to tags */
  78. int uflag; /* -u: update tags */
  79. int exit_val; /* exit value */
  80. int step; /* step through args */
  81. int ch; /* getopts char */
  82. setlocale(LC_ALL, "");
  83. aflag = uflag = NO;
  84. tflag = YES;
  85. while ((ch = getopt(argc, argv, "BFTadf:tuwvx")) != -1)
  86. switch(ch) {
  87. case 'B':
  88. searchar = '?';
  89. break;
  90. case 'F':
  91. searchar = '/';
  92. break;
  93. case 'T':
  94. tflag = NO;
  95. break;
  96. case 'a':
  97. aflag++;
  98. break;
  99. case 'd':
  100. dflag++;
  101. break;
  102. case 'f':
  103. outfile = optarg;
  104. break;
  105. case 't':
  106. tflag = YES;
  107. break;
  108. case 'u':
  109. uflag++;
  110. break;
  111. case 'w':
  112. wflag++;
  113. break;
  114. case 'v':
  115. vflag++;
  116. case 'x':
  117. xflag++;
  118. break;
  119. case '?':
  120. default:
  121. usage();
  122. }
  123. argv += optind;
  124. argc -= optind;
  125. if (!argc)
  126. usage();
  127. if (!xflag)
  128. setlocale(LC_COLLATE, "C");
  129. init();
  130. for (exit_val = step = 0; step < argc; ++step)
  131. if (!(inf = fopen(argv[step], "r"))) {
  132. warn("%s", argv[step]);
  133. exit_val = 1;
  134. }
  135. else {
  136. curfile = argv[step];
  137. find_entries(argv[step]);
  138. (void)fclose(inf);
  139. }
  140. if (head) {
  141. if (xflag)
  142. put_entries(head);
  143. else {
  144. if (uflag) {
  145. FILE *oldf;
  146. regex_t *regx;
  147. if ((oldf = fopen(outfile, "r")) == NULL)
  148. err(1, "opening %s", outfile);
  149. if (unlink(outfile))
  150. err(1, "unlinking %s", outfile);
  151. if ((outf = fopen(outfile, "w")) == NULL)
  152. err(1, "recreating %s", outfile);
  153. if ((regx = calloc(argc, sizeof(regex_t))) == NULL)
  154. err(1, "RE alloc");
  155. for (step = 0; step < argc; step++) {
  156. (void)strcpy(lbuf, "\t");
  157. (void)strlcat(lbuf, argv[step], LINE_MAX);
  158. (void)strlcat(lbuf, "\t", LINE_MAX);
  159. if (regcomp(regx + step, lbuf,
  160. REG_NOSPEC))
  161. warn("RE compilation failed");
  162. }
  163. nextline:
  164. while (fgets(lbuf, LINE_MAX, oldf)) {
  165. for (step = 0; step < argc; step++)
  166. if (regexec(regx + step,
  167. lbuf, 0, NULL, 0) == 0)
  168. goto nextline;
  169. fputs(lbuf, outf);
  170. }
  171. for (step = 0; step < argc; step++)
  172. regfree(regx + step);
  173. free(regx);
  174. fclose(oldf);
  175. fclose(outf);
  176. ++aflag;
  177. }
  178. if (!(outf = fopen(outfile, aflag ? "a" : "w")))
  179. err(1, "%s", outfile);
  180. put_entries(head);
  181. (void)fclose(outf);
  182. if (uflag) {
  183. pid_t pid;
  184. if ((pid = fork()) == -1)
  185. err(1, "fork failed");
  186. else if (pid == 0) {
  187. execlp("sort", "sort", "-o", outfile,
  188. outfile, NULL);
  189. err(1, "exec of sort failed");
  190. }
  191. /* Just assume the sort went OK. The old code
  192. did not do any checks either. */
  193. (void)wait(NULL);
  194. }
  195. }
  196. }
  197. exit(exit_val);
  198. }
  199. static void
  200. usage(void)
  201. {
  202. (void)fprintf(stderr, "usage: ctags [-BFTaduwvx] [-f tagsfile] file ...\n");
  203. exit(1);
  204. }
  205. /*
  206. * init --
  207. * this routine sets up the boolean pseudo-functions which work by
  208. * setting boolean flags dependent upon the corresponding character.
  209. * Every char which is NOT in that string is false with respect to
  210. * the pseudo-function. Therefore, all of the array "_wht" is NO
  211. * by default and then the elements subscripted by the chars in
  212. * CWHITE are set to YES. Thus, "_wht" of a char is YES if it is in
  213. * the string CWHITE, else NO.
  214. */
  215. void
  216. init(void)
  217. {
  218. int i;
  219. const unsigned char *sp;
  220. for (i = 0; i < 256; i++) {
  221. _wht[i] = _etk[i] = _itk[i] = _btk[i] = NO;
  222. _gd[i] = YES;
  223. }
  224. #define CWHITE " \f\t\n"
  225. for (sp = CWHITE; *sp; sp++) /* white space chars */
  226. _wht[*sp] = YES;
  227. #define CTOKEN " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?"
  228. for (sp = CTOKEN; *sp; sp++) /* token ending chars */
  229. _etk[*sp] = YES;
  230. #define CINTOK "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789"
  231. for (sp = CINTOK; *sp; sp++) /* valid in-token chars */
  232. _itk[*sp] = YES;
  233. #define CBEGIN "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
  234. for (sp = CBEGIN; *sp; sp++) /* token starting chars */
  235. _btk[*sp] = YES;
  236. #define CNOTGD ",;"
  237. for (sp = CNOTGD; *sp; sp++) /* invalid after-function chars */
  238. _gd[*sp] = NO;
  239. }
  240. /*
  241. * find_entries --
  242. * this routine opens the specified file and calls the function
  243. * which searches the file.
  244. */
  245. void
  246. find_entries(char *file)
  247. {
  248. char *cp;
  249. lineno = 0; /* should be 1 ?? KB */
  250. if ((cp = strrchr(file, '.'))) {
  251. if (cp[1] == 'l' && !cp[2]) {
  252. int c;
  253. for (;;) {
  254. if (GETC(==, EOF))
  255. return;
  256. if (!iswhite(c)) {
  257. rewind(inf);
  258. break;
  259. }
  260. }
  261. #define LISPCHR ";(["
  262. /* lisp */ if (strchr(LISPCHR, c)) {
  263. l_entries();
  264. return;
  265. }
  266. /* lex */ else {
  267. /*
  268. * we search all 3 parts of a lex file
  269. * for C references. This may be wrong.
  270. */
  271. toss_yysec();
  272. (void)strcpy(lbuf, "%%$");
  273. pfnote("yylex", lineno);
  274. rewind(inf);
  275. }
  276. }
  277. /* yacc */ else if (cp[1] == 'y' && !cp[2]) {
  278. /*
  279. * we search only the 3rd part of a yacc file
  280. * for C references. This may be wrong.
  281. */
  282. toss_yysec();
  283. (void)strcpy(lbuf, "%%$");
  284. pfnote("yyparse", lineno);
  285. y_entries();
  286. }
  287. /* fortran */ else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) {
  288. if (PF_funcs())
  289. return;
  290. rewind(inf);
  291. }
  292. }
  293. /* C */ c_entries();
  294. }