|
24 | 24 | #include <stdio.h> /* stderr */ |
25 | 25 | #include <stdbool.h> |
26 | 26 |
|
| 27 | +#include <unistd.h> |
| 28 | + |
27 | 29 | typedef struct sReadOption { |
28 | 30 | bool sortOverride; |
29 | 31 | sortType sortMethod; |
@@ -56,6 +58,7 @@ struct actionSpec { |
56 | 58 | ACTION_LIST = 1 << 1, |
57 | 59 | ACTION_LIST_PTAGS = 1 << 2, |
58 | 60 | ACTION_LIST_INCLUDED = 1 << 3, |
| 61 | + ACTION_AGGREGATE = 1 << 4, |
59 | 62 | } action; |
60 | 63 | const char *name; /* for ACTION_FIND */ |
61 | 64 | bool canonicalizing; |
@@ -609,6 +612,8 @@ static const char *const Usage = |
609 | 612 | " List pseudo tags.\n" |
610 | 613 | " -L | --list-included\n" |
611 | 614 | " List included tag files.\n" |
| 615 | + " -X | --generate-aggregate-tag-file\n" |
| 616 | + " Generate an aggregate file includes tag files specified with -t option.\n" |
612 | 617 | "Options:\n" |
613 | 618 | " -d | --debug\n" |
614 | 619 | " Turn on debugging output.\n" |
@@ -764,6 +769,42 @@ static void loadIndirectTagFiles (struct inputSpec *inputSpec, ptrArray *inputSp |
764 | 769 | deleteTagFileX (fileX); |
765 | 770 | } |
766 | 771 |
|
| 772 | +static void printMustPseudoTag(tagPrintOptions *opts, FILE *fp, |
| 773 | + const char *name, const char *file,const char *pattern) |
| 774 | +{ |
| 775 | + tagEntry e; |
| 776 | + |
| 777 | + memset (&e, 0, sizeof (e)); |
| 778 | + |
| 779 | + e.name = name; |
| 780 | + e.file = file; |
| 781 | + e.address.pattern = pattern; |
| 782 | + tagsPrintPseudoTag (&e, opts, NULL, fp); |
| 783 | +} |
| 784 | + |
| 785 | +static void printMustPseudoTags(tagPrintOptions *opts, FILE *fp) |
| 786 | +{ |
| 787 | + char buf[PATH_MAX]; |
| 788 | + if (!getcwd(buf, sizeof(buf))) |
| 789 | + { |
| 790 | + fprintf(stderr, "Failed to get the current working directory\n"); |
| 791 | + exit (1); |
| 792 | + } |
| 793 | + |
| 794 | + printMustPseudoTag(opts, fp, "!_TAG_FILE_FORMAT", "2", "//"); |
| 795 | + printMustPseudoTag(opts, fp, "!_TAG_FILE_SORTED", "1", "//"); |
| 796 | + printMustPseudoTag(opts, fp, "!_TAG_OUTPUT_EXCMD", "pattern", "//"); |
| 797 | + printMustPseudoTag(opts, fp, "!_TAG_OUTPUT_FILESEP", "slash", "//"); |
| 798 | + printMustPseudoTag(opts, fp, "!_TAG_OUTPUT_MODE", "u-ctags", "//"); |
| 799 | + printMustPseudoTag(opts, fp, "!_TAG_OUTPUT_VERSION", "0.0", "/current.age/"); |
| 800 | + printMustPseudoTag(opts, fp, "!_TAG_PATTERN_LENGTH_LIMIT", "0", "//"); |
| 801 | + printMustPseudoTag(opts, fp, "!_TAG_PROC_CWD", buf, "//"); |
| 802 | + printMustPseudoTag(opts, fp, "!_TAG_PROGRAM_AUTHOR", "Universal Ctags Team", "//"); |
| 803 | + printMustPseudoTag(opts, fp, "!_TAG_PROGRAM_NAME", "readtags", "/with -X option/"); |
| 804 | + printMustPseudoTag(opts, fp, "!_TAG_PROGRAM_URL", "https://ctags.io/", "/official site/"); |
| 805 | + printMustPseudoTag(opts, fp, "!_TAG_PROGRAM_VERSION", "0.0.0", "/TODO/"); |
| 806 | +} |
| 807 | + |
767 | 808 | extern int main (int argc, char **argv) |
768 | 809 | { |
769 | 810 | int i; |
@@ -901,6 +942,8 @@ extern int main (int argc, char **argv) |
901 | 942 | actionSpec.canonicalizing = true; |
902 | 943 | actionSpec.canon.absoluteOnly = false; |
903 | 944 | } |
| 945 | + else if (strcmp (optname, "generate-aggregate-tag-file") == 0) |
| 946 | + actionSpec.action |= ACTION_AGGREGATE; |
904 | 947 | #ifdef READTAGS_DSL |
905 | 948 | else if (strcmp (optname, "filter") == 0) |
906 | 949 | { |
@@ -1022,6 +1065,9 @@ extern int main (int argc, char **argv) |
1022 | 1065 | actionSpec.canonicalizing = true; |
1023 | 1066 | actionSpec.canon.absoluteOnly = false; |
1024 | 1067 | break; |
| 1068 | + case 'X': |
| 1069 | + actionSpec.action |= ACTION_AGGREGATE; |
| 1070 | + break; |
1025 | 1071 | #ifdef READTAGS_DSL |
1026 | 1072 | case 'Q': |
1027 | 1073 | if (i + 1 == argc) |
@@ -1075,6 +1121,23 @@ extern int main (int argc, char **argv) |
1075 | 1121 | if (ptrArrayIsEmpty (inputSpecs)) |
1076 | 1122 | addInputSpec (inputSpecs, "tags", false); |
1077 | 1123 |
|
| 1124 | + if (actionSpec.action & ACTION_AGGREGATE) |
| 1125 | + { |
| 1126 | + tagEntry e; |
| 1127 | + for (unsigned int i = 0; i < ptrArrayCount (inputSpecs); i++) |
| 1128 | + { |
| 1129 | + struct inputSpec *inputSpec = ptrArrayItem (inputSpecs, i); |
| 1130 | + memset (&e, 0, sizeof (e)); |
| 1131 | + e.name = "!_READTAGS_INCLUDE"; |
| 1132 | + e.file = inputSpec->tagFileName; |
| 1133 | + e.address.pattern = "//"; |
| 1134 | + tagsPrintPseudoTag (&e, &printOpts, NULL, stdout); |
| 1135 | + } |
| 1136 | + |
| 1137 | + printMustPseudoTags (&printOpts, stdout); |
| 1138 | + goto out; |
| 1139 | + } |
| 1140 | + |
1078 | 1141 | unsigned int start = 0; |
1079 | 1142 | unsigned int end = ptrArrayCount (inputSpecs); |
1080 | 1143 | while (1) |
@@ -1124,6 +1187,7 @@ extern int main (int argc, char **argv) |
1124 | 1187 | } |
1125 | 1188 | } |
1126 | 1189 |
|
| 1190 | + out: |
1127 | 1191 | ptrArrayDelete (inputSpecs); |
1128 | 1192 |
|
1129 | 1193 | #ifdef READTAGS_DSL |
|
0 commit comments