comparison lib-src/etags.c @ 45655:a4c27d23899f

(enum arg_type): New label at_stdin. (STDIN): New constant. (parsing_stdin): New flag. (longopts): New option --parse-stdin=NAME. (print_help): Document it. (main): Handle it. (process_file): Split into process_file and process_file_name. (process_file_name): New function.
author Francesco Potortì <pot@gnu.org>
date Thu, 06 Jun 2002 12:47:58 +0000
parents 816b7344d062
children 466c8ca0e543
comparison
equal deleted inserted replaced
45654:816b7344d062 45655:a4c27d23899f
32 * 2002 #line directives by Francesco Potort́. 32 * 2002 #line directives by Francesco Potort́.
33 * 33 *
34 * Francesco Potort́ <pot@gnu.org> has maintained it since 1993. 34 * Francesco Potort́ <pot@gnu.org> has maintained it since 1993.
35 */ 35 */
36 36
37 char pot_etags_version[] = "@(#) pot revision number is 15.26"; 37 char pot_etags_version[] = "@(#) pot revision number is 16.4";
38 38
39 #define TRUE 1 39 #define TRUE 1
40 #define FALSE 0 40 #define FALSE 0
41 41
42 #ifdef DEBUG 42 #ifdef DEBUG
287 { 287 {
288 enum { 288 enum {
289 at_language, /* a language specification */ 289 at_language, /* a language specification */
290 at_regexp, /* a regular expression */ 290 at_regexp, /* a regular expression */
291 at_icregexp, /* same, but with case ignored */ 291 at_icregexp, /* same, but with case ignored */
292 at_filename /* a file name */ 292 at_filename, /* a file name */
293 at_stdin /* read from stdin here */
293 } arg_type; /* argument type */ 294 } arg_type; /* argument type */
294 language *lang; /* language associated with the argument */ 295 language *lang; /* language associated with the argument */
295 char *what; /* the argument itself */ 296 char *what; /* the argument itself */
296 } argument; 297 } argument;
297 298
364 static void pfatal __P((char *)); 365 static void pfatal __P((char *));
365 static void add_node __P((node *, node **)); 366 static void add_node __P((node *, node **));
366 367
367 static void init __P((void)); 368 static void init __P((void));
368 static void initbuffer __P((linebuffer *)); 369 static void initbuffer __P((linebuffer *));
369 static void process_file __P((char *, language *)); 370 static void process_file_name __P((char *, language *));
371 static void process_file __P((FILE *, char *, language *));
370 static void find_entries __P((FILE *)); 372 static void find_entries __P((FILE *));
371 static void free_tree __P((node *)); 373 static void free_tree __P((node *));
372 static void free_fdesc __P((fdesc *)); 374 static void free_fdesc __P((fdesc *));
373 static void pfnote __P((char *, bool, char *, int, int, long)); 375 static void pfnote __P((char *, bool, char *, int, int, long));
374 static void new_pfnote __P((char *, int, bool, char *, int, int, long)); 376 static void new_pfnote __P((char *, int, bool, char *, int, int, long));
449 static bool cxref_style; /* -x: create cxref style output */ 451 static bool cxref_style; /* -x: create cxref style output */
450 static bool cplusplus; /* .[hc] means C++, not C */ 452 static bool cplusplus; /* .[hc] means C++, not C */
451 static bool noindentypedefs; /* -I: ignore indentation in C */ 453 static bool noindentypedefs; /* -I: ignore indentation in C */
452 static bool packages_only; /* --packages-only: in Ada, only tag packages*/ 454 static bool packages_only; /* --packages-only: in Ada, only tag packages*/
453 455
456 #define STDIN 0x1001 /* returned by getopt_long on --parse-stdin */
457 static bool parsing_stdin; /* --parse-stdin used */
458
454 #ifdef ETAGS_REGEXPS 459 #ifdef ETAGS_REGEXPS
455 /* List of all regexps. */ 460 /* List of all regexps. */
456 static pattern *p_head; 461 static pattern *p_head;
457 462
458 /* How many characters in the character set. (From regex.c.) */ 463 /* How many characters in the character set. (From regex.c.) */
478 #ifdef ETAGS_REGEXPS 483 #ifdef ETAGS_REGEXPS
479 { "regex", required_argument, NULL, 'r' }, 484 { "regex", required_argument, NULL, 'r' },
480 { "no-regex", no_argument, NULL, 'R' }, 485 { "no-regex", no_argument, NULL, 'R' },
481 { "ignore-case-regex", required_argument, NULL, 'c' }, 486 { "ignore-case-regex", required_argument, NULL, 'c' },
482 #endif /* ETAGS_REGEXPS */ 487 #endif /* ETAGS_REGEXPS */
488 { "parse-stdin", required_argument, NULL, STDIN },
483 { "version", no_argument, NULL, 'V' }, 489 { "version", no_argument, NULL, 'V' },
484 490
485 #if CTAGS /* Etags options */ 491 #if CTAGS /* Etags options */
486 { "backward-search", no_argument, NULL, 'B' }, 492 { "backward-search", no_argument, NULL, 'B' },
487 { "cxref", no_argument, NULL, 'x' }, 493 { "cxref", no_argument, NULL, 'x' },
703 #endif /* LONG_OPTIONS */ 709 #endif /* LONG_OPTIONS */
704 puts (" A - as file name means read names from stdin (one per line).\n\ 710 puts (" A - as file name means read names from stdin (one per line).\n\
705 Absolute names are stored in the output file as they are.\n\ 711 Absolute names are stored in the output file as they are.\n\
706 Relative ones are stored relative to the output file's directory.\n"); 712 Relative ones are stored relative to the output file's directory.\n");
707 713
714 puts ("--parse-stdin=NAME\n\
715 Read from standard input and record tags as belonging to file NAME.");
716
708 if (!CTAGS) 717 if (!CTAGS)
709 puts ("-a, --append\n\ 718 puts ("-a, --append\n\
710 Append tag entries to existing tags file."); 719 Append tag entries to existing tags file.");
711 720
712 puts ("--packages-only\n\ 721 puts ("--packages-only\n\
968 int current_arg, file_count; 977 int current_arg, file_count;
969 linebuffer filename_lb; 978 linebuffer filename_lb;
970 #ifdef VMS 979 #ifdef VMS
971 bool got_err; 980 bool got_err;
972 #endif 981 #endif
982 char *optstring;
983 int opt;
984
973 985
974 #ifdef DOS_NT 986 #ifdef DOS_NT
975 _fmode = O_BINARY; /* all of files are treated as binary files */ 987 _fmode = O_BINARY; /* all of files are treated as binary files */
976 #endif /* DOS_NT */ 988 #endif /* DOS_NT */
977 989
1002 { 1014 {
1003 typedefs = typedefs_or_cplusplus = constantypedefs = TRUE; 1015 typedefs = typedefs_or_cplusplus = constantypedefs = TRUE;
1004 globals = TRUE; 1016 globals = TRUE;
1005 } 1017 }
1006 1018
1007 while (1) 1019 optstring = "-";
1008 {
1009 int opt;
1010 char *optstring = "-";
1011
1012 #ifdef ETAGS_REGEXPS 1020 #ifdef ETAGS_REGEXPS
1013 optstring = "-r:Rc:"; 1021 optstring = "-r:Rc:";
1014 #endif /* ETAGS_REGEXPS */ 1022 #endif /* ETAGS_REGEXPS */
1015
1016 #ifndef LONG_OPTIONS 1023 #ifndef LONG_OPTIONS
1017 optstring = optstring + 1; 1024 optstring = optstring + 1;
1018 #endif /* LONG_OPTIONS */ 1025 #endif /* LONG_OPTIONS */
1019 1026 optstring = concat (optstring,
1020 optstring = concat (optstring, 1027 "Cf:Il:o:SVhH",
1021 "Cf:Il:o:SVhH", 1028 (CTAGS) ? "BxdtTuvw" : "aDi:");
1022 (CTAGS) ? "BxdtTuvw" : "aDi:"); 1029
1023 1030 while ((opt = getopt_long (argc, argv, optstring, longopts, 0)) != EOF)
1024 opt = getopt_long (argc, argv, optstring, longopts, 0); 1031 switch (opt)
1025 if (opt == EOF) 1032 {
1033 case 0:
1034 /* If getopt returns 0, then it has already processed a
1035 long-named option. We should do nothing. */
1026 break; 1036 break;
1027 1037
1028 switch (opt) 1038 case 1:
1029 { 1039 /* This means that a file name has been seen. Record it. */
1030 case 0: 1040 argbuffer[current_arg].arg_type = at_filename;
1031 /* If getopt returns 0, then it has already processed a 1041 argbuffer[current_arg].what = optarg;
1032 long-named option. We should do nothing. */ 1042 ++current_arg;
1033 break; 1043 ++file_count;
1034 1044 break;
1035 case 1: 1045
1036 /* This means that a file name has been seen. Record it. */ 1046 case STDIN:
1037 argbuffer[current_arg].arg_type = at_filename; 1047 /* Parse standard input. Idea by Vivek <vivek@etla.org>. */
1038 argbuffer[current_arg].what = optarg; 1048 argbuffer[current_arg].arg_type = at_stdin;
1039 ++current_arg; 1049 argbuffer[current_arg].what = optarg;
1040 ++file_count; 1050 ++current_arg;
1041 break; 1051 ++file_count;
1042 1052 parsing_stdin = TRUE;
1043 /* Common options. */ 1053 break;
1044 case 'C': cplusplus = TRUE; break; 1054
1045 case 'f': /* for compatibility with old makefiles */ 1055 /* Common options. */
1046 case 'o': 1056 case 'C': cplusplus = TRUE; break;
1047 if (tagfile) 1057 case 'f': /* for compatibility with old makefiles */
1048 { 1058 case 'o':
1049 error ("-o option may only be given once.", (char *)NULL); 1059 if (tagfile)
1050 suggest_asking_for_help (); 1060 {
1061 error ("-o option may only be given once.", (char *)NULL);
1062 suggest_asking_for_help ();
1063 }
1064 tagfile = optarg;
1065 break;
1066 case 'I':
1067 case 'S': /* for backward compatibility */
1068 noindentypedefs = TRUE;
1069 break;
1070 case 'l':
1071 {
1072 language *lang = get_language_from_langname (optarg);
1073 if (lang != NULL)
1074 {
1075 argbuffer[current_arg].lang = lang;
1076 argbuffer[current_arg].arg_type = at_language;
1077 ++current_arg;
1051 } 1078 }
1052 tagfile = optarg; 1079 }
1053 break; 1080 break;
1054 case 'I': 1081 case 'r':
1055 case 'S': /* for backward compatibility */ 1082 argbuffer[current_arg].arg_type = at_regexp;
1056 noindentypedefs = TRUE; 1083 argbuffer[current_arg].what = optarg;
1057 break; 1084 ++current_arg;
1058 case 'l': 1085 break;
1059 { 1086 case 'R':
1060 language *lang = get_language_from_langname (optarg); 1087 argbuffer[current_arg].arg_type = at_regexp;
1061 if (lang != NULL) 1088 argbuffer[current_arg].what = NULL;
1062 { 1089 ++current_arg;
1063 argbuffer[current_arg].lang = lang; 1090 break;
1064 argbuffer[current_arg].arg_type = at_language; 1091 case 'c':
1065 ++current_arg; 1092 argbuffer[current_arg].arg_type = at_icregexp;
1066 } 1093 argbuffer[current_arg].what = optarg;
1067 } 1094 ++current_arg;
1068 break; 1095 break;
1069 case 'r': 1096 case 'V':
1070 argbuffer[current_arg].arg_type = at_regexp; 1097 print_version ();
1071 argbuffer[current_arg].what = optarg; 1098 break;
1072 ++current_arg; 1099 case 'h':
1073 break; 1100 case 'H':
1074 case 'R': 1101 print_help ();
1075 argbuffer[current_arg].arg_type = at_regexp; 1102 break;
1076 argbuffer[current_arg].what = NULL; 1103
1077 ++current_arg; 1104 /* Etags options */
1078 break; 1105 case 'a': append_to_tagfile = TRUE; break;
1079 case 'c': 1106 case 'D': constantypedefs = FALSE; break;
1080 argbuffer[current_arg].arg_type = at_icregexp; 1107 case 'i': included_files[nincluded_files++] = optarg; break;
1081 argbuffer[current_arg].what = optarg; 1108
1082 ++current_arg; 1109 /* Ctags options. */
1083 break; 1110 case 'B': searchar = '?'; break;
1084 case 'V': 1111 case 'd': constantypedefs = TRUE; break;
1085 print_version (); 1112 case 't': typedefs = TRUE; break;
1086 break; 1113 case 'T': typedefs = typedefs_or_cplusplus = TRUE; break;
1087 case 'h': 1114 case 'u': update = TRUE; break;
1088 case 'H': 1115 case 'v': vgrind_style = TRUE; /*FALLTHRU*/
1089 print_help (); 1116 case 'x': cxref_style = TRUE; break;
1090 break; 1117 case 'w': no_warnings = TRUE; break;
1091 1118 default:
1092 /* Etags options */ 1119 suggest_asking_for_help ();
1093 case 'a': append_to_tagfile = TRUE; break; 1120 }
1094 case 'D': constantypedefs = FALSE; break;
1095 case 'i': included_files[nincluded_files++] = optarg; break;
1096
1097 /* Ctags options. */
1098 case 'B': searchar = '?'; break;
1099 case 'd': constantypedefs = TRUE; break;
1100 case 't': typedefs = TRUE; break;
1101 case 'T': typedefs = typedefs_or_cplusplus = TRUE; break;
1102 case 'u': update = TRUE; break;
1103 case 'v': vgrind_style = TRUE; /*FALLTHRU*/
1104 case 'x': cxref_style = TRUE; break;
1105 case 'w': no_warnings = TRUE; break;
1106 default:
1107 suggest_asking_for_help ();
1108 }
1109 }
1110 1121
1111 for (; optind < argc; ++optind) 1122 for (; optind < argc; ++optind)
1112 { 1123 {
1113 argbuffer[current_arg].arg_type = at_filename; 1124 argbuffer[current_arg].arg_type = at_filename;
1114 argbuffer[current_arg].what = argv[optind]; 1125 argbuffer[current_arg].what = argv[optind];
1197 this_file = argbuffer[i].what; 1208 this_file = argbuffer[i].what;
1198 #endif 1209 #endif
1199 /* Input file named "-" means read file names from stdin 1210 /* Input file named "-" means read file names from stdin
1200 (one per line) and use them. */ 1211 (one per line) and use them. */
1201 if (streq (this_file, "-")) 1212 if (streq (this_file, "-"))
1202 while (readline_internal (&filename_lb, stdin) > 0) 1213 {
1203 process_file (filename_lb.buffer, lang); 1214 if (parsing_stdin)
1215 fatal ("cannot parse standard input AND read file names from it",
1216 (char *)NULL);
1217 while (readline_internal (&filename_lb, stdin) > 0)
1218 process_file_name (filename_lb.buffer, lang);
1219 }
1204 else 1220 else
1205 process_file (this_file, lang); 1221 process_file_name (this_file, lang);
1206 #ifdef VMS 1222 #ifdef VMS
1207 } 1223 }
1208 #endif 1224 #endif
1209 break; 1225 break;
1226 case at_stdin:
1227 this_file = argbuffer[i].what;
1228 process_file (stdin, this_file, lang);
1229 break;
1210 } 1230 }
1211 } 1231 }
1212 1232
1213 #ifdef ETAGS_REGEXPS 1233 #ifdef ETAGS_REGEXPS
1214 free_patterns (); 1234 free_patterns ();
1231 if (update) 1251 if (update)
1232 { 1252 {
1233 char cmd[BUFSIZ]; 1253 char cmd[BUFSIZ];
1234 for (i = 0; i < current_arg; ++i) 1254 for (i = 0; i < current_arg; ++i)
1235 { 1255 {
1236 if (argbuffer[i].arg_type != at_filename) 1256 switch (argbuffer[i].arg_type)
1237 continue; 1257 {
1258 case at_filename:
1259 case at_stdin:
1260 break;
1261 default:
1262 continue; /* the for loop */
1263 }
1238 sprintf (cmd, 1264 sprintf (cmd,
1239 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS", 1265 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
1240 tagfile, argbuffer[i].what, tagfile); 1266 tagfile, argbuffer[i].what, tagfile);
1241 if (system (cmd) != GOOD) 1267 if (system (cmd) != GOOD)
1242 fatal ("failed to execute shell command", (char *)NULL); 1268 fatal ("failed to execute shell command", (char *)NULL);
1389 1415
1390 /* 1416 /*
1391 * This routine is called on each file argument. 1417 * This routine is called on each file argument.
1392 */ 1418 */
1393 static void 1419 static void
1394 process_file (file, lang) 1420 process_file_name (file, lang)
1395 char *file; 1421 char *file;
1396 language *lang; 1422 language *lang;
1397 { 1423 {
1398 struct stat stat_buf; 1424 struct stat stat_buf;
1399 FILE *inf; 1425 FILE *inf;
1400 static const fdesc emptyfdesc;
1401 fdesc *fdp; 1426 fdesc *fdp;
1402 compressor *compr; 1427 compressor *compr;
1403 char *compressed_name, *uncompressed_name; 1428 char *compressed_name, *uncompressed_name;
1404 char *ext, *real_name; 1429 char *ext, *real_name;
1405 int retval; 1430 int retval;
1406
1407 1431
1408 canonicalize_filename (file); 1432 canonicalize_filename (file);
1409 if (streq (file, tagfile) && !streq (tagfile, "-")) 1433 if (streq (file, tagfile) && !streq (tagfile, "-"))
1410 { 1434 {
1411 error ("skipping inclusion of %s in self.", file); 1435 error ("skipping inclusion of %s in self.", file);
1497 { 1521 {
1498 perror (real_name); 1522 perror (real_name);
1499 goto cleanup; 1523 goto cleanup;
1500 } 1524 }
1501 1525
1502 /* Create a new input file description entry. */ 1526 process_file (inf, uncompressed_name, lang);
1503 fdp = xnew (1, fdesc);
1504 *fdp = emptyfdesc;
1505 fdp->next = fdhead;
1506 fdp->infname = savestr (uncompressed_name);
1507 fdp->lang = lang;
1508 fdp->infabsname = absolute_filename (uncompressed_name, cwd);
1509 fdp->infabsdir = absolute_dirname (uncompressed_name, cwd);
1510 if (filename_is_absolute (uncompressed_name))
1511 {
1512 /* file is an absolute file name. Canonicalize it. */
1513 fdp->taggedfname = absolute_filename (uncompressed_name, NULL);
1514 }
1515 else
1516 {
1517 /* file is a file name relative to cwd. Make it relative
1518 to the directory of the tags file. */
1519 fdp->taggedfname = relative_filename (uncompressed_name, tagfiledir);
1520 }
1521 fdp->usecharno = TRUE; /* use char position when making tags */
1522 fdp->prop = NULL;
1523
1524 fdhead = fdp;
1525 curfdp = fdhead; /* the current file description */
1526
1527 find_entries (inf);
1528 1527
1529 if (real_name == compressed_name) 1528 if (real_name == compressed_name)
1530 retval = pclose (inf); 1529 retval = pclose (inf);
1531 else 1530 else
1532 retval = fclose (inf); 1531 retval = fclose (inf);
1533 if (retval < 0) 1532 if (retval < 0)
1534 pfatal (file); 1533 pfatal (file);
1534
1535 cleanup:
1536 if (compressed_name) free (compressed_name);
1537 if (uncompressed_name) free (uncompressed_name);
1538 last_node = NULL;
1539 curfdp = NULL;
1540 return;
1541 }
1542
1543 static void
1544 process_file (fh, fn, lang)
1545 FILE *fh;
1546 char *fn;
1547 language *lang;
1548 {
1549 static const fdesc emptyfdesc;
1550 fdesc *fdp;
1551
1552 /* Create a new input file description entry. */
1553 fdp = xnew (1, fdesc);
1554 *fdp = emptyfdesc;
1555 fdp->next = fdhead;
1556 fdp->infname = savestr (fn);
1557 fdp->lang = lang;
1558 fdp->infabsname = absolute_filename (fn, cwd);
1559 fdp->infabsdir = absolute_dirname (fn, cwd);
1560 if (filename_is_absolute (fn))
1561 {
1562 /* An absolute file name. Canonicalize it. */
1563 fdp->taggedfname = absolute_filename (fn, NULL);
1564 }
1565 else
1566 {
1567 /* A file name relative to cwd. Make it relative
1568 to the directory of the tags file. */
1569 fdp->taggedfname = relative_filename (fn, tagfiledir);
1570 }
1571 fdp->usecharno = TRUE; /* use char position when making tags */
1572 fdp->prop = NULL;
1573
1574 fdhead = fdp;
1575 curfdp = fdhead; /* the current file description */
1576
1577 find_entries (fh);
1535 1578
1536 /* If not Ctags, and if this is not metasource and if it contained no #line 1579 /* If not Ctags, and if this is not metasource and if it contained no #line
1537 directives, we can write the tags and free all nodes pointing to 1580 directives, we can write the tags and free all nodes pointing to
1538 curfdp. */ 1581 curfdp. */
1539 if (!CTAGS 1582 if (!CTAGS
1564 nodehead = NULL; /* no nodes left */ 1607 nodehead = NULL; /* no nodes left */
1565 else 1608 else
1566 prev->left = NULL; /* delete the pointer to the sublist */ 1609 prev->left = NULL; /* delete the pointer to the sublist */
1567 } 1610 }
1568 } 1611 }
1569
1570 cleanup:
1571 if (compressed_name) free (compressed_name);
1572 if (uncompressed_name) free (uncompressed_name);
1573 last_node = NULL;
1574 curfdp = NULL;
1575 return;
1576 } 1612 }
1577 1613
1578 /* 1614 /*
1579 * This routine sets up the boolean pseudo-functions which work 1615 * This routine sets up the boolean pseudo-functions which work
1580 * by setting boolean flags dependent upon the corresponding character. 1616 * by setting boolean flags dependent upon the corresponding character.
5027 } 5063 }
5028 else if (s[pos] == '\'') 5064 else if (s[pos] == '\'')
5029 { 5065 {
5030 pos++; 5066 pos++;
5031 5067
5032 while (1) 5068 for (;;)
5033 { 5069 {
5034 if (s[pos] == '\'') 5070 if (s[pos] == '\'')
5035 { 5071 {
5036 pos++; 5072 pos++;
5037 if (s[pos] != '\'') 5073 if (s[pos] != '\'')
5206 } 5242 }
5207 else if (s[pos] == '\'') 5243 else if (s[pos] == '\'')
5208 { 5244 {
5209 pos++; 5245 pos++;
5210 5246
5211 while (1) 5247 for (;;)
5212 { 5248 {
5213 if (s[pos] == '\'') 5249 if (s[pos] == '\'')
5214 { 5250 {
5215 pos++; 5251 pos++;
5216 break; 5252 break;
5540 register char *pend; 5576 register char *pend;
5541 int chars_deleted; 5577 int chars_deleted;
5542 5578
5543 pend = p + lbp->size; /* Separate to avoid 386/IX compiler bug. */ 5579 pend = p + lbp->size; /* Separate to avoid 386/IX compiler bug. */
5544 5580
5545 while (1) 5581 for (;;)
5546 { 5582 {
5547 register int c = getc (stream); 5583 register int c = getc (stream);
5548 if (p == pend) 5584 if (p == pend)
5549 { 5585 {
5550 /* We're at the end of linebuffer: expand it. */ 5586 /* We're at the end of linebuffer: expand it. */