ctags.rb 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: */