1 /*
2 * Copyright (c) 1998-2002, Darren Hiebert
3 *
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
6 *
7 * External interface to entry.c
8 */
9
10 #include "general.h" /* must always come first */
11
12 #include "entry_p.h"
13 #include "field.h"
14 #include "field_p.h"
15 #include "mio.h"
16 #include "options_p.h"
17 #include "parse_p.h"
18 #include "ptag_p.h"
19 #include "read.h"
20 #include "writer_p.h"
21 #include "xtag.h"
22 #include "xtag_p.h"
23
24
25 #define CTAGS_FILE "tags"
26
27
28 static int writeCtagsEntry (tagWriter *writer CTAGS_ATTR_UNUSED,
29 MIO * mio, const tagEntryInfo *const tag,
30 void *clientData);
31 static int writeCtagsPtagEntry (tagWriter *writer CTAGS_ATTR_UNUSED,
32 MIO * mio, const ptagDesc *desc,
33 const char *const fileName,
34 const char *const pattern,
35 const char *const parserName,
36 void *clientData);
37 static bool treatFieldAsFixed (int fieldType);
38 static void checkCtagsOptions (tagWriter *writer, bool fieldsWereReset);
39
40 #ifdef WIN32
41 static enum filenameSepOp overrideFilenameSeparator (enum filenameSepOp currentSetting);
42 #endif /* WIN32 */
43
44 struct rejection {
45 bool rejectionInThisInput;
46 };
47
48 tagWriter uCtagsWriter = {
49 .writeEntry = writeCtagsEntry,
50 .writePtagEntry = writeCtagsPtagEntry,
51 .printPtagByDefault = true,
52 .preWriteEntry = NULL,
53 .postWriteEntry = NULL,
54 .rescanFailedEntry = NULL,
55 .treatFieldAsFixed = treatFieldAsFixed,
56 .checkOptions = checkCtagsOptions,
57 #ifdef WIN32
58 .overrideFilenameSeparator = overrideFilenameSeparator,
59 #endif
60 .defaultFileName = CTAGS_FILE,
61 };
62
beginECtagsFile(tagWriter * writer CTAGS_ATTR_UNUSED,MIO * mio CTAGS_ATTR_UNUSED,void * clientData CTAGS_ATTR_UNUSED)63 static void *beginECtagsFile (tagWriter *writer CTAGS_ATTR_UNUSED, MIO * mio CTAGS_ATTR_UNUSED,
64 void *clientData CTAGS_ATTR_UNUSED)
65 {
66 static struct rejection rej;
67
68 rej.rejectionInThisInput = false;
69
70 return &rej;
71 }
72
endECTagsFile(tagWriter * writer,MIO * mio CTAGS_ATTR_UNUSED,const char * filename CTAGS_ATTR_UNUSED,void * clientData CTAGS_ATTR_UNUSED)73 static bool endECTagsFile (tagWriter *writer, MIO * mio CTAGS_ATTR_UNUSED, const char* filename CTAGS_ATTR_UNUSED,
74 void *clientData CTAGS_ATTR_UNUSED)
75 {
76 struct rejection *rej = writer->private;
77 return rej->rejectionInThisInput;
78 }
79
80 #ifdef WIN32
overrideFilenameSeparator(enum filenameSepOp currentSetting)81 static enum filenameSepOp overrideFilenameSeparator (enum filenameSepOp currentSetting)
82 {
83 if (currentSetting == FILENAME_SEP_UNSET)
84 return FILENAME_SEP_USE_SLASH;
85 return currentSetting;
86 }
87 #endif
88
89 tagWriter eCtagsWriter = {
90 .writeEntry = writeCtagsEntry,
91 .writePtagEntry = writeCtagsPtagEntry,
92 .printPtagByDefault = true,
93 .preWriteEntry = beginECtagsFile,
94 .postWriteEntry = endECTagsFile,
95 .rescanFailedEntry = NULL,
96 .treatFieldAsFixed = treatFieldAsFixed,
97 .defaultFileName = CTAGS_FILE,
98 .checkOptions = checkCtagsOptions,
99 };
100
hasTagEntryTabOrNewlineChar(const tagEntryInfo * const tag)101 static bool hasTagEntryTabOrNewlineChar (const tagEntryInfo * const tag)
102 {
103
104 if (doesFieldHaveTabOrNewlineChar (FIELD_NAME, tag, NO_PARSER_FIELD)
105 || doesFieldHaveTabOrNewlineChar (FIELD_INPUT_FILE, tag, NO_PARSER_FIELD))
106 return true;
107
108 if (tag->lineNumberEntry)
109 {
110 if (Option.lineDirectives)
111 {
112 if (doesFieldHaveTabOrNewlineChar (FIELD_LINE_NUMBER, tag, NO_PARSER_FIELD))
113 return true;
114 }
115 }
116 else if (doesFieldHaveTabOrNewlineChar (FIELD_PATTERN, tag, NO_PARSER_FIELD))
117 {
118 /* Pattern may have a tab char. However, doesFieldHaveTabOrNewlineChar returns
119 * false because NO_PARSER_FIELD may not have doesContainAnyChar handler.
120 */
121 return true;
122 }
123
124 if (includeExtensionFlags ())
125 {
126 if (isFieldEnabled (FIELD_SCOPE) && doesFieldHaveValue (FIELD_SCOPE, tag)
127 && (doesFieldHaveTabOrNewlineChar (FIELD_SCOPE_KIND_LONG, tag, NO_PARSER_FIELD)
128 || doesFieldHaveTabOrNewlineChar (FIELD_SCOPE, tag, NO_PARSER_FIELD)))
129 return true;
130 if (isFieldEnabled (FIELD_TYPE_REF) && doesFieldHaveValue (FIELD_TYPE_REF, tag)
131 && doesFieldHaveTabOrNewlineChar (FIELD_TYPE_REF, tag, NO_PARSER_FIELD))
132 return true;
133 if (isFieldEnabled (FIELD_FILE_SCOPE) && doesFieldHaveValue (FIELD_FILE_SCOPE, tag)
134 && doesFieldHaveTabOrNewlineChar (FIELD_FILE_SCOPE, tag, NO_PARSER_FIELD))
135 return true;
136
137 int f[] = { FIELD_INHERITANCE,
138 FIELD_ACCESS,
139 FIELD_IMPLEMENTATION,
140 FIELD_SIGNATURE,
141 FIELD_ROLES,
142 FIELD_EXTRAS,
143 FIELD_XPATH,
144 FIELD_END_LINE,
145 -1};
146 for (unsigned int i = 0; f[i] >= 0; i++)
147 {
148 if (isFieldEnabled (f[i]) && doesFieldHaveValue (f[i], tag)
149 && doesFieldHaveTabOrNewlineChar (f[i], tag, NO_PARSER_FIELD))
150 return true;
151 }
152 }
153
154 for (unsigned int i = 0; i < tag->usedParserFields; i++)
155 {
156 const tagField *f = getParserFieldForIndex(tag, i);
157 fieldType ftype = f->ftype;
158 if (isFieldEnabled (ftype))
159 {
160 if (doesFieldHaveTabOrNewlineChar (ftype, tag, i))
161 return true;
162 }
163 }
164 return false;
165 }
166
167
escapeFieldValueFull(tagWriter * writer,const tagEntryInfo * tag,fieldType ftype,int fieldIndex)168 static const char* escapeFieldValueFull (tagWriter *writer, const tagEntryInfo * tag, fieldType ftype, int fieldIndex)
169 {
170 const char *v;
171 if (writer->type == WRITER_E_CTAGS && doesFieldHaveRenderer(ftype, true))
172 v = renderFieldNoEscaping (ftype, tag, fieldIndex);
173 else
174 v = renderField (ftype, tag, fieldIndex);
175
176 return v;
177 }
178
escapeFieldValue(tagWriter * writer,const tagEntryInfo * tag,fieldType ftype)179 static const char* escapeFieldValue (tagWriter *writer, const tagEntryInfo * tag, fieldType ftype)
180 {
181 return escapeFieldValueFull (writer, tag, ftype, NO_PARSER_FIELD);
182 }
183
renderExtensionFieldMaybe(tagWriter * writer,int xftype,const tagEntryInfo * const tag,char sep[2],MIO * mio)184 static int renderExtensionFieldMaybe (tagWriter *writer, int xftype, const tagEntryInfo *const tag, char sep[2], MIO *mio)
185 {
186 if (isFieldEnabled (xftype) && doesFieldHaveValue (xftype, tag))
187 {
188 int len;
189 len = mio_printf (mio, "%s\t%s:%s", sep,
190 getFieldName (xftype),
191 escapeFieldValue (writer, tag, xftype));
192 sep[0] = '\0';
193 return len;
194 }
195 else
196 return 0;
197 }
198
addParserFields(tagWriter * writer,MIO * mio,const tagEntryInfo * const tag)199 static int addParserFields (tagWriter *writer, MIO * mio, const tagEntryInfo *const tag)
200 {
201 unsigned int i;
202 int length = 0;
203
204 for (i = 0; i < tag->usedParserFields; i++)
205 {
206 const tagField *f = getParserFieldForIndex(tag, i);
207 fieldType ftype = f->ftype;
208 if (! isFieldEnabled (ftype))
209 continue;
210
211 length += mio_printf(mio, "\t%s:%s",
212 getFieldName (ftype),
213 escapeFieldValueFull (writer, tag, ftype, i));
214 }
215 return length;
216 }
217
writeLineNumberEntry(tagWriter * writer,MIO * mio,const tagEntryInfo * const tag)218 static int writeLineNumberEntry (tagWriter *writer, MIO * mio, const tagEntryInfo *const tag)
219 {
220 if (Option.lineDirectives)
221 return mio_printf (mio, "%s", escapeFieldValue (writer, tag, FIELD_LINE_NUMBER));
222 else
223 return mio_printf (mio, "%lu", tag->lineNumber);
224 }
225
addExtensionFields(tagWriter * writer,MIO * mio,const tagEntryInfo * const tag)226 static int addExtensionFields (tagWriter *writer, MIO *mio, const tagEntryInfo *const tag)
227 {
228 bool isKindKeyEnabled = isFieldEnabled (FIELD_KIND_KEY);
229 bool isScopeEnabled = isFieldEnabled (FIELD_SCOPE_KEY);
230
231 const char* const kindKey = isKindKeyEnabled
232 ?getFieldName (FIELD_KIND_KEY)
233 :"";
234 const char* const kindFmt = isKindKeyEnabled
235 ?"%s\t%s:%s"
236 :"%s\t%s%s";
237 const char* const scopeKey = isScopeEnabled
238 ?getFieldName (FIELD_SCOPE_KEY)
239 :"";
240 const char* const scopeFmt = isScopeEnabled
241 ?"%s\t%s:%s:%s"
242 :"%s\t%s%s:%s";
243
244 char sep [] = {';', '"', '\0'};
245 int length = 0;
246
247 const char *str = NULL;;
248 kindDefinition *kdef = getLanguageKind(tag->langType, tag->kindIndex);
249 const char kind_letter_str[2] = {kdef->letter, '\0'};
250
251 if (kdef->name != NULL && (isFieldEnabled (FIELD_KIND_LONG) ||
252 (isFieldEnabled (FIELD_KIND) && kdef->letter == KIND_NULL_LETTER)))
253 {
254 /* Use kind long name */
255 str = kdef->name;
256 }
257 else if (kdef->letter != KIND_NULL_LETTER && (isFieldEnabled (FIELD_KIND) ||
258 (isFieldEnabled (FIELD_KIND_LONG) && kdef->name == NULL)))
259 {
260 /* Use kind letter */
261 str = kind_letter_str;
262 }
263
264 if (str)
265 {
266 length += mio_printf (mio, kindFmt, sep, kindKey, str);
267 sep [0] = '\0';
268 }
269
270 if (isFieldEnabled (FIELD_LINE_NUMBER) && doesFieldHaveValue (FIELD_LINE_NUMBER, tag))
271 {
272 length += mio_printf (mio, "%s\t%s:%ld", sep,
273 getFieldName (FIELD_LINE_NUMBER),
274 tag->lineNumber);
275 sep [0] = '\0';
276 }
277
278 length += renderExtensionFieldMaybe (writer, FIELD_LANGUAGE, tag, sep, mio);
279
280 if (isFieldEnabled (FIELD_SCOPE))
281 {
282 const char* k, *v;
283
284 k = escapeFieldValue (writer, tag, FIELD_SCOPE_KIND_LONG);
285 v = escapeFieldValue (writer, tag, FIELD_SCOPE);
286 if (k && v)
287 {
288 length += mio_printf (mio, scopeFmt, sep, scopeKey, k, v);
289 sep [0] = '\0';
290 }
291 }
292
293 if (isFieldEnabled (FIELD_TYPE_REF) && doesFieldHaveValue (FIELD_TYPE_REF, tag))
294 {
295 length += mio_printf (mio, "%s\t%s:%s", sep,
296 getFieldName (FIELD_TYPE_REF),
297 escapeFieldValue (writer, tag, FIELD_TYPE_REF));
298 sep [0] = '\0';
299 }
300
301 if (isFieldEnabled (FIELD_FILE_SCOPE) && doesFieldHaveValue (FIELD_FILE_SCOPE, tag))
302 {
303 length += mio_printf (mio, "%s\t%s:", sep,
304 getFieldName (FIELD_FILE_SCOPE));
305 sep [0] = '\0';
306 }
307
308 for (int k = FIELD_ECTAGS_LOOP_START; k <= FIELD_ECTAGS_LOOP_LAST; k++)
309 length += renderExtensionFieldMaybe (writer, k, tag, sep, mio);
310 for (int k = FIELD_UCTAGS_LOOP_START; k <= FIELD_BUILTIN_LAST; k++)
311 length += renderExtensionFieldMaybe (writer, k, tag, sep, mio);
312
313 return length;
314 }
315
writeCtagsEntry(tagWriter * writer,MIO * mio,const tagEntryInfo * const tag,void * clientData CTAGS_ATTR_UNUSED)316 static int writeCtagsEntry (tagWriter *writer,
317 MIO * mio, const tagEntryInfo *const tag,
318 void *clientData CTAGS_ATTR_UNUSED)
319 {
320 if (writer->private)
321 {
322 struct rejection *rej = writer->private;
323 if (hasTagEntryTabOrNewlineChar (tag))
324 {
325 rej->rejectionInThisInput = true;
326 return 0;
327 }
328 }
329
330 int length = mio_printf (mio, "%s\t%s\t",
331 escapeFieldValue (writer, tag, FIELD_NAME),
332 escapeFieldValue (writer, tag, FIELD_INPUT_FILE));
333
334 /* This is for handling 'common' of 'fortran'. See the
335 description of --excmd=mixed in ctags.1. In tags output, what
336 we call "pattern" is instructions for vi.
337
338 However, in the other formats, pattern should be pattern as its name. */
339 if (tag->lineNumberEntry)
340 length += writeLineNumberEntry (writer, mio, tag);
341 else
342 {
343 if (Option.locate == EX_COMBINE)
344 length += mio_printf(mio, "%lu;", tag->lineNumber);
345 length += mio_puts(mio, escapeFieldValue(writer, tag, FIELD_PATTERN));
346 }
347
348 if (includeExtensionFlags ())
349 {
350 length += addExtensionFields (writer, mio, tag);
351 length += addParserFields (writer, mio, tag);
352 }
353
354 length += mio_printf (mio, "\n");
355
356 return length;
357 }
358
writeCtagsPtagEntry(tagWriter * writer CTAGS_ATTR_UNUSED,MIO * mio,const ptagDesc * desc,const char * const fileName,const char * const pattern,const char * const parserName,void * clientData CTAGS_ATTR_UNUSED)359 static int writeCtagsPtagEntry (tagWriter *writer CTAGS_ATTR_UNUSED,
360 MIO * mio, const ptagDesc *desc,
361 const char *const fileName,
362 const char *const pattern,
363 const char *const parserName,
364 void *clientData CTAGS_ATTR_UNUSED)
365 {
366
367 bool extras = includeExtensionFlags () && isFieldEnabled (FIELD_EXTRAS);
368 const char *xsep = extras? ";\" ": "";
369 const char *fsep = extras? ":": "";
370 const char *fieldx = extras? getFieldName (FIELD_EXTRAS): "";
371 const char *xptag = extras? getXtagName (XTAG_PSEUDO_TAGS): "";
372
373 return parserName
374
375 #define OPT(X) ((X)?(X):"")
376 ? mio_printf (mio, "%s%s%s%s\t%s\t/%s/%s%s%s%s\n",
377 PSEUDO_TAG_PREFIX, desc->name, PSEUDO_TAG_SEPARATOR, parserName,
378 OPT(fileName), OPT(pattern),
379 xsep, fieldx, fsep, xptag)
380 : mio_printf (mio, "%s%s\t%s\t/%s/%s%s%s%s\n",
381 PSEUDO_TAG_PREFIX, desc->name,
382 OPT(fileName), OPT(pattern),
383 xsep, fieldx, fsep, xptag);
384 #undef OPT
385 }
386
387 static fieldType fixedFields [] = {
388 FIELD_NAME,
389 FIELD_INPUT_FILE,
390 FIELD_PATTERN,
391 };
392
treatFieldAsFixed(int fieldType)393 static bool treatFieldAsFixed (int fieldType)
394 {
395 for (int i = 0; i < ARRAY_SIZE(fixedFields); i++)
396 if (fixedFields [i] == fieldType)
397 return true;
398 return false;
399 }
400
checkCtagsOptions(tagWriter * writer CTAGS_ATTR_UNUSED,bool fieldsWereReset)401 static void checkCtagsOptions (tagWriter *writer CTAGS_ATTR_UNUSED,
402 bool fieldsWereReset)
403 {
404 if (isFieldEnabled (FIELD_KIND_KEY)
405 && (!(isFieldEnabled (FIELD_KIND_LONG) ||
406 isFieldEnabled (FIELD_KIND))))
407 {
408 error (WARNING, "though %c/%s field is enabled, neither %c nor %c field is not enabled",
409 getFieldLetter (FIELD_KIND_KEY),
410 getFieldName (FIELD_KIND_KEY),
411 getFieldLetter (FIELD_KIND),
412 getFieldLetter (FIELD_KIND_LONG));
413 error (WARNING, "enable the %c field to make the %c/%s field printable",
414 getFieldLetter (FIELD_KIND_LONG),
415 getFieldLetter (FIELD_KIND_KEY),
416 getFieldName (FIELD_KIND_KEY));
417 enableField (FIELD_KIND_LONG, true);
418 }
419 if (isFieldEnabled (FIELD_SCOPE_KEY)
420 && !isFieldEnabled (FIELD_SCOPE))
421 {
422 error (WARNING, "though %c/%s field is enabled, %c field is not enabled",
423 getFieldLetter (FIELD_SCOPE_KEY),
424 getFieldName (FIELD_SCOPE_KEY),
425 getFieldLetter (FIELD_SCOPE));
426 error (WARNING, "enable the %c field to make the %c/%s field printable",
427 getFieldLetter (FIELD_SCOPE),
428 getFieldLetter (FIELD_SCOPE_KEY),
429 getFieldName (FIELD_SCOPE_KEY));
430 enableField (FIELD_SCOPE, true);
431 }
432
433 for (int i = 0; i < ARRAY_SIZE (fixedFields); i++)
434 {
435 if (!isFieldEnabled (fixedFields [i]))
436 {
437 enableField (fixedFields [i], true);
438
439 if (fieldsWereReset)
440 continue;
441
442 const char *name = getFieldName (fixedFields [i]);
443 unsigned char letter = getFieldLetter (fixedFields [i]);
444
445 if (name && letter != NUL_FIELD_LETTER)
446 error(WARNING, "Cannot disable fixed field: '%c'{%s} in ctags output mode",
447 letter, name);
448 else if (name)
449 error(WARNING, "Cannot disable fixed field: {%s} in ctags output mode",
450 name);
451 else if (letter != NUL_FIELD_LETTER)
452 error(WARNING, "Cannot disable fixed field: '%c' in ctags output mode",
453 letter);
454 }
455 }
456 }
457