ctags.rb 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. data/Gemfile +2 -0
  2. data/Rakefile +23 -0
  3. data/ctags.rb.gemspec +23 -0
  4. data/ext/.gitignore +3 -0
  5. data/ext/extconf.rb +15 -0
  6. data/ext/vendor/exuberant-ctags/.gitignore +6 -0
  7. data/ext/vendor/exuberant-ctags/.indent.pro +31 -0
  8. data/ext/vendor/exuberant-ctags/COPYING +340 -0
  9. data/ext/vendor/exuberant-ctags/EXTENDING.html +386 -0
  10. data/ext/vendor/exuberant-ctags/FAQ +371 -0
  11. data/ext/vendor/exuberant-ctags/INSTALL +215 -0
  12. data/ext/vendor/exuberant-ctags/INSTALL.oth +73 -0
  13. data/ext/vendor/exuberant-ctags/MAINTAINERS +88 -0
  14. data/ext/vendor/exuberant-ctags/Makefile.in +222 -0
  15. data/ext/vendor/exuberant-ctags/NEWS +871 -0
  16. data/ext/vendor/exuberant-ctags/README +73 -0
  17. data/ext/vendor/exuberant-ctags/ant.c +42 -0
  18. data/ext/vendor/exuberant-ctags/argproc.c +505 -0
  19. data/ext/vendor/exuberant-ctags/args.c +274 -0
  20. data/ext/vendor/exuberant-ctags/args.h +63 -0
  21. data/ext/vendor/exuberant-ctags/asm.c +387 -0
  22. data/ext/vendor/exuberant-ctags/asp.c +328 -0
  23. data/ext/vendor/exuberant-ctags/awk.c +81 -0
  24. data/ext/vendor/exuberant-ctags/basic.c +203 -0
  25. data/ext/vendor/exuberant-ctags/beta.c +321 -0
  26. data/ext/vendor/exuberant-ctags/c.c +2932 -0
  27. data/ext/vendor/exuberant-ctags/cobol.c +50 -0
  28. data/ext/vendor/exuberant-ctags/config.h.in +277 -0
  29. data/ext/vendor/exuberant-ctags/configure +7704 -0
  30. data/ext/vendor/exuberant-ctags/configure.ac +532 -0
  31. data/ext/vendor/exuberant-ctags/ctags.1 +1186 -0
  32. data/ext/vendor/exuberant-ctags/ctags.h +28 -0
  33. data/ext/vendor/exuberant-ctags/ctags.html +2087 -0
  34. data/ext/vendor/exuberant-ctags/ctags.spec +40 -0
  35. data/ext/vendor/exuberant-ctags/debug.c +113 -0
  36. data/ext/vendor/exuberant-ctags/debug.h +70 -0
  37. data/ext/vendor/exuberant-ctags/descrip.mms +68 -0
  38. data/ext/vendor/exuberant-ctags/dosbatch.c +42 -0
  39. data/ext/vendor/exuberant-ctags/e_amiga.h +24 -0
  40. data/ext/vendor/exuberant-ctags/e_djgpp.h +47 -0
  41. data/ext/vendor/exuberant-ctags/e_mac.h +143 -0
  42. data/ext/vendor/exuberant-ctags/e_msoft.h +76 -0
  43. data/ext/vendor/exuberant-ctags/e_os2.h +37 -0
  44. data/ext/vendor/exuberant-ctags/e_qdos.h +34 -0
  45. data/ext/vendor/exuberant-ctags/e_riscos.h +58 -0
  46. data/ext/vendor/exuberant-ctags/e_vms.h +31 -0
  47. data/ext/vendor/exuberant-ctags/eiffel.c +1352 -0
  48. data/ext/vendor/exuberant-ctags/entry.c +847 -0
  49. data/ext/vendor/exuberant-ctags/entry.h +103 -0
  50. data/ext/vendor/exuberant-ctags/erlang.c +189 -0
  51. data/ext/vendor/exuberant-ctags/flex.c +2243 -0
  52. data/ext/vendor/exuberant-ctags/fortran.c +2197 -0
  53. data/ext/vendor/exuberant-ctags/general.h +127 -0
  54. data/ext/vendor/exuberant-ctags/get.c +669 -0
  55. data/ext/vendor/exuberant-ctags/get.h +50 -0
  56. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/all-wcprops +47 -0
  57. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/entries +112 -0
  58. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/README.txt.svn-base +5 -0
  59. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regcomp.c.svn-base +3818 -0
  60. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.c.svn-base +74 -0
  61. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.h.svn-base +575 -0
  62. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.c.svn-base +1713 -0
  63. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.h.svn-base +773 -0
  64. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regexec.c.svn-base +4338 -0
  65. data/ext/vendor/exuberant-ctags/gnu_regex/README.txt +5 -0
  66. data/ext/vendor/exuberant-ctags/gnu_regex/regcomp.c +3818 -0
  67. data/ext/vendor/exuberant-ctags/gnu_regex/regex.c +74 -0
  68. data/ext/vendor/exuberant-ctags/gnu_regex/regex.h +575 -0
  69. data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.c +1713 -0
  70. data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.h +773 -0
  71. data/ext/vendor/exuberant-ctags/gnu_regex/regexec.c +4338 -0
  72. data/ext/vendor/exuberant-ctags/html.c +49 -0
  73. data/ext/vendor/exuberant-ctags/jscript.c +1572 -0
  74. data/ext/vendor/exuberant-ctags/keyword.c +258 -0
  75. data/ext/vendor/exuberant-ctags/keyword.h +34 -0
  76. data/ext/vendor/exuberant-ctags/lisp.c +139 -0
  77. data/ext/vendor/exuberant-ctags/lregex.c +704 -0
  78. data/ext/vendor/exuberant-ctags/lua.c +133 -0
  79. data/ext/vendor/exuberant-ctags/mac.c +273 -0
  80. data/ext/vendor/exuberant-ctags/magic.diff +21 -0
  81. data/ext/vendor/exuberant-ctags/main.c +584 -0
  82. data/ext/vendor/exuberant-ctags/main.h +32 -0
  83. data/ext/vendor/exuberant-ctags/maintainer.mak +476 -0
  84. data/ext/vendor/exuberant-ctags/make.c +217 -0
  85. data/ext/vendor/exuberant-ctags/matlab.c +44 -0
  86. data/ext/vendor/exuberant-ctags/mk_bc3.mak +46 -0
  87. data/ext/vendor/exuberant-ctags/mk_bc5.mak +49 -0
  88. data/ext/vendor/exuberant-ctags/mk_djg.mak +18 -0
  89. data/ext/vendor/exuberant-ctags/mk_manx.mak +65 -0
  90. data/ext/vendor/exuberant-ctags/mk_mingw.mak +31 -0
  91. data/ext/vendor/exuberant-ctags/mk_mpw.mak +130 -0
  92. data/ext/vendor/exuberant-ctags/mk_mvc.mak +40 -0
  93. data/ext/vendor/exuberant-ctags/mk_os2.mak +104 -0
  94. data/ext/vendor/exuberant-ctags/mk_qdos.mak +100 -0
  95. data/ext/vendor/exuberant-ctags/mk_sas.mak +63 -0
  96. data/ext/vendor/exuberant-ctags/mkinstalldirs +40 -0
  97. data/ext/vendor/exuberant-ctags/ocaml.c +1842 -0
  98. data/ext/vendor/exuberant-ctags/options.c +1842 -0
  99. data/ext/vendor/exuberant-ctags/options.h +155 -0
  100. data/ext/vendor/exuberant-ctags/parse.c +677 -0
  101. data/ext/vendor/exuberant-ctags/parse.h +129 -0
  102. data/ext/vendor/exuberant-ctags/parsers.h +63 -0
  103. data/ext/vendor/exuberant-ctags/pascal.c +267 -0
  104. data/ext/vendor/exuberant-ctags/perl.c +382 -0
  105. data/ext/vendor/exuberant-ctags/php.c +237 -0
  106. data/ext/vendor/exuberant-ctags/python.c +771 -0
  107. data/ext/vendor/exuberant-ctags/qdos.c +106 -0
  108. data/ext/vendor/exuberant-ctags/read.c +569 -0
  109. data/ext/vendor/exuberant-ctags/read.h +116 -0
  110. data/ext/vendor/exuberant-ctags/readtags.c +959 -0
  111. data/ext/vendor/exuberant-ctags/readtags.h +252 -0
  112. data/ext/vendor/exuberant-ctags/rexx.c +39 -0
  113. data/ext/vendor/exuberant-ctags/routines.c +891 -0
  114. data/ext/vendor/exuberant-ctags/routines.h +134 -0
  115. data/ext/vendor/exuberant-ctags/ruby.c +408 -0
  116. data/ext/vendor/exuberant-ctags/scheme.c +111 -0
  117. data/ext/vendor/exuberant-ctags/sh.c +115 -0
  118. data/ext/vendor/exuberant-ctags/slang.c +41 -0
  119. data/ext/vendor/exuberant-ctags/sml.c +212 -0
  120. data/ext/vendor/exuberant-ctags/sort.c +230 -0
  121. data/ext/vendor/exuberant-ctags/sort.h +32 -0
  122. data/ext/vendor/exuberant-ctags/source.mak +122 -0
  123. data/ext/vendor/exuberant-ctags/sql.c +2112 -0
  124. data/ext/vendor/exuberant-ctags/strlist.c +281 -0
  125. data/ext/vendor/exuberant-ctags/strlist.h +54 -0
  126. data/ext/vendor/exuberant-ctags/tcl.c +116 -0
  127. data/ext/vendor/exuberant-ctags/tex.c +524 -0
  128. data/ext/vendor/exuberant-ctags/verilog.c +340 -0
  129. data/ext/vendor/exuberant-ctags/vhdl.c +835 -0
  130. data/ext/vendor/exuberant-ctags/vim.c +636 -0
  131. data/ext/vendor/exuberant-ctags/vstring.c +232 -0
  132. data/ext/vendor/exuberant-ctags/vstring.h +85 -0
  133. data/ext/vendor/exuberant-ctags/yacc.c +40 -0
  134. data/lib/ctags/exuberant.rb +45 -0
  135. data/lib/ctags/version.rb +3 -0
  136. data/lib/ctags.rb +6 -0
  137. data/test/test_ctags.rb +24 -0
  138. metadata +233 -0
@@ -0,0 +1,704 @@
1
+ /*
2
+ * $Id: lregex.c 576 2007-06-30 04:16:23Z elliotth $
3
+ *
4
+ * Copyright (c) 2000-2003, Darren Hiebert
5
+ *
6
+ * This source code is released for free distribution under the terms of the
7
+ * GNU General Public License.
8
+ *
9
+ * This module contains functions for applying regular expression matching.
10
+ *
11
+ * The code for utlizing the Gnu regex package with regards to processing the
12
+ * regex option and checking for regex matches was adapted from routines in
13
+ * Gnu etags.
14
+ */
15
+
16
+ /*
17
+ * INCLUDE FILES
18
+ */
19
+ #include "general.h" /* must always come first */
20
+
21
+ #include <string.h>
22
+
23
+ #ifdef HAVE_REGCOMP
24
+ # include <ctype.h>
25
+ # include <stddef.h>
26
+ # ifdef HAVE_SYS_TYPES_H
27
+ # include <sys/types.h> /* declare off_t (not known to regex.h on FreeBSD) */
28
+ # endif
29
+ # include <regex.h>
30
+ #endif
31
+
32
+ #include "debug.h"
33
+ #include "entry.h"
34
+ #include "parse.h"
35
+ #include "read.h"
36
+ #include "routines.h"
37
+
38
+ #ifdef HAVE_REGEX
39
+
40
+ /*
41
+ * MACROS
42
+ */
43
+
44
+ /* Back-references \0 through \9 */
45
+ #define BACK_REFERENCE_COUNT 10
46
+
47
+ #if defined (HAVE_REGCOMP) && !defined (REGCOMP_BROKEN)
48
+ # define POSIX_REGEX
49
+ #endif
50
+
51
+ #define REGEX_NAME "Regex"
52
+
53
+ /*
54
+ * DATA DECLARATIONS
55
+ */
56
+ #if defined (POSIX_REGEX)
57
+
58
+ struct sKind {
59
+ boolean enabled;
60
+ char letter;
61
+ char* name;
62
+ char* description;
63
+ };
64
+
65
+ enum pType { PTRN_TAG, PTRN_CALLBACK };
66
+
67
+ typedef struct {
68
+ regex_t *pattern;
69
+ enum pType type;
70
+ union {
71
+ struct {
72
+ char *name_pattern;
73
+ struct sKind kind;
74
+ } tag;
75
+ struct {
76
+ regexCallback function;
77
+ } callback;
78
+ } u;
79
+ } regexPattern;
80
+
81
+ #endif
82
+
83
+ typedef struct {
84
+ regexPattern *patterns;
85
+ unsigned int count;
86
+ } patternSet;
87
+
88
+ /*
89
+ * DATA DEFINITIONS
90
+ */
91
+
92
+ static boolean regexBroken = FALSE;
93
+
94
+ /* Array of pattern sets, indexed by language */
95
+ static patternSet* Sets = NULL;
96
+ static int SetUpper = -1; /* upper language index in list */
97
+
98
+ /*
99
+ * FUNCTION DEFINITIONS
100
+ */
101
+
102
+ static void clearPatternSet (const langType language)
103
+ {
104
+ if (language <= SetUpper)
105
+ {
106
+ patternSet* const set = Sets + language;
107
+ unsigned int i;
108
+ for (i = 0 ; i < set->count ; ++i)
109
+ {
110
+ regexPattern *p = &set->patterns [i];
111
+ #if defined (POSIX_REGEX)
112
+ regfree (p->pattern);
113
+ #endif
114
+ eFree (p->pattern);
115
+ p->pattern = NULL;
116
+
117
+ if (p->type == PTRN_TAG)
118
+ {
119
+ eFree (p->u.tag.name_pattern);
120
+ p->u.tag.name_pattern = NULL;
121
+ eFree (p->u.tag.kind.name);
122
+ p->u.tag.kind.name = NULL;
123
+ if (p->u.tag.kind.description != NULL)
124
+ {
125
+ eFree (p->u.tag.kind.description);
126
+ p->u.tag.kind.description = NULL;
127
+ }
128
+ }
129
+ }
130
+ if (set->patterns != NULL)
131
+ eFree (set->patterns);
132
+ set->patterns = NULL;
133
+ set->count = 0;
134
+ }
135
+ }
136
+
137
+ /*
138
+ * Regex psuedo-parser
139
+ */
140
+
141
+ static void makeRegexTag (
142
+ const vString* const name, const struct sKind* const kind)
143
+ {
144
+ if (kind->enabled)
145
+ {
146
+ tagEntryInfo e;
147
+ Assert (name != NULL && vStringLength (name) > 0);
148
+ Assert (kind != NULL);
149
+ initTagEntry (&e, vStringValue (name));
150
+ e.kind = kind->letter;
151
+ e.kindName = kind->name;
152
+ makeTagEntry (&e);
153
+ }
154
+ }
155
+
156
+ /*
157
+ * Regex pattern definition
158
+ */
159
+
160
+ /* Take a string like "/blah/" and turn it into "blah", making sure
161
+ * that the first and last characters are the same, and handling
162
+ * quoted separator characters. Actually, stops on the occurrence of
163
+ * an unquoted separator. Also turns "\t" into a Tab character.
164
+ * Returns pointer to terminating separator. Works in place. Null
165
+ * terminates name string.
166
+ */
167
+ static char* scanSeparators (char* name)
168
+ {
169
+ char sep = name [0];
170
+ char *copyto = name;
171
+ boolean quoted = FALSE;
172
+
173
+ for (++name ; *name != '\0' ; ++name)
174
+ {
175
+ if (quoted)
176
+ {
177
+ if (*name == sep)
178
+ *copyto++ = sep;
179
+ else if (*name == 't')
180
+ *copyto++ = '\t';
181
+ else
182
+ {
183
+ /* Something else is quoted, so preserve the quote. */
184
+ *copyto++ = '\\';
185
+ *copyto++ = *name;
186
+ }
187
+ quoted = FALSE;
188
+ }
189
+ else if (*name == '\\')
190
+ quoted = TRUE;
191
+ else if (*name == sep)
192
+ {
193
+ break;
194
+ }
195
+ else
196
+ *copyto++ = *name;
197
+ }
198
+ *copyto = '\0';
199
+ return name;
200
+ }
201
+
202
+ /* Parse `regexp', in form "/regex/name/[k,Kind/]flags" (where the separator
203
+ * character is whatever the first character of `regexp' is), by breaking it
204
+ * up into null terminated strings, removing the separators, and expanding
205
+ * '\t' into tabs. When complete, `regexp' points to the line matching
206
+ * pattern, a pointer to the name matching pattern is written to `name', a
207
+ * pointer to the kinds is written to `kinds' (possibly NULL), and a pointer
208
+ * to the trailing flags is written to `flags'. If the pattern is not in the
209
+ * correct format, a false value is returned.
210
+ */
211
+ static boolean parseTagRegex (
212
+ char* const regexp, char** const name,
213
+ char** const kinds, char** const flags)
214
+ {
215
+ boolean result = FALSE;
216
+ const int separator = (unsigned char) regexp [0];
217
+
218
+ *name = scanSeparators (regexp);
219
+ if (*regexp == '\0')
220
+ error (WARNING, "empty regexp");
221
+ else if (**name != separator)
222
+ error (WARNING, "%s: incomplete regexp", regexp);
223
+ else
224
+ {
225
+ char* const third = scanSeparators (*name);
226
+ if (**name == '\0')
227
+ error (WARNING, "%s: regexp missing name pattern", regexp);
228
+ if ((*name) [strlen (*name) - 1] == '\\')
229
+ error (WARNING, "error in name pattern: \"%s\"", *name);
230
+ if (*third != separator)
231
+ error (WARNING, "%s: regexp missing final separator", regexp);
232
+ else
233
+ {
234
+ char* const fourth = scanSeparators (third);
235
+ if (*fourth == separator)
236
+ {
237
+ *kinds = third;
238
+ scanSeparators (fourth);
239
+ *flags = fourth;
240
+ }
241
+ else
242
+ {
243
+ *flags = third;
244
+ *kinds = NULL;
245
+ }
246
+ result = TRUE;
247
+ }
248
+ }
249
+ return result;
250
+ }
251
+
252
+ static void addCompiledTagPattern (
253
+ const langType language, regex_t* const pattern,
254
+ char* const name, const char kind, char* const kindName,
255
+ char *const description)
256
+ {
257
+ patternSet* set;
258
+ regexPattern *ptrn;
259
+ if (language > SetUpper)
260
+ {
261
+ int i;
262
+ Sets = xRealloc (Sets, (language + 1), patternSet);
263
+ for (i = SetUpper + 1 ; i <= language ; ++i)
264
+ {
265
+ Sets [i].patterns = NULL;
266
+ Sets [i].count = 0;
267
+ }
268
+ SetUpper = language;
269
+ }
270
+ set = Sets + language;
271
+ set->patterns = xRealloc (set->patterns, (set->count + 1), regexPattern);
272
+ ptrn = &set->patterns [set->count];
273
+ set->count += 1;
274
+
275
+ ptrn->pattern = pattern;
276
+ ptrn->type = PTRN_TAG;
277
+ ptrn->u.tag.name_pattern = name;
278
+ ptrn->u.tag.kind.enabled = TRUE;
279
+ ptrn->u.tag.kind.letter = kind;
280
+ ptrn->u.tag.kind.name = kindName;
281
+ ptrn->u.tag.kind.description = description;
282
+ }
283
+
284
+ static void addCompiledCallbackPattern (
285
+ const langType language, regex_t* const pattern,
286
+ const regexCallback callback)
287
+ {
288
+ patternSet* set;
289
+ regexPattern *ptrn;
290
+ if (language > SetUpper)
291
+ {
292
+ int i;
293
+ Sets = xRealloc (Sets, (language + 1), patternSet);
294
+ for (i = SetUpper + 1 ; i <= language ; ++i)
295
+ {
296
+ Sets [i].patterns = NULL;
297
+ Sets [i].count = 0;
298
+ }
299
+ SetUpper = language;
300
+ }
301
+ set = Sets + language;
302
+ set->patterns = xRealloc (set->patterns, (set->count + 1), regexPattern);
303
+ ptrn = &set->patterns [set->count];
304
+ set->count += 1;
305
+
306
+ ptrn->pattern = pattern;
307
+ ptrn->type = PTRN_CALLBACK;
308
+ ptrn->u.callback.function = callback;
309
+ }
310
+
311
+ #if defined (POSIX_REGEX)
312
+
313
+ static regex_t* compileRegex (const char* const regexp, const char* const flags)
314
+ {
315
+ int cflags = REG_EXTENDED | REG_NEWLINE;
316
+ regex_t *result = NULL;
317
+ int errcode;
318
+ int i;
319
+ for (i = 0 ; flags != NULL && flags [i] != '\0' ; ++i)
320
+ {
321
+ switch ((int) flags [i])
322
+ {
323
+ case 'b': cflags &= ~REG_EXTENDED; break;
324
+ case 'e': cflags |= REG_EXTENDED; break;
325
+ case 'i': cflags |= REG_ICASE; break;
326
+ default: error (WARNING, "unknown regex flag: '%c'", *flags); break;
327
+ }
328
+ }
329
+ result = xMalloc (1, regex_t);
330
+ errcode = regcomp (result, regexp, cflags);
331
+ if (errcode != 0)
332
+ {
333
+ char errmsg[256];
334
+ regerror (errcode, result, errmsg, 256);
335
+ error (WARNING, "regcomp %s: %s", regexp, errmsg);
336
+ regfree (result);
337
+ eFree (result);
338
+ result = NULL;
339
+ }
340
+ return result;
341
+ }
342
+
343
+ #endif
344
+
345
+ static void parseKinds (
346
+ const char* const kinds, char* const kind, char** const kindName,
347
+ char **description)
348
+ {
349
+ *kind = '\0';
350
+ *kindName = NULL;
351
+ *description = NULL;
352
+ if (kinds == NULL || kinds [0] == '\0')
353
+ {
354
+ *kind = 'r';
355
+ *kindName = eStrdup ("regex");
356
+ }
357
+ else if (kinds [0] != '\0')
358
+ {
359
+ const char* k = kinds;
360
+ if (k [0] != ',' && (k [1] == ',' || k [1] == '\0'))
361
+ *kind = *k++;
362
+ else
363
+ *kind = 'r';
364
+ if (*k == ',')
365
+ ++k;
366
+ if (k [0] == '\0')
367
+ *kindName = eStrdup ("regex");
368
+ else
369
+ {
370
+ const char *const comma = strchr (k, ',');
371
+ if (comma == NULL)
372
+ *kindName = eStrdup (k);
373
+ else
374
+ {
375
+ *kindName = (char*) eMalloc (comma - k + 1);
376
+ strncpy (*kindName, k, comma - k);
377
+ (*kindName) [comma - k] = '\0';
378
+ k = comma + 1;
379
+ if (k [0] != '\0')
380
+ *description = eStrdup (k);
381
+ }
382
+ }
383
+ }
384
+ }
385
+
386
+ static void printRegexKind (const regexPattern *pat, unsigned int i, boolean indent)
387
+ {
388
+ const struct sKind *const kind = &pat [i].u.tag.kind;
389
+ const char *const indentation = indent ? " " : "";
390
+ Assert (pat [i].type == PTRN_TAG);
391
+ printf ("%s%c %s %s\n", indentation,
392
+ kind->letter != '\0' ? kind->letter : '?',
393
+ kind->description != NULL ? kind->description : kind->name,
394
+ kind->enabled ? "" : " [off]");
395
+ }
396
+
397
+ static void processLanguageRegex (const langType language,
398
+ const char* const parameter)
399
+ {
400
+ if (parameter == NULL || parameter [0] == '\0')
401
+ clearPatternSet (language);
402
+ else if (parameter [0] != '@')
403
+ addLanguageRegex (language, parameter);
404
+ else if (! doesFileExist (parameter + 1))
405
+ error (WARNING, "cannot open regex file");
406
+ else
407
+ {
408
+ const char* regexfile = parameter + 1;
409
+ FILE* const fp = fopen (regexfile, "r");
410
+ if (fp == NULL)
411
+ error (WARNING | PERROR, regexfile);
412
+ else
413
+ {
414
+ vString* const regex = vStringNew ();
415
+ while (readLine (regex, fp))
416
+ addLanguageRegex (language, vStringValue (regex));
417
+ fclose (fp);
418
+ vStringDelete (regex);
419
+ }
420
+ }
421
+ }
422
+
423
+ /*
424
+ * Regex pattern matching
425
+ */
426
+
427
+ #if defined (POSIX_REGEX)
428
+
429
+ static vString* substitute (
430
+ const char* const in, const char* out,
431
+ const int nmatch, const regmatch_t* const pmatch)
432
+ {
433
+ vString* result = vStringNew ();
434
+ const char* p;
435
+ for (p = out ; *p != '\0' ; p++)
436
+ {
437
+ if (*p == '\\' && isdigit ((int) *++p))
438
+ {
439
+ const int dig = *p - '0';
440
+ if (0 < dig && dig < nmatch && pmatch [dig].rm_so != -1)
441
+ {
442
+ const int diglen = pmatch [dig].rm_eo - pmatch [dig].rm_so;
443
+ vStringNCatS (result, in + pmatch [dig].rm_so, diglen);
444
+ }
445
+ }
446
+ else if (*p != '\n' && *p != '\r')
447
+ vStringPut (result, *p);
448
+ }
449
+ vStringTerminate (result);
450
+ return result;
451
+ }
452
+
453
+ static void matchTagPattern (const vString* const line,
454
+ const regexPattern* const patbuf,
455
+ const regmatch_t* const pmatch)
456
+ {
457
+ vString *const name = substitute (vStringValue (line),
458
+ patbuf->u.tag.name_pattern, BACK_REFERENCE_COUNT, pmatch);
459
+ vStringStripLeading (name);
460
+ vStringStripTrailing (name);
461
+ if (vStringLength (name) > 0)
462
+ makeRegexTag (name, &patbuf->u.tag.kind);
463
+ else
464
+ error (WARNING, "%s:%ld: null expansion of name pattern \"%s\"",
465
+ getInputFileName (), getInputLineNumber (),
466
+ patbuf->u.tag.name_pattern);
467
+ vStringDelete (name);
468
+ }
469
+
470
+ static void matchCallbackPattern (
471
+ const vString* const line, const regexPattern* const patbuf,
472
+ const regmatch_t* const pmatch)
473
+ {
474
+ regexMatch matches [BACK_REFERENCE_COUNT];
475
+ unsigned int count = 0;
476
+ int i;
477
+ for (i = 0 ; i < BACK_REFERENCE_COUNT && pmatch [i].rm_so != -1 ; ++i)
478
+ {
479
+ matches [i].start = pmatch [i].rm_so;
480
+ matches [i].length = pmatch [i].rm_eo - pmatch [i].rm_so;
481
+ ++count;
482
+ }
483
+ patbuf->u.callback.function (vStringValue (line), matches, count);
484
+ }
485
+
486
+ static boolean matchRegexPattern (const vString* const line,
487
+ const regexPattern* const patbuf)
488
+ {
489
+ boolean result = FALSE;
490
+ regmatch_t pmatch [BACK_REFERENCE_COUNT];
491
+ const int match = regexec (patbuf->pattern, vStringValue (line),
492
+ BACK_REFERENCE_COUNT, pmatch, 0);
493
+ if (match == 0)
494
+ {
495
+ result = TRUE;
496
+ if (patbuf->type == PTRN_TAG)
497
+ matchTagPattern (line, patbuf, pmatch);
498
+ else if (patbuf->type == PTRN_CALLBACK)
499
+ matchCallbackPattern (line, patbuf, pmatch);
500
+ else
501
+ {
502
+ Assert ("invalid pattern type" == NULL);
503
+ result = FALSE;
504
+ }
505
+ }
506
+ return result;
507
+ }
508
+
509
+ #endif
510
+
511
+ /* PUBLIC INTERFACE */
512
+
513
+ /* Match against all patterns for specified language. Returns true if at least
514
+ * on pattern matched.
515
+ */
516
+ extern boolean matchRegex (const vString* const line, const langType language)
517
+ {
518
+ boolean result = FALSE;
519
+ if (language != LANG_IGNORE && language <= SetUpper &&
520
+ Sets [language].count > 0)
521
+ {
522
+ const patternSet* const set = Sets + language;
523
+ unsigned int i;
524
+ for (i = 0 ; i < set->count ; ++i)
525
+ if (matchRegexPattern (line, set->patterns + i))
526
+ result = TRUE;
527
+ }
528
+ return result;
529
+ }
530
+
531
+ extern void findRegexTags (void)
532
+ {
533
+ /* merely read all lines of the file */
534
+ while (fileReadLine () != NULL)
535
+ ;
536
+ }
537
+
538
+ #endif /* HAVE_REGEX */
539
+
540
+ extern void addTagRegex (
541
+ const langType language __unused__,
542
+ const char* const regex __unused__,
543
+ const char* const name __unused__,
544
+ const char* const kinds __unused__,
545
+ const char* const flags __unused__)
546
+ {
547
+ #ifdef HAVE_REGEX
548
+ Assert (regex != NULL);
549
+ Assert (name != NULL);
550
+ if (! regexBroken)
551
+ {
552
+ regex_t* const cp = compileRegex (regex, flags);
553
+ if (cp != NULL)
554
+ {
555
+ char kind;
556
+ char* kindName;
557
+ char* description;
558
+ parseKinds (kinds, &kind, &kindName, &description);
559
+ addCompiledTagPattern (language, cp, eStrdup (name),
560
+ kind, kindName, description);
561
+ }
562
+ }
563
+ #endif
564
+ }
565
+
566
+ extern void addCallbackRegex (
567
+ const langType language __unused__,
568
+ const char* const regex __unused__,
569
+ const char* const flags __unused__,
570
+ const regexCallback callback __unused__)
571
+ {
572
+ #ifdef HAVE_REGEX
573
+ Assert (regex != NULL);
574
+ if (! regexBroken)
575
+ {
576
+ regex_t* const cp = compileRegex (regex, flags);
577
+ if (cp != NULL)
578
+ addCompiledCallbackPattern (language, cp, callback);
579
+ }
580
+ #endif
581
+ }
582
+
583
+ extern void addLanguageRegex (
584
+ const langType language __unused__, const char* const regex __unused__)
585
+ {
586
+ #ifdef HAVE_REGEX
587
+ if (! regexBroken)
588
+ {
589
+ char *const regex_pat = eStrdup (regex);
590
+ char *name, *kinds, *flags;
591
+ if (parseTagRegex (regex_pat, &name, &kinds, &flags))
592
+ {
593
+ addTagRegex (language, regex_pat, name, kinds, flags);
594
+ eFree (regex_pat);
595
+ }
596
+ }
597
+ #endif
598
+ }
599
+
600
+ /*
601
+ * Regex option parsing
602
+ */
603
+
604
+ extern boolean processRegexOption (const char *const option,
605
+ const char *const parameter __unused__)
606
+ {
607
+ boolean handled = FALSE;
608
+ const char* const dash = strchr (option, '-');
609
+ if (dash != NULL && strncmp (option, "regex", dash - option) == 0)
610
+ {
611
+ #ifdef HAVE_REGEX
612
+ langType language;
613
+ language = getNamedLanguage (dash + 1);
614
+ if (language == LANG_IGNORE)
615
+ error (WARNING, "unknown language \"%s\" in --%s option", (dash + 1), option);
616
+ else
617
+ processLanguageRegex (language, parameter);
618
+ #else
619
+ error (WARNING, "regex support not available; required for --%s option",
620
+ option);
621
+ #endif
622
+ handled = TRUE;
623
+ }
624
+ return handled;
625
+ }
626
+
627
+ extern void disableRegexKinds (const langType language __unused__)
628
+ {
629
+ #ifdef HAVE_REGEX
630
+ if (language <= SetUpper && Sets [language].count > 0)
631
+ {
632
+ patternSet* const set = Sets + language;
633
+ unsigned int i;
634
+ for (i = 0 ; i < set->count ; ++i)
635
+ if (set->patterns [i].type == PTRN_TAG)
636
+ set->patterns [i].u.tag.kind.enabled = FALSE;
637
+ }
638
+ #endif
639
+ }
640
+
641
+ extern boolean enableRegexKind (
642
+ const langType language __unused__,
643
+ const int kind __unused__, const boolean mode __unused__)
644
+ {
645
+ boolean result = FALSE;
646
+ #ifdef HAVE_REGEX
647
+ if (language <= SetUpper && Sets [language].count > 0)
648
+ {
649
+ patternSet* const set = Sets + language;
650
+ unsigned int i;
651
+ for (i = 0 ; i < set->count ; ++i)
652
+ if (set->patterns [i].type == PTRN_TAG &&
653
+ set->patterns [i].u.tag.kind.letter == kind)
654
+ {
655
+ set->patterns [i].u.tag.kind.enabled = mode;
656
+ result = TRUE;
657
+ }
658
+ }
659
+ #endif
660
+ return result;
661
+ }
662
+
663
+ extern void printRegexKinds (const langType language __unused__, boolean indent __unused__)
664
+ {
665
+ #ifdef HAVE_REGEX
666
+ if (language <= SetUpper && Sets [language].count > 0)
667
+ {
668
+ patternSet* const set = Sets + language;
669
+ unsigned int i;
670
+ for (i = 0 ; i < set->count ; ++i)
671
+ if (set->patterns [i].type == PTRN_TAG)
672
+ printRegexKind (set->patterns, i, indent);
673
+ }
674
+ #endif
675
+ }
676
+
677
+ extern void freeRegexResources (void)
678
+ {
679
+ #ifdef HAVE_REGEX
680
+ int i;
681
+ for (i = 0 ; i <= SetUpper ; ++i)
682
+ clearPatternSet (i);
683
+ if (Sets != NULL)
684
+ eFree (Sets);
685
+ Sets = NULL;
686
+ SetUpper = -1;
687
+ #endif
688
+ }
689
+
690
+ /* Check for broken regcomp() on Cygwin */
691
+ extern void checkRegex (void)
692
+ {
693
+ #if defined (HAVE_REGEX) && defined (CHECK_REGCOMP)
694
+ regex_t patbuf;
695
+ int errcode;
696
+ if (regcomp (&patbuf, "/hello/", 0) != 0)
697
+ {
698
+ error (WARNING, "Disabling broken regex");
699
+ regexBroken = TRUE;
700
+ }
701
+ #endif
702
+ }
703
+
704
+ /* vi:set tabstop=4 shiftwidth=4: */