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.
15
#include "general.h" /* must always come first */
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)
48
initTagEntry (&e, vStringValue (name));
50
e.kindName = kinds [kind].name;
51
e.kind = kinds [kind].letter;
58
extern void makeSimpleScopedTag (const vString* const name,
59
kindOption* const kinds, const int kind,
60
const char* scope, const char *scope2,
63
if (name != NULL && vStringLength (name) > 0)
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;
79
* parserDescription mapping management
82
extern parserDefinition* parserNew (const char* name)
84
parserDefinition* result = xCalloc (1, parserDefinition);
85
result->name = eStrdup (name);
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;
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)
110
static langType getExtensionLanguage (const char *const extension)
112
langType result = LANG_IGNORE;
114
for (i = 0 ; i < LanguageCount && result == LANG_IGNORE ; ++i)
116
stringList* const exts = LanguageTable [i]->currentExtensions;
117
if (exts != NULL && stringListExtensionMatched (exts, extension))
123
static langType getPatternLanguage (const char *const fileName)
125
langType result = LANG_IGNORE;
126
const char* base = baseFilename (fileName);
128
for (i = 0 ; i < LanguageCount && result == LANG_IGNORE ; ++i)
130
stringList* const ptrns = LanguageTable [i]->currentPatterns;
131
if (ptrns != NULL && stringListFileMatched (ptrns, base))
137
#ifdef SYS_INTERPRETER
139
/* The name of the language interpreter, either directly or as the argument
142
static vString* determineInterpreter (const char* const cmd)
144
vString* const interpreter = vStringNew ();
148
vStringClear (interpreter);
149
for ( ; isspace (*p) ; ++p)
151
for ( ; *p != '\0' && ! isspace (*p) ; ++p)
152
vStringPut (interpreter, (int) *p);
153
vStringTerminate (interpreter);
154
} while (strcmp (vStringValue (interpreter), "env") == 0);
158
static langType getInterpreterLanguage (const char *const fileName)
160
langType result = LANG_IGNORE;
161
FILE* const fp = g_fopen (fileName, "r");
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);
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);
198
extern void printLanguageMap (const langType language)
200
boolean first = TRUE;
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)));
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)));
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 ();
231
LanguageTable [language]->currentPatterns =
232
stringListNewFromArgv (LanguageTable [language]->patterns);
234
if (LanguageTable [language]->extensions == NULL)
235
LanguageTable [language]->currentExtensions = stringListNew ();
238
LanguageTable [language]->currentExtensions =
239
stringListNewFromArgv (LanguageTable [language]->extensions);
243
extern void installLanguageMapDefaults (void)
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)
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)
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;
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]) ();
310
boolean accepted = FALSE;
311
if (def->name == NULL || def->name[0] == '\0')
312
error (FATAL, "parser definition must contain name\n");
316
def->parser = findRegexTags;
320
else if ((def->parser == NULL) == (def->parser2 == NULL))
322
"%s parser definition must define one and only one parsing routine\n",
328
def->id = LanguageCount++;
329
LanguageTable [def->id] = def;
333
enableLanguages (TRUE);
334
initializeParsers ();
337
extern void freeParserResources (void)
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;
357
extern void processLanguageDefineOption (const char *const option,
358
const char *const __unused__ parameter)
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);
367
unsigned int i = LanguageCount++;
368
parserDefinition* const def = parserNew (parameter);
369
def->parser = findRegexTags;
370
def->currentPatterns = stringListNew ();
371
def->currentExtensions = stringListNew ();
375
LanguageTable = xRealloc (LanguageTable, i + 1, parserDefinition*);
376
LanguageTable [i] = def;
379
error (WARNING, "regex support not available; required for --%s option",
384
static kindOption *langKindOption (const langType language, const int flag)
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];
397
extern void processLegacyKindOption (const char *const parameter)
399
const langType lang = getNamedLanguage ("c");
400
boolean clear = FALSE;
401
const char* p = parameter;
405
error (WARNING, "-i option is deprecated; use --c-types option instead");
411
if (clear && *p != '+' && *p != '-')
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;
429
kindOption* const opt = langKindOption (lang, c);
433
error (WARNING, "Unsupported parameter '%c' for -i option", c);
438
static void disableLanguageKinds (const langType language)
440
if (LanguageTable [language]->regex)
442
disableRegexKinds (language);
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)
460
result = enableRegexKind (language, kind, mode);
466
kindOption* const opt = langKindOption (language, kind);
476
static void processLangKindOption (const langType language,
477
const char *const option,
478
const char *const parameter)
480
const char *p = parameter;
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;
494
if (! enableLanguageKind (language, c, mode))
495
error (WARNING, "Unsupported parameter '%c' for --%s option",
501
extern boolean processKindOption (const char *const option,
502
const char *const parameter)
504
boolean handled = FALSE;
505
const char* const dash = strchr (option, '-');
507
(strcmp (dash + 1, "types") == 0 || strcmp (dash + 1, "kinds") == 0))
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);
516
processLangKindOption (language, option, parameter);
517
vStringDelete (langName);
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)
539
char* const name = newLowerString (lang->name);
540
printf (" --%s-types=[+|-]kinds\n", name);
542
if (lang->kinds != NULL)
543
for (i = 0 ; i < lang->kindCount ; ++i)
544
printLangugageKindOption (lang->kinds + i);
546
/*printRegexKindOptions (language);*/ /* unused */
551
extern void printKindOptions (void)
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);
573
static void makeFileTag (const char *const fileName)
575
if (Option.include.fileNames)
578
initTagEntry (&tag, baseFilename (fileName));
580
tag.isFileEntry = TRUE;
581
tag.lineNumberEntry = TRUE;
583
tag.kindName = "file";
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);
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);
643
tagFileResized = createTagsWithFallback (fileName, language);
645
addTotals (1, 0L, 0L);
647
return tagFileResized;
650
/* vi:set tabstop=8 shiftwidth=4 nowrap: */