Fix build with bleeding edge GLib
[geany-mirror.git] / tagmanager / ctags / parse.c
blobdf72b6dbc9290af272f0c206a3ebc6a47bdcb6b2
1 /*
3 * Copyright (c) 1996-2001, Darren Hiebert
5 * This source code is released for free distribution under the terms of the
6 * GNU General Public License.
8 * This module contains functions for managing source languages and
9 * dispatching files to the appropriate language parser.
13 * INCLUDE FILES
15 #include "general.h" /* must always come first */
17 #include <string.h>
18 #include <mio/mio.h>
21 #include "entry.h"
22 #include "main.h"
23 #define OPTION_WRITE
24 #include "options.h"
25 #include "parsers.h"
26 #include "read.h"
27 #include "vstring.h"
30 * DATA DEFINITIONS
32 static parserDefinitionFunc* BuiltInParsers[] = { PARSER_LIST };
33 parserDefinition** LanguageTable = NULL;
34 static unsigned int LanguageCount = 0;
35 tagEntryFunction TagEntryFunction = NULL;
36 tagEntrySetArglistFunction TagEntrySetArglistFunction = NULL;
39 * FUNCTION DEFINITIONS
42 extern void makeSimpleTag (const vString* const name,
43 kindOption* const kinds, const int kind)
45 if (name != NULL && vStringLength (name) > 0)
47 tagEntryInfo e;
48 initTagEntry (&e, vStringValue (name));
50 e.kindName = kinds [kind].name;
51 e.kind = kinds [kind].letter;
53 makeTagEntry (&e);
58 extern void makeSimpleScopedTag (const vString* const name,
59 kindOption* const kinds, const int kind,
60 const char* scope, const char *scope2,
61 const char *laccess)
63 if (name != NULL && vStringLength (name) > 0)
65 tagEntryInfo e;
66 initTagEntry (&e, vStringValue (name));
68 e.kindName = kinds [kind].name;
69 e.kind = kinds [kind].letter;
70 e.extensionFields.scope[0] = scope;
71 e.extensionFields.scope[1] = scope2;
72 e.extensionFields.access = laccess;
74 makeTagEntry (&e);
79 * parserDescription mapping management
82 extern parserDefinition* parserNew (const char* name)
84 parserDefinition* result = xCalloc (1, parserDefinition);
85 result->name = eStrdup (name);
86 return result;
89 extern const char *getLanguageName (const langType language)
91 /*Assert (0 <= language && language < (int) LanguageCount);*/
92 if (language < 0) return NULL;
93 return LanguageTable [language]->name;
96 extern langType getNamedLanguage (const char *const name)
98 langType result = LANG_IGNORE;
99 unsigned int i;
100 Assert (name != NULL);
101 for (i = 0 ; i < LanguageCount && result == LANG_IGNORE ; ++i)
103 if (LanguageTable [i]->name != NULL)
104 if (stricmp (name, LanguageTable [i]->name) == 0)
105 result = i;
107 return result;
110 static langType getExtensionLanguage (const char *const extension)
112 langType result = LANG_IGNORE;
113 unsigned int i;
114 for (i = 0 ; i < LanguageCount && result == LANG_IGNORE ; ++i)
116 stringList* const exts = LanguageTable [i]->currentExtensions;
117 if (exts != NULL && stringListExtensionMatched (exts, extension))
118 result = i;
120 return result;
123 static langType getPatternLanguage (const char *const fileName)
125 langType result = LANG_IGNORE;
126 const char* base = baseFilename (fileName);
127 unsigned int i;
128 for (i = 0 ; i < LanguageCount && result == LANG_IGNORE ; ++i)
130 stringList* const ptrns = LanguageTable [i]->currentPatterns;
131 if (ptrns != NULL && stringListFileMatched (ptrns, base))
132 result = i;
134 return result;
137 #ifdef SYS_INTERPRETER
139 /* The name of the language interpreter, either directly or as the argument
140 * to "env".
142 static vString* determineInterpreter (const char* const cmd)
144 vString* const interpreter = vStringNew ();
145 const char* p = cmd;
148 vStringClear (interpreter);
149 for ( ; isspace (*p) ; ++p)
150 ; /* no-op */
151 for ( ; *p != '\0' && ! isspace (*p) ; ++p)
152 vStringPut (interpreter, (int) *p);
153 vStringTerminate (interpreter);
154 } while (strcmp (vStringValue (interpreter), "env") == 0);
155 return interpreter;
158 static langType getInterpreterLanguage (const char *const fileName)
160 langType result = LANG_IGNORE;
161 FILE* const fp = g_fopen (fileName, "r");
162 if (fp != NULL)
164 vString* const vLine = vStringNew ();
165 const char* const line = readLine (vLine, fp);
166 if (line != NULL && line [0] == '#' && line [1] == '!')
168 const char* const lastSlash = strrchr (line, '/');
169 const char *const cmd = lastSlash != NULL ? lastSlash+1 : line+2;
170 vString* const interpreter = determineInterpreter (cmd);
171 result = getExtensionLanguage (vStringValue (interpreter));
172 vStringDelete (interpreter);
174 vStringDelete (vLine);
175 fclose (fp);
177 return result;
180 #endif
182 extern langType getFileLanguage (const char *const fileName)
184 langType language = Option.language;
185 if (language == LANG_AUTO)
187 language = getExtensionLanguage (fileExtension (fileName));
188 if (language == LANG_IGNORE)
189 language = getPatternLanguage (fileName);
190 #ifdef SYS_INTERPRETER
191 if (language == LANG_IGNORE && isExecutable (fileName))
192 language = getInterpreterLanguage (fileName);
193 #endif
195 return language;
198 extern void printLanguageMap (const langType language)
200 boolean first = TRUE;
201 unsigned int i;
202 stringList* map = LanguageTable [language]->currentPatterns;
203 Assert (0 <= language && language < (int) LanguageCount);
204 for (i = 0 ; map != NULL && i < stringListCount (map) ; ++i)
206 printf ("%s(%s)", (first ? "" : " "),
207 vStringValue (stringListItem (map, i)));
208 first = FALSE;
210 map = LanguageTable [language]->currentExtensions;
211 for (i = 0 ; map != NULL && i < stringListCount (map) ; ++i)
213 printf ("%s.%s", (first ? "" : " "),
214 vStringValue (stringListItem (map, i)));
215 first = FALSE;
219 extern void installLanguageMapDefault (const langType language)
221 Assert (language >= 0);
222 if (LanguageTable [language]->currentPatterns != NULL)
223 stringListDelete (LanguageTable [language]->currentPatterns);
224 if (LanguageTable [language]->currentExtensions != NULL)
225 stringListDelete (LanguageTable [language]->currentExtensions);
227 if (LanguageTable [language]->patterns == NULL)
228 LanguageTable [language]->currentPatterns = stringListNew ();
229 else
231 LanguageTable [language]->currentPatterns =
232 stringListNewFromArgv (LanguageTable [language]->patterns);
234 if (LanguageTable [language]->extensions == NULL)
235 LanguageTable [language]->currentExtensions = stringListNew ();
236 else
238 LanguageTable [language]->currentExtensions =
239 stringListNewFromArgv (LanguageTable [language]->extensions);
243 extern void installLanguageMapDefaults (void)
245 unsigned int i;
246 for (i = 0 ; i < LanguageCount ; ++i)
248 installLanguageMapDefault (i);
252 extern void clearLanguageMap (const langType language)
254 Assert (0 <= language && language < (int) LanguageCount);
255 stringListClear (LanguageTable [language]->currentPatterns);
256 stringListClear (LanguageTable [language]->currentExtensions);
259 extern void addLanguagePatternMap (const langType language, const char* ptrn)
261 vString* const str = vStringNewInit (ptrn);
262 Assert (0 <= language && language < (int) LanguageCount);
263 if (LanguageTable [language]->currentPatterns == NULL)
264 LanguageTable [language]->currentPatterns = stringListNew ();
265 stringListAdd (LanguageTable [language]->currentPatterns, str);
268 extern void addLanguageExtensionMap (const langType language,
269 const char* extension)
271 vString* const str = vStringNewInit (extension);
272 Assert (0 <= language && language < (int) LanguageCount);
273 stringListAdd (LanguageTable [language]->currentExtensions, str);
276 extern void enableLanguages (const boolean state)
278 unsigned int i;
279 for (i = 0 ; i < LanguageCount ; ++i)
280 LanguageTable [i]->enabled = state;
283 extern void enableLanguage (const langType language, const boolean state)
285 Assert (0 <= language && language < (int) LanguageCount);
286 LanguageTable [language]->enabled = state;
289 static void initializeParsers (void)
291 unsigned int i;
292 for (i = 0 ; i < LanguageCount ; ++i)
293 if (LanguageTable [i]->initialize != NULL)
294 (LanguageTable [i]->initialize) ((langType) i);
297 extern void initializeParsing (void)
299 unsigned int builtInCount;
300 unsigned int i;
302 builtInCount = sizeof (BuiltInParsers) / sizeof (BuiltInParsers [0]);
303 LanguageTable = xMalloc (builtInCount, parserDefinition*);
305 for (i = 0 ; i < builtInCount ; ++i)
307 parserDefinition* const def = (*BuiltInParsers [i]) ();
308 if (def != NULL)
310 boolean accepted = FALSE;
311 if (def->name == NULL || def->name[0] == '\0')
312 error (FATAL, "parser definition must contain name\n");
313 else if (def->regex)
315 #ifdef HAVE_REGEX
316 def->parser = findRegexTags;
317 accepted = TRUE;
318 #endif
320 else if ((def->parser == NULL) == (def->parser2 == NULL))
321 error (FATAL,
322 "%s parser definition must define one and only one parsing routine\n",
323 def->name);
324 else
325 accepted = TRUE;
326 if (accepted)
328 def->id = LanguageCount++;
329 LanguageTable [def->id] = def;
333 enableLanguages (TRUE);
334 initializeParsers ();
337 extern void freeParserResources (void)
339 unsigned int i;
340 for (i = 0 ; i < LanguageCount ; ++i)
342 freeList (&LanguageTable [i]->currentPatterns);
343 freeList (&LanguageTable [i]->currentExtensions);
344 eFree (LanguageTable [i]->name);
345 LanguageTable [i]->name = NULL;
346 eFree (LanguageTable [i]);
348 eFree (LanguageTable);
349 LanguageTable = NULL;
350 LanguageCount = 0;
354 * Option parsing
357 extern void processLanguageDefineOption (const char *const option,
358 const char *const UNUSED parameter)
360 #ifdef HAVE_REGEX
361 if (parameter [0] == '\0')
362 error (WARNING, "No language specified for \"%s\" option", option);
363 else if (getNamedLanguage (parameter) != LANG_IGNORE)
364 error (WARNING, "Language \"%s\" already defined", parameter);
365 else
367 unsigned int i = LanguageCount++;
368 parserDefinition* const def = parserNew (parameter);
369 def->parser = findRegexTags;
370 def->currentPatterns = stringListNew ();
371 def->currentExtensions = stringListNew ();
372 def->regex = TRUE;
373 def->enabled = TRUE;
374 def->id = i;
375 LanguageTable = xRealloc (LanguageTable, i + 1, parserDefinition*);
376 LanguageTable [i] = def;
378 #else
379 error (WARNING, "regex support not available; required for --%s option",
380 option);
381 #endif
384 static kindOption *langKindOption (const langType language, const int flag)
386 unsigned int i;
387 kindOption* result = NULL;
388 const parserDefinition* lang;
389 Assert (0 <= language && language < (int) LanguageCount);
390 lang = LanguageTable [language];
391 for (i=0 ; i < lang->kindCount && result == NULL ; ++i)
392 if (lang->kinds [i].letter == flag)
393 result = &lang->kinds [i];
394 return result;
397 extern void processLegacyKindOption (const char *const parameter)
399 const langType lang = getNamedLanguage ("c");
400 boolean clear = FALSE;
401 const char* p = parameter;
402 boolean mode = TRUE;
403 int c;
405 error (WARNING, "-i option is deprecated; use --c-types option instead");
406 if (*p == '=')
408 clear = TRUE;
409 ++p;
411 if (clear && *p != '+' && *p != '-')
413 unsigned int i;
414 for (i = 0 ; i < LanguageTable [lang]->kindCount ; ++i)
415 LanguageTable [lang]->kinds [i].enabled = FALSE;
416 Option.include.fileNames= FALSE;
417 Option.include.fileScope= FALSE;
419 while ((c = *p++) != '\0') switch (c)
421 case '+': mode = TRUE; break;
422 case '-': mode = FALSE; break;
424 case 'F': Option.include.fileNames = mode; break;
425 case 'S': Option.include.fileScope = mode; break;
427 default:
429 kindOption* const opt = langKindOption (lang, c);
430 if (opt != NULL)
431 opt->enabled = mode;
432 else
433 error (WARNING, "Unsupported parameter '%c' for -i option", c);
434 } break;
438 static void disableLanguageKinds (const langType language)
440 if (LanguageTable [language]->regex)
441 #ifdef HAVE_REGEX
442 disableRegexKinds (language);
443 #else
445 #endif
446 else
448 unsigned int i;
449 for (i = 0 ; i < LanguageTable [language]->kindCount ; ++i)
450 LanguageTable [language]->kinds [i].enabled = FALSE;
454 static boolean enableLanguageKind (const langType language,
455 const int kind, const boolean mode)
457 boolean result = FALSE;
458 if (LanguageTable [language]->regex)
459 #ifdef HAVE_REGEX
460 result = enableRegexKind (language, kind, mode);
461 #else
463 #endif
464 else
466 kindOption* const opt = langKindOption (language, kind);
467 if (opt != NULL)
469 opt->enabled = mode;
470 result = TRUE;
473 return result;
476 static void processLangKindOption (const langType language,
477 const char *const option,
478 const char *const parameter)
480 const char *p = parameter;
481 boolean mode = TRUE;
482 int c;
484 Assert (0 <= language && language < (int) LanguageCount);
485 if (*p != '+' && *p != '-')
486 disableLanguageKinds (language);
487 while ((c = *p++) != '\0') switch (c)
489 case '+': mode = TRUE; break;
490 case '-': mode = FALSE; break;
492 default:
494 if (! enableLanguageKind (language, c, mode))
495 error (WARNING, "Unsupported parameter '%c' for --%s option",
496 c, option);
497 } break;
501 extern boolean processKindOption (const char *const option,
502 const char *const parameter)
504 boolean handled = FALSE;
505 const char* const dash = strchr (option, '-');
506 if (dash != NULL &&
507 (strcmp (dash + 1, "types") == 0 || strcmp (dash + 1, "kinds") == 0))
509 langType language;
510 vString* langName = vStringNew ();
511 vStringNCopyS (langName, option, dash - option);
512 language = getNamedLanguage (vStringValue (langName));
513 if (language == LANG_IGNORE)
514 error (WARNING, "Unknown language specified in \"%s\" option", option);
515 else
516 processLangKindOption (language, option, parameter);
517 vStringDelete (langName);
518 handled = TRUE;
520 return handled;
523 static void printLangugageKindOption (const kindOption* const kind)
525 printf (" %c %s%s\n", kind->letter,
526 kind->description != NULL ? kind->description :
527 (kind->name != NULL ? kind->name : ""),
528 kind->enabled ? "" : " [off]");
531 static void printLangugageKindOptions (const langType language)
533 const parserDefinition* lang;
534 Assert (0 <= language && language < (int) LanguageCount);
535 lang = LanguageTable [language];
536 if (lang->kinds != NULL || lang->regex)
538 unsigned int i;
539 char* const name = newLowerString (lang->name);
540 printf (" --%s-types=[+|-]kinds\n", name);
541 eFree (name);
542 if (lang->kinds != NULL)
543 for (i = 0 ; i < lang->kindCount ; ++i)
544 printLangugageKindOption (lang->kinds + i);
545 #ifdef HAVE_REGEX
546 /*printRegexKindOptions (language);*/ /* unused */
547 #endif
551 extern void printKindOptions (void)
553 unsigned int i;
555 printf (
556 "\n The following options are used to specify which language-specific tag\n\
557 types (or kinds) should be included in the tag file. \"Kinds\" is a group of\n\
558 one-letter flags designating kinds of tags to either include or exclude from\n\
559 the output. Each letter or group of letters may be preceded by either '+' to\n\
560 add it to those already included, or '-' to exclude it from the output. In\n\
561 the absence of any preceding '+' or '-' sign, only those kinds listed in\n\
562 \"kinds\" will be included in the output. Below each option is a list of the\n\
563 flags accepted. All kinds are enabled by default unless otherwise noted.\n\n");
565 for (i = 0 ; i < LanguageCount ; ++i)
566 printLangugageKindOptions (i);
570 * File parsing
573 static void makeFileTag (const char *const fileName)
575 if (Option.include.fileNames)
577 tagEntryInfo tag;
578 initTagEntry (&tag, baseFilename (fileName));
580 tag.isFileEntry = TRUE;
581 tag.lineNumberEntry = TRUE;
582 tag.lineNumber = 1;
583 tag.kindName = "file";
584 tag.kind = 'F';
586 makeTagEntry (&tag);
590 static boolean createTagsForFile (const char *const fileName,
591 const langType language,
592 const unsigned int passCount)
594 boolean retried = FALSE;
596 if (fileOpen (fileName, language))
599 makeFileTag (fileName);
601 if (LanguageTable [language]->parser != NULL)
602 LanguageTable [language]->parser ();
603 else if (LanguageTable [language]->parser2 != NULL)
604 retried = LanguageTable [language]->parser2 (passCount);
607 fileClose ();
610 return retried;
613 static boolean createTagsWithFallback (const char *const fileName,
614 const langType language)
616 const unsigned long numTags = TagFile.numTags.added;
617 MIOPos tagFilePosition;
618 unsigned int passCount = 0;
619 boolean tagFileResized = FALSE;
621 mio_getpos (TagFile.mio, &tagFilePosition);
622 while (createTagsForFile (fileName, language, ++passCount))
624 /* Restore prior state of tag file.
626 mio_setpos (TagFile.mio, &tagFilePosition);
627 TagFile.numTags.added = numTags;
628 tagFileResized = TRUE;
630 return tagFileResized;
633 extern boolean parseFile (const char *const fileName)
635 boolean tagFileResized = FALSE;
636 langType language = Option.language;
637 if (Option.language == LANG_AUTO)
638 language = getFileLanguage (fileName);
639 Assert (language != LANG_AUTO);
640 if (Option.filter)
641 openTagFile ();
643 tagFileResized = createTagsWithFallback (fileName, language);
645 addTotals (1, 0L, 0L);
647 return tagFileResized;
650 /* vi:set tabstop=8 shiftwidth=4 nowrap: */