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,847 @@
1
+ /*
2
+ * $Id: entry.c 443 2006-05-30 04:37:13Z darren $
3
+ *
4
+ * Copyright (c) 1996-2002, 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 creating tag entries.
10
+ */
11
+
12
+ /*
13
+ * INCLUDE FILES
14
+ */
15
+ #include "general.h" /* must always come first */
16
+
17
+ #include <string.h>
18
+ #include <ctype.h> /* to define isspace () */
19
+ #include <errno.h>
20
+
21
+ #if defined (HAVE_SYS_TYPES_H)
22
+ # include <sys/types.h> /* to declare off_t on some hosts */
23
+ #endif
24
+ #if defined (HAVE_TYPES_H)
25
+ # include <types.h> /* to declare off_t on some hosts */
26
+ #endif
27
+ #if defined (HAVE_UNISTD_H)
28
+ # include <unistd.h> /* to declare close (), ftruncate (), truncate () */
29
+ #endif
30
+
31
+ /* These header files provide for the functions necessary to do file
32
+ * truncation.
33
+ */
34
+ #ifdef HAVE_FCNTL_H
35
+ # include <fcntl.h>
36
+ #endif
37
+ #ifdef HAVE_IO_H
38
+ # include <io.h>
39
+ #endif
40
+
41
+ #include "debug.h"
42
+ #include "ctags.h"
43
+ #include "entry.h"
44
+ #include "main.h"
45
+ #include "options.h"
46
+ #include "read.h"
47
+ #include "routines.h"
48
+ #include "sort.h"
49
+ #include "strlist.h"
50
+
51
+ /*
52
+ * MACROS
53
+ */
54
+ #define PSEUDO_TAG_PREFIX "!_"
55
+
56
+ #define includeExtensionFlags() (Option.tagFileFormat > 1)
57
+
58
+ /*
59
+ * Portability defines
60
+ */
61
+ #if !defined(HAVE_TRUNCATE) && !defined(HAVE_FTRUNCATE) && !defined(HAVE_CHSIZE)
62
+ # define USE_REPLACEMENT_TRUNCATE
63
+ #endif
64
+
65
+ /* Hack for rediculous practice of Microsoft Visual C++.
66
+ */
67
+ #if defined (WIN32) && defined (_MSC_VER)
68
+ # define chsize _chsize
69
+ # define open _open
70
+ # define close _close
71
+ # define O_RDWR _O_RDWR
72
+ #endif
73
+
74
+ /*
75
+ * DATA DEFINITIONS
76
+ */
77
+
78
+ tagFile TagFile = {
79
+ NULL, /* tag file name */
80
+ NULL, /* tag file directory (absolute) */
81
+ NULL, /* file pointer */
82
+ { 0, 0 }, /* numTags */
83
+ { 0, 0, 0 }, /* max */
84
+ { NULL, NULL, 0 }, /* etags */
85
+ NULL /* vLine */
86
+ };
87
+
88
+ static boolean TagsToStdout = FALSE;
89
+
90
+ /*
91
+ * FUNCTION PROTOTYPES
92
+ */
93
+ #ifdef NEED_PROTO_TRUNCATE
94
+ extern int truncate (const char *path, off_t length);
95
+ #endif
96
+
97
+ #ifdef NEED_PROTO_FTRUNCATE
98
+ extern int ftruncate (int fd, off_t length);
99
+ #endif
100
+
101
+ /*
102
+ * FUNCTION DEFINITIONS
103
+ */
104
+
105
+ extern void freeTagFileResources (void)
106
+ {
107
+ if (TagFile.directory != NULL)
108
+ eFree (TagFile.directory);
109
+ vStringDelete (TagFile.vLine);
110
+ }
111
+
112
+ extern const char *tagFileName (void)
113
+ {
114
+ return TagFile.name;
115
+ }
116
+
117
+ /*
118
+ * Pseudo tag support
119
+ */
120
+
121
+ static void rememberMaxLengths (const size_t nameLength, const size_t lineLength)
122
+ {
123
+ if (nameLength > TagFile.max.tag)
124
+ TagFile.max.tag = nameLength;
125
+
126
+ if (lineLength > TagFile.max.line)
127
+ TagFile.max.line = lineLength;
128
+ }
129
+
130
+ static void writePseudoTag (
131
+ const char *const tagName,
132
+ const char *const fileName,
133
+ const char *const pattern)
134
+ {
135
+ const int length = fprintf (
136
+ TagFile.fp, "%s%s\t%s\t/%s/\n",
137
+ PSEUDO_TAG_PREFIX, tagName, fileName, pattern);
138
+ ++TagFile.numTags.added;
139
+ rememberMaxLengths (strlen (tagName), (size_t) length);
140
+ }
141
+
142
+ static void addPseudoTags (void)
143
+ {
144
+ if (! Option.xref)
145
+ {
146
+ char format [11];
147
+ const char *formatComment = "unknown format";
148
+
149
+ sprintf (format, "%u", Option.tagFileFormat);
150
+
151
+ if (Option.tagFileFormat == 1)
152
+ formatComment = "original ctags format";
153
+ else if (Option.tagFileFormat == 2)
154
+ formatComment =
155
+ "extended format; --format=1 will not append ;\" to lines";
156
+
157
+ writePseudoTag ("TAG_FILE_FORMAT", format, formatComment);
158
+ writePseudoTag ("TAG_FILE_SORTED",
159
+ Option.sorted == SO_FOLDSORTED ? "2" :
160
+ (Option.sorted == SO_SORTED ? "1" : "0"),
161
+ "0=unsorted, 1=sorted, 2=foldcase");
162
+ writePseudoTag ("TAG_PROGRAM_AUTHOR", AUTHOR_NAME, AUTHOR_EMAIL);
163
+ writePseudoTag ("TAG_PROGRAM_NAME", PROGRAM_NAME, "");
164
+ writePseudoTag ("TAG_PROGRAM_URL", PROGRAM_URL, "official site");
165
+ writePseudoTag ("TAG_PROGRAM_VERSION", PROGRAM_VERSION, "");
166
+ }
167
+ }
168
+
169
+ static void updateSortedFlag (
170
+ const char *const line, FILE *const fp, fpos_t startOfLine)
171
+ {
172
+ const char *const tab = strchr (line, '\t');
173
+
174
+ if (tab != NULL)
175
+ {
176
+ const long boolOffset = tab - line + 1; /* where it should be */
177
+
178
+ if (line [boolOffset] == '0' || line [boolOffset] == '1')
179
+ {
180
+ fpos_t nextLine;
181
+
182
+ if (fgetpos (fp, &nextLine) == -1 || fsetpos (fp, &startOfLine) == -1)
183
+ error (WARNING, "Failed to update 'sorted' pseudo-tag");
184
+ else
185
+ {
186
+ fpos_t flagLocation;
187
+ int c, d;
188
+
189
+ do
190
+ c = fgetc (fp);
191
+ while (c != '\t' && c != '\n');
192
+ fgetpos (fp, &flagLocation);
193
+ d = fgetc (fp);
194
+ if (c == '\t' && (d == '0' || d == '1') &&
195
+ d != (int) Option.sorted)
196
+ {
197
+ fsetpos (fp, &flagLocation);
198
+ fputc (Option.sorted == SO_FOLDSORTED ? '2' :
199
+ (Option.sorted == SO_SORTED ? '1' : '0'), fp);
200
+ }
201
+ fsetpos (fp, &nextLine);
202
+ }
203
+ }
204
+ }
205
+ }
206
+
207
+ /* Look through all line beginning with "!_TAG_FILE", and update those which
208
+ * require it.
209
+ */
210
+ static long unsigned int updatePseudoTags (FILE *const fp)
211
+ {
212
+ enum { maxEntryLength = 20 };
213
+ char entry [maxEntryLength + 1];
214
+ unsigned long linesRead = 0;
215
+ fpos_t startOfLine;
216
+ size_t entryLength;
217
+ const char *line;
218
+
219
+ sprintf (entry, "%sTAG_FILE", PSEUDO_TAG_PREFIX);
220
+ entryLength = strlen (entry);
221
+ Assert (entryLength < maxEntryLength);
222
+
223
+ fgetpos (fp, &startOfLine);
224
+ line = readLine (TagFile.vLine, fp);
225
+ while (line != NULL && line [0] == entry [0])
226
+ {
227
+ ++linesRead;
228
+ if (strncmp (line, entry, entryLength) == 0)
229
+ {
230
+ char tab, classType [16];
231
+
232
+ if (sscanf (line + entryLength, "%15s%c", classType, &tab) == 2 &&
233
+ tab == '\t')
234
+ {
235
+ if (strcmp (classType, "_SORTED") == 0)
236
+ updateSortedFlag (line, fp, startOfLine);
237
+ }
238
+ fgetpos (fp, &startOfLine);
239
+ }
240
+ line = readLine (TagFile.vLine, fp);
241
+ }
242
+ while (line != NULL) /* skip to end of file */
243
+ {
244
+ ++linesRead;
245
+ line = readLine (TagFile.vLine, fp);
246
+ }
247
+ return linesRead;
248
+ }
249
+
250
+ /*
251
+ * Tag file management
252
+ */
253
+
254
+ static boolean isValidTagAddress (const char *const excmd)
255
+ {
256
+ boolean isValid = FALSE;
257
+
258
+ if (strchr ("/?", excmd [0]) != NULL)
259
+ isValid = TRUE;
260
+ else
261
+ {
262
+ char *address = xMalloc (strlen (excmd) + 1, char);
263
+ if (sscanf (excmd, "%[^;\n]", address) == 1 &&
264
+ strspn (address,"0123456789") == strlen (address))
265
+ isValid = TRUE;
266
+ eFree (address);
267
+ }
268
+ return isValid;
269
+ }
270
+
271
+ static boolean isCtagsLine (const char *const line)
272
+ {
273
+ enum fieldList { TAG, TAB1, SRC_FILE, TAB2, EXCMD, NUM_FIELDS };
274
+ boolean ok = FALSE; /* we assume not unless confirmed */
275
+ const size_t fieldLength = strlen (line) + 1;
276
+ char *const fields = xMalloc (NUM_FIELDS * fieldLength, char);
277
+
278
+ if (fields == NULL)
279
+ error (FATAL, "Cannot analyze tag file");
280
+ else
281
+ {
282
+ #define field(x) (fields + ((size_t) (x) * fieldLength))
283
+
284
+ const int numFields = sscanf (
285
+ line, "%[^\t]%[\t]%[^\t]%[\t]%[^\r\n]",
286
+ field (TAG), field (TAB1), field (SRC_FILE),
287
+ field (TAB2), field (EXCMD));
288
+
289
+ /* There must be exactly five fields: two tab fields containing
290
+ * exactly one tab each, the tag must not begin with "#", and the
291
+ * file name should not end with ";", and the excmd must be
292
+ * accceptable.
293
+ *
294
+ * These conditions will reject tag-looking lines like:
295
+ * int a; <C-comment>
296
+ * #define LABEL <C-comment>
297
+ */
298
+ if (numFields == NUM_FIELDS &&
299
+ strlen (field (TAB1)) == 1 &&
300
+ strlen (field (TAB2)) == 1 &&
301
+ field (TAG) [0] != '#' &&
302
+ field (SRC_FILE) [strlen (field (SRC_FILE)) - 1] != ';' &&
303
+ isValidTagAddress (field (EXCMD)))
304
+ ok = TRUE;
305
+
306
+ eFree (fields);
307
+ }
308
+ return ok;
309
+ }
310
+
311
+ static boolean isEtagsLine (const char *const line)
312
+ {
313
+ boolean result = FALSE;
314
+ if (line [0] == '\f')
315
+ result = (boolean) (line [1] == '\n' || line [1] == '\r');
316
+ return result;
317
+ }
318
+
319
+ static boolean isTagFile (const char *const filename)
320
+ {
321
+ boolean ok = FALSE; /* we assume not unless confirmed */
322
+ FILE *const fp = fopen (filename, "rb");
323
+
324
+ if (fp == NULL && errno == ENOENT)
325
+ ok = TRUE;
326
+ else if (fp != NULL)
327
+ {
328
+ const char *line = readLine (TagFile.vLine, fp);
329
+
330
+ if (line == NULL)
331
+ ok = TRUE;
332
+ else
333
+ ok = (boolean) (isCtagsLine (line) || isEtagsLine (line));
334
+ fclose (fp);
335
+ }
336
+ return ok;
337
+ }
338
+
339
+ extern void copyBytes (FILE* const fromFp, FILE* const toFp, const long size)
340
+ {
341
+ enum { BufferSize = 1000 };
342
+ long toRead, numRead;
343
+ char* buffer = xMalloc (BufferSize, char);
344
+ long remaining = size;
345
+ do
346
+ {
347
+ toRead = (0 < remaining && remaining < BufferSize) ?
348
+ remaining : (long) BufferSize;
349
+ numRead = fread (buffer, (size_t) 1, (size_t) toRead, fromFp);
350
+ if (fwrite (buffer, (size_t)1, (size_t)numRead, toFp) < (size_t)numRead)
351
+ error (FATAL | PERROR, "cannot complete write");
352
+ if (remaining > 0)
353
+ remaining -= numRead;
354
+ } while (numRead == toRead && remaining != 0);
355
+ eFree (buffer);
356
+ }
357
+
358
+ extern void copyFile (const char *const from, const char *const to, const long size)
359
+ {
360
+ FILE* const fromFp = fopen (from, "rb");
361
+ if (fromFp == NULL)
362
+ error (FATAL | PERROR, "cannot open file to copy");
363
+ else
364
+ {
365
+ FILE* const toFp = fopen (to, "wb");
366
+ if (toFp == NULL)
367
+ error (FATAL | PERROR, "cannot open copy destination");
368
+ else
369
+ {
370
+ copyBytes (fromFp, toFp, size);
371
+ fclose (toFp);
372
+ }
373
+ fclose (fromFp);
374
+ }
375
+ }
376
+
377
+ extern void openTagFile (void)
378
+ {
379
+ setDefaultTagFileName ();
380
+ TagsToStdout = isDestinationStdout ();
381
+
382
+ if (TagFile.vLine == NULL)
383
+ TagFile.vLine = vStringNew ();
384
+
385
+ /* Open the tags file.
386
+ */
387
+ if (TagsToStdout)
388
+ TagFile.fp = tempFile ("w", &TagFile.name);
389
+ else
390
+ {
391
+ boolean fileExists;
392
+
393
+ setDefaultTagFileName ();
394
+ TagFile.name = eStrdup (Option.tagFileName);
395
+ fileExists = doesFileExist (TagFile.name);
396
+ if (fileExists && ! isTagFile (TagFile.name))
397
+ error (FATAL,
398
+ "\"%s\" doesn't look like a tag file; I refuse to overwrite it.",
399
+ TagFile.name);
400
+
401
+ if (Option.etags)
402
+ {
403
+ if (Option.append && fileExists)
404
+ TagFile.fp = fopen (TagFile.name, "a+b");
405
+ else
406
+ TagFile.fp = fopen (TagFile.name, "w+b");
407
+ }
408
+ else
409
+ {
410
+ if (Option.append && fileExists)
411
+ {
412
+ TagFile.fp = fopen (TagFile.name, "r+");
413
+ if (TagFile.fp != NULL)
414
+ {
415
+ TagFile.numTags.prev = updatePseudoTags (TagFile.fp);
416
+ fclose (TagFile.fp);
417
+ TagFile.fp = fopen (TagFile.name, "a+");
418
+ }
419
+ }
420
+ else
421
+ {
422
+ TagFile.fp = fopen (TagFile.name, "w");
423
+ if (TagFile.fp != NULL)
424
+ addPseudoTags ();
425
+ }
426
+ }
427
+ if (TagFile.fp == NULL)
428
+ {
429
+ error (FATAL | PERROR, "cannot open tag file");
430
+ exit (1);
431
+ }
432
+ }
433
+ if (TagsToStdout)
434
+ TagFile.directory = eStrdup (CurrentDirectory);
435
+ else
436
+ TagFile.directory = absoluteDirname (TagFile.name);
437
+ }
438
+
439
+ #ifdef USE_REPLACEMENT_TRUNCATE
440
+
441
+ /* Replacement for missing library function.
442
+ */
443
+ static int replacementTruncate (const char *const name, const long size)
444
+ {
445
+ char *tempName = NULL;
446
+ FILE *fp = tempFile ("w", &tempName);
447
+ fclose (fp);
448
+ copyFile (name, tempName, size);
449
+ copyFile (tempName, name, WHOLE_FILE);
450
+ remove (tempName);
451
+ eFree (tempName);
452
+
453
+ return 0;
454
+ }
455
+
456
+ #endif
457
+
458
+ static void sortTagFile (void)
459
+ {
460
+ if (TagFile.numTags.added > 0L)
461
+ {
462
+ if (Option.sorted != SO_UNSORTED)
463
+ {
464
+ verbose ("sorting tag file\n");
465
+ #ifdef EXTERNAL_SORT
466
+ externalSortTags (TagsToStdout);
467
+ #else
468
+ internalSortTags (TagsToStdout);
469
+ #endif
470
+ }
471
+ else if (TagsToStdout)
472
+ catFile (tagFileName ());
473
+ }
474
+ if (TagsToStdout)
475
+ remove (tagFileName ()); /* remove temporary file */
476
+ }
477
+
478
+ static void resizeTagFile (const long newSize)
479
+ {
480
+ int result;
481
+
482
+ #ifdef USE_REPLACEMENT_TRUNCATE
483
+ result = replacementTruncate (TagFile.name, newSize);
484
+ #else
485
+ # ifdef HAVE_TRUNCATE
486
+ result = truncate (TagFile.name, (off_t) newSize);
487
+ # else
488
+ const int fd = open (TagFile.name, O_RDWR);
489
+
490
+ if (fd == -1)
491
+ result = -1;
492
+ else
493
+ {
494
+ # ifdef HAVE_FTRUNCATE
495
+ result = ftruncate (fd, (off_t) newSize);
496
+ # else
497
+ # ifdef HAVE_CHSIZE
498
+ result = chsize (fd, newSize);
499
+ # endif
500
+ # endif
501
+ close (fd);
502
+ }
503
+ # endif
504
+ #endif
505
+ if (result == -1)
506
+ fprintf (errout, "Cannot shorten tag file: errno = %d\n", errno);
507
+ }
508
+
509
+ static void writeEtagsIncludes (FILE *const fp)
510
+ {
511
+ if (Option.etagsInclude)
512
+ {
513
+ unsigned int i;
514
+ for (i = 0 ; i < stringListCount (Option.etagsInclude) ; ++i)
515
+ {
516
+ vString *item = stringListItem (Option.etagsInclude, i);
517
+ fprintf (fp, "\f\n%s,include\n", vStringValue (item));
518
+ }
519
+ }
520
+ }
521
+
522
+ extern void closeTagFile (const boolean resize)
523
+ {
524
+ long desiredSize, size;
525
+
526
+ if (Option.etags)
527
+ writeEtagsIncludes (TagFile.fp);
528
+ desiredSize = ftell (TagFile.fp);
529
+ fseek (TagFile.fp, 0L, SEEK_END);
530
+ size = ftell (TagFile.fp);
531
+ fclose (TagFile.fp);
532
+ if (resize && desiredSize < size)
533
+ {
534
+ DebugStatement (
535
+ debugPrintf (DEBUG_STATUS, "shrinking %s from %ld to %ld bytes\n",
536
+ TagFile.name, size, desiredSize); )
537
+ resizeTagFile (desiredSize);
538
+ }
539
+ sortTagFile ();
540
+ eFree (TagFile.name);
541
+ TagFile.name = NULL;
542
+ }
543
+
544
+ extern void beginEtagsFile (void)
545
+ {
546
+ TagFile.etags.fp = tempFile ("w+b", &TagFile.etags.name);
547
+ TagFile.etags.byteCount = 0;
548
+ }
549
+
550
+ extern void endEtagsFile (const char *const name)
551
+ {
552
+ const char *line;
553
+
554
+ fprintf (TagFile.fp, "\f\n%s,%ld\n", name, (long) TagFile.etags.byteCount);
555
+ if (TagFile.etags.fp != NULL)
556
+ {
557
+ rewind (TagFile.etags.fp);
558
+ while ((line = readLine (TagFile.vLine, TagFile.etags.fp)) != NULL)
559
+ fputs (line, TagFile.fp);
560
+ fclose (TagFile.etags.fp);
561
+ remove (TagFile.etags.name);
562
+ eFree (TagFile.etags.name);
563
+ TagFile.etags.fp = NULL;
564
+ TagFile.etags.name = NULL;
565
+ }
566
+ }
567
+
568
+ /*
569
+ * Tag entry management
570
+ */
571
+
572
+ /* This function copies the current line out to a specified file. It has no
573
+ * effect on the fileGetc () function. During copying, any '\' characters
574
+ * are doubled and a leading '^' or trailing '$' is also quoted. End of line
575
+ * characters (line feed or carriage return) are dropped.
576
+ */
577
+ static size_t writeSourceLine (FILE *const fp, const char *const line)
578
+ {
579
+ size_t length = 0;
580
+ const char *p;
581
+
582
+ /* Write everything up to, but not including, a line end character.
583
+ */
584
+ for (p = line ; *p != '\0' ; ++p)
585
+ {
586
+ const int next = *(p + 1);
587
+ const int c = *p;
588
+
589
+ if (c == CRETURN || c == NEWLINE)
590
+ break;
591
+
592
+ /* If character is '\', or a terminal '$', then quote it.
593
+ */
594
+ if (c == BACKSLASH || c == (Option.backward ? '?' : '/') ||
595
+ (c == '$' && (next == NEWLINE || next == CRETURN)))
596
+ {
597
+ putc (BACKSLASH, fp);
598
+ ++length;
599
+ }
600
+ putc (c, fp);
601
+ ++length;
602
+ }
603
+ return length;
604
+ }
605
+
606
+ /* Writes "line", stripping leading and duplicate white space.
607
+ */
608
+ static size_t writeCompactSourceLine (FILE *const fp, const char *const line)
609
+ {
610
+ boolean lineStarted = FALSE;
611
+ size_t length = 0;
612
+ const char *p;
613
+ int c;
614
+
615
+ /* Write everything up to, but not including, the newline.
616
+ */
617
+ for (p = line, c = *p ; c != NEWLINE && c != '\0' ; c = *++p)
618
+ {
619
+ if (lineStarted || ! isspace (c)) /* ignore leading spaces */
620
+ {
621
+ lineStarted = TRUE;
622
+ if (isspace (c))
623
+ {
624
+ int next;
625
+
626
+ /* Consume repeating white space.
627
+ */
628
+ while (next = *(p+1) , isspace (next) && next != NEWLINE)
629
+ ++p;
630
+ c = ' '; /* force space character for any white space */
631
+ }
632
+ if (c != CRETURN || *(p + 1) != NEWLINE)
633
+ {
634
+ putc (c, fp);
635
+ ++length;
636
+ }
637
+ }
638
+ }
639
+ return length;
640
+ }
641
+
642
+ static int writeXrefEntry (const tagEntryInfo *const tag)
643
+ {
644
+ const char *const line =
645
+ readSourceLine (TagFile.vLine, tag->filePosition, NULL);
646
+ int length;
647
+
648
+ if (Option.tagFileFormat == 1)
649
+ length = fprintf (TagFile.fp, "%-16s %4lu %-16s ", tag->name,
650
+ tag->lineNumber, tag->sourceFileName);
651
+ else
652
+ length = fprintf (TagFile.fp, "%-16s %-10s %4lu %-16s ", tag->name,
653
+ tag->kindName, tag->lineNumber, tag->sourceFileName);
654
+
655
+ length += writeCompactSourceLine (TagFile.fp, line);
656
+ putc (NEWLINE, TagFile.fp);
657
+ ++length;
658
+
659
+ return length;
660
+ }
661
+
662
+ /* Truncates the text line containing the tag at the character following the
663
+ * tag, providing a character which designates the end of the tag.
664
+ */
665
+ static void truncateTagLine (
666
+ char *const line, const char *const token, const boolean discardNewline)
667
+ {
668
+ char *p = strstr (line, token);
669
+
670
+ if (p != NULL)
671
+ {
672
+ p += strlen (token);
673
+ if (*p != '\0' && ! (*p == '\n' && discardNewline))
674
+ ++p; /* skip past character terminating character */
675
+ *p = '\0';
676
+ }
677
+ }
678
+
679
+ static int writeEtagsEntry (const tagEntryInfo *const tag)
680
+ {
681
+ int length;
682
+
683
+ if (tag->isFileEntry)
684
+ length = fprintf (TagFile.etags.fp, "\177%s\001%lu,0\n",
685
+ tag->name, tag->lineNumber);
686
+ else
687
+ {
688
+ long seekValue;
689
+ char *const line =
690
+ readSourceLine (TagFile.vLine, tag->filePosition, &seekValue);
691
+
692
+ if (tag->truncateLine)
693
+ truncateTagLine (line, tag->name, TRUE);
694
+ else
695
+ line [strlen (line) - 1] = '\0';
696
+
697
+ length = fprintf (TagFile.etags.fp, "%s\177%s\001%lu,%ld\n", line,
698
+ tag->name, tag->lineNumber, seekValue);
699
+ }
700
+ TagFile.etags.byteCount += length;
701
+
702
+ return length;
703
+ }
704
+
705
+ static int addExtensionFields (const tagEntryInfo *const tag)
706
+ {
707
+ const char* const kindKey = Option.extensionFields.kindKey ? "kind:" : "";
708
+ boolean first = TRUE;
709
+ const char* separator = ";\"";
710
+ const char* const empty = "";
711
+ int length = 0;
712
+ /* "sep" returns a value only the first time it is evaluated */
713
+ #define sep (first ? (first = FALSE, separator) : empty)
714
+
715
+ if (tag->kindName != NULL && (Option.extensionFields.kindLong ||
716
+ (Option.extensionFields.kind && tag->kind == '\0')))
717
+ length += fprintf (TagFile.fp,"%s\t%s%s", sep, kindKey, tag->kindName);
718
+ else if (tag->kind != '\0' && (Option.extensionFields.kind ||
719
+ (Option.extensionFields.kindLong && tag->kindName == NULL)))
720
+ length += fprintf (TagFile.fp, "%s\t%s%c", sep, kindKey, tag->kind);
721
+
722
+ if (Option.extensionFields.lineNumber)
723
+ length += fprintf (TagFile.fp, "%s\tline:%ld", sep, tag->lineNumber);
724
+
725
+ if (Option.extensionFields.language && tag->language != NULL)
726
+ length += fprintf (TagFile.fp, "%s\tlanguage:%s", sep, tag->language);
727
+
728
+ if (Option.extensionFields.scope &&
729
+ tag->extensionFields.scope [0] != NULL &&
730
+ tag->extensionFields.scope [1] != NULL)
731
+ length += fprintf (TagFile.fp, "%s\t%s:%s", sep,
732
+ tag->extensionFields.scope [0],
733
+ tag->extensionFields.scope [1]);
734
+
735
+ if (Option.extensionFields.typeRef &&
736
+ tag->extensionFields.typeRef [0] != NULL &&
737
+ tag->extensionFields.typeRef [1] != NULL)
738
+ length += fprintf (TagFile.fp, "%s\ttyperef:%s:%s", sep,
739
+ tag->extensionFields.typeRef [0],
740
+ tag->extensionFields.typeRef [1]);
741
+
742
+ if (Option.extensionFields.fileScope && tag->isFileScope)
743
+ length += fprintf (TagFile.fp, "%s\tfile:", sep);
744
+
745
+ if (Option.extensionFields.inheritance &&
746
+ tag->extensionFields.inheritance != NULL)
747
+ length += fprintf (TagFile.fp, "%s\tinherits:%s", sep,
748
+ tag->extensionFields.inheritance);
749
+
750
+ if (Option.extensionFields.access && tag->extensionFields.access != NULL)
751
+ length += fprintf (TagFile.fp, "%s\taccess:%s", sep,
752
+ tag->extensionFields.access);
753
+
754
+ if (Option.extensionFields.implementation &&
755
+ tag->extensionFields.implementation != NULL)
756
+ length += fprintf (TagFile.fp, "%s\timplementation:%s", sep,
757
+ tag->extensionFields.implementation);
758
+
759
+ if (Option.extensionFields.signature &&
760
+ tag->extensionFields.signature != NULL)
761
+ length += fprintf (TagFile.fp, "%s\tsignature:%s", sep,
762
+ tag->extensionFields.signature);
763
+
764
+ return length;
765
+ #undef sep
766
+ }
767
+
768
+ static int writePatternEntry (const tagEntryInfo *const tag)
769
+ {
770
+ char *const line = readSourceLine (TagFile.vLine, tag->filePosition, NULL);
771
+ const int searchChar = Option.backward ? '?' : '/';
772
+ boolean newlineTerminated;
773
+ int length = 0;
774
+
775
+ if (tag->truncateLine)
776
+ truncateTagLine (line, tag->name, FALSE);
777
+ newlineTerminated = (boolean) (line [strlen (line) - 1] == '\n');
778
+
779
+ length += fprintf (TagFile.fp, "%c^", searchChar);
780
+ length += writeSourceLine (TagFile.fp, line);
781
+ length += fprintf (TagFile.fp, "%s%c", newlineTerminated ? "$":"", searchChar);
782
+
783
+ return length;
784
+ }
785
+
786
+ static int writeLineNumberEntry (const tagEntryInfo *const tag)
787
+ {
788
+ return fprintf (TagFile.fp, "%lu", tag->lineNumber);
789
+ }
790
+
791
+ static int writeCtagsEntry (const tagEntryInfo *const tag)
792
+ {
793
+ int length = fprintf (TagFile.fp, "%s\t%s\t",
794
+ tag->name, tag->sourceFileName);
795
+
796
+ if (tag->lineNumberEntry)
797
+ length += writeLineNumberEntry (tag);
798
+ else
799
+ length += writePatternEntry (tag);
800
+
801
+ if (includeExtensionFlags ())
802
+ length += addExtensionFields (tag);
803
+
804
+ length += fprintf (TagFile.fp, "\n");
805
+
806
+ return length;
807
+ }
808
+
809
+ extern void makeTagEntry (const tagEntryInfo *const tag)
810
+ {
811
+ Assert (tag->name != NULL);
812
+ if (tag->name [0] == '\0')
813
+ error (WARNING, "ignoring null tag in %s", vStringValue (File.name));
814
+ else
815
+ {
816
+ int length = 0;
817
+
818
+ DebugStatement ( debugEntry (tag); )
819
+ if (Option.xref)
820
+ {
821
+ if (! tag->isFileEntry)
822
+ length = writeXrefEntry (tag);
823
+ }
824
+ else if (Option.etags)
825
+ length = writeEtagsEntry (tag);
826
+ else
827
+ length = writeCtagsEntry (tag);
828
+
829
+ ++TagFile.numTags.added;
830
+ rememberMaxLengths (strlen (tag->name), (size_t) length);
831
+ DebugStatement ( fflush (TagFile.fp); )
832
+ }
833
+ }
834
+
835
+ extern void initTagEntry (tagEntryInfo *const e, const char *const name)
836
+ {
837
+ Assert (File.source.name != NULL);
838
+ memset (e, 0, sizeof (tagEntryInfo));
839
+ e->lineNumberEntry = (boolean) (Option.locate == EX_LINENUM);
840
+ e->lineNumber = getSourceLineNumber ();
841
+ e->language = getSourceLanguageName ();
842
+ e->filePosition = getInputFilePosition ();
843
+ e->sourceFileName = getSourceFileTagPath ();
844
+ e->name = name;
845
+ }
846
+
847
+ /* vi:set tabstop=4 shiftwidth=4: */