2 * $Id: parse.c 597 2007-07-31 05:35:30Z dhiebert $
4 * Copyright (c) 1996-2003, Darren Hiebert
6 * This source code is released for free distribution under the terms of the
7 * GNU General Public License.
9 * This module contains functions for managing source languages and
10 * dispatching files to the appropriate language parser.
16 #include "general.h" /* must always come first */
33 static parserDefinitionFunc
* BuiltInParsers
[] = { PARSER_LIST
};
34 static parserDefinition
** LanguageTable
= NULL
;
35 static unsigned int LanguageCount
= 0;
38 * FUNCTION DEFINITIONS
41 extern void makeSimpleTag (
42 const vString
* const name
, kindOption
* const kinds
, const int kind
)
44 if (kinds
[kind
].enabled
&& name
!= NULL
&& vStringLength (name
) > 0)
47 initTagEntry (&e
, vStringValue (name
));
49 e
.kindName
= kinds
[kind
].name
;
50 e
.kind
= kinds
[kind
].letter
;
57 * parserDescription mapping management
60 extern parserDefinition
* parserNew (const char* name
)
62 parserDefinition
* result
= xCalloc (1, parserDefinition
);
63 result
->name
= eStrdup (name
);
67 extern const char *getLanguageName (const langType language
)
70 if (language
== LANG_IGNORE
)
74 Assert (0 <= language
&& language
< (int) LanguageCount
);
75 result
= LanguageTable
[language
]->name
;
80 extern langType
getNamedLanguage (const char *const name
)
82 langType result
= LANG_IGNORE
;
84 Assert (name
!= NULL
);
85 for (i
= 0 ; i
< LanguageCount
&& result
== LANG_IGNORE
; ++i
)
87 const parserDefinition
* const lang
= LanguageTable
[i
];
88 if (lang
->name
!= NULL
)
89 if (strcasecmp (name
, lang
->name
) == 0)
95 static langType
getExtensionLanguage (const char *const extension
)
97 langType result
= LANG_IGNORE
;
99 for (i
= 0 ; i
< LanguageCount
&& result
== LANG_IGNORE
; ++i
)
101 stringList
* const exts
= LanguageTable
[i
]->currentExtensions
;
102 if (exts
!= NULL
&& stringListExtensionMatched (exts
, extension
))
108 static langType
getPatternLanguage (const char *const fileName
)
110 langType result
= LANG_IGNORE
;
111 const char* base
= baseFilename (fileName
);
113 for (i
= 0 ; i
< LanguageCount
&& result
== LANG_IGNORE
; ++i
)
115 stringList
* const ptrns
= LanguageTable
[i
]->currentPatterns
;
116 if (ptrns
!= NULL
&& stringListFileMatched (ptrns
, base
))
122 #ifdef SYS_INTERPRETER
124 /* The name of the language interpreter, either directly or as the argument
127 static vString
* determineInterpreter (const char* const cmd
)
129 vString
* const interpreter
= vStringNew ();
133 vStringClear (interpreter
);
134 for ( ; isspace ((int) *p
) ; ++p
)
136 for ( ; *p
!= '\0' && ! isspace ((int) *p
) ; ++p
)
137 vStringPut (interpreter
, (int) *p
);
138 vStringTerminate (interpreter
);
139 } while (strcmp (vStringValue (interpreter
), "env") == 0);
143 static langType
getInterpreterLanguage (const char *const fileName
)
145 langType result
= LANG_IGNORE
;
146 FILE* const fp
= fopen (fileName
, "r");
149 vString
* const vLine
= vStringNew ();
150 const char* const line
= readLine (vLine
, fp
);
151 if (line
!= NULL
&& line
[0] == '#' && line
[1] == '!')
153 const char* const lastSlash
= strrchr (line
, '/');
154 const char *const cmd
= lastSlash
!= NULL
? lastSlash
+1 : line
+2;
155 vString
* const interpreter
= determineInterpreter (cmd
);
156 result
= getExtensionLanguage (vStringValue (interpreter
));
157 if (result
== LANG_IGNORE
)
158 result
= getNamedLanguage (vStringValue (interpreter
));
159 vStringDelete (interpreter
);
161 vStringDelete (vLine
);
169 extern langType
getFileLanguage (const char *const fileName
)
171 langType language
= Option
.language
;
172 if (language
== LANG_AUTO
)
174 language
= getExtensionLanguage (fileExtension (fileName
));
175 if (language
== LANG_IGNORE
)
176 language
= getPatternLanguage (fileName
);
177 #ifdef SYS_INTERPRETER
178 if (language
== LANG_IGNORE
)
180 fileStatus
*status
= eStat (fileName
);
181 if (status
->isExecutable
)
182 language
= getInterpreterLanguage (fileName
);
189 extern void printLanguageMap (const langType language
)
191 boolean first
= TRUE
;
193 stringList
* map
= LanguageTable
[language
]->currentPatterns
;
194 Assert (0 <= language
&& language
< (int) LanguageCount
);
195 for (i
= 0 ; map
!= NULL
&& i
< stringListCount (map
) ; ++i
)
197 printf ("%s(%s)", (first
? "" : " "),
198 vStringValue (stringListItem (map
, i
)));
201 map
= LanguageTable
[language
]->currentExtensions
;
202 for (i
= 0 ; map
!= NULL
&& i
< stringListCount (map
) ; ++i
)
204 printf ("%s.%s", (first
? "" : " "),
205 vStringValue (stringListItem (map
, i
)));
210 extern void installLanguageMapDefault (const langType language
)
212 parserDefinition
* lang
;
213 Assert (0 <= language
&& language
< (int) LanguageCount
);
214 lang
= LanguageTable
[language
];
215 if (lang
->currentPatterns
!= NULL
)
216 stringListDelete (lang
->currentPatterns
);
217 if (lang
->currentExtensions
!= NULL
)
218 stringListDelete (lang
->currentExtensions
);
220 if (lang
->patterns
== NULL
)
221 lang
->currentPatterns
= stringListNew ();
224 lang
->currentPatterns
=
225 stringListNewFromArgv (lang
->patterns
);
227 if (lang
->extensions
== NULL
)
228 lang
->currentExtensions
= stringListNew ();
231 lang
->currentExtensions
=
232 stringListNewFromArgv (lang
->extensions
);
235 printLanguageMap (language
);
239 extern void installLanguageMapDefaults (void)
242 for (i
= 0 ; i
< LanguageCount
; ++i
)
244 verbose (" %s: ", getLanguageName (i
));
245 installLanguageMapDefault (i
);
249 extern void clearLanguageMap (const langType language
)
251 Assert (0 <= language
&& language
< (int) LanguageCount
);
252 stringListClear (LanguageTable
[language
]->currentPatterns
);
253 stringListClear (LanguageTable
[language
]->currentExtensions
);
256 extern void addLanguagePatternMap (const langType language
, const char* ptrn
)
258 vString
* const str
= vStringNewInit (ptrn
);
259 parserDefinition
* lang
;
260 Assert (0 <= language
&& language
< (int) LanguageCount
);
261 lang
= LanguageTable
[language
];
262 if (lang
->currentPatterns
== NULL
)
263 lang
->currentPatterns
= stringListNew ();
264 stringListAdd (lang
->currentPatterns
, str
);
267 extern boolean
removeLanguageExtensionMap (const char *const extension
)
269 boolean result
= FALSE
;
271 for (i
= 0 ; i
< LanguageCount
&& ! result
; ++i
)
273 stringList
* const exts
= LanguageTable
[i
]->currentExtensions
;
274 if (exts
!= NULL
&& stringListRemoveExtension (exts
, extension
))
276 verbose (" (removed from %s)", getLanguageName (i
));
283 extern void addLanguageExtensionMap (
284 const langType language
, const char* extension
)
286 vString
* const str
= vStringNewInit (extension
);
287 Assert (0 <= language
&& language
< (int) LanguageCount
);
288 removeLanguageExtensionMap (extension
);
289 stringListAdd (LanguageTable
[language
]->currentExtensions
, str
);
292 extern void enableLanguage (const langType language
, const boolean state
)
294 Assert (0 <= language
&& language
< (int) LanguageCount
);
295 LanguageTable
[language
]->enabled
= state
;
298 extern void enableLanguages (const boolean state
)
301 for (i
= 0 ; i
< LanguageCount
; ++i
)
302 enableLanguage (i
, state
);
305 static void initializeParsers (void)
308 for (i
= 0 ; i
< LanguageCount
; ++i
)
309 if (LanguageTable
[i
]->initialize
!= NULL
)
310 (LanguageTable
[i
]->initialize
) ((langType
) i
);
313 extern void initializeParsing (void)
315 unsigned int builtInCount
;
318 builtInCount
= sizeof (BuiltInParsers
) / sizeof (BuiltInParsers
[0]);
319 LanguageTable
= xMalloc (builtInCount
, parserDefinition
*);
321 verbose ("Installing parsers: ");
322 for (i
= 0 ; i
< builtInCount
; ++i
)
324 parserDefinition
* const def
= (*BuiltInParsers
[i
]) ();
327 boolean accepted
= FALSE
;
328 if (def
->name
== NULL
|| def
->name
[0] == '\0')
329 error (FATAL
, "parser definition must contain name\n");
333 def
->parser
= findRegexTags
;
337 else if ((def
->parser
== NULL
) == (def
->parser2
== NULL
))
339 "%s parser definition must define one and only one parsing routine\n",
345 verbose ("%s%s", i
> 0 ? ", " : "", def
->name
);
346 def
->id
= LanguageCount
++;
347 LanguageTable
[def
->id
] = def
;
352 enableLanguages (TRUE
);
353 initializeParsers ();
356 extern void freeParserResources (void)
359 for (i
= 0 ; i
< LanguageCount
; ++i
)
361 parserDefinition
* const lang
= LanguageTable
[i
];
362 freeList (&lang
->currentPatterns
);
363 freeList (&lang
->currentExtensions
);
368 if (LanguageTable
!= NULL
)
369 eFree (LanguageTable
);
370 LanguageTable
= NULL
;
378 extern void processLanguageDefineOption (
379 const char *const option
, const char *const parameter __unused__
)
382 if (parameter
[0] == '\0')
383 error (WARNING
, "No language specified for \"%s\" option", option
);
384 else if (getNamedLanguage (parameter
) != LANG_IGNORE
)
385 error (WARNING
, "Language \"%s\" already defined", parameter
);
388 unsigned int i
= LanguageCount
++;
389 parserDefinition
* const def
= parserNew (parameter
);
390 def
->parser
= findRegexTags
;
391 def
->currentPatterns
= stringListNew ();
392 def
->currentExtensions
= stringListNew ();
396 LanguageTable
= xRealloc (LanguageTable
, i
+ 1, parserDefinition
*);
397 LanguageTable
[i
] = def
;
400 error (WARNING
, "regex support not available; required for --%s option",
405 static kindOption
*langKindOption (const langType language
, const int flag
)
408 kindOption
* result
= NULL
;
409 const parserDefinition
* lang
;
410 Assert (0 <= language
&& language
< (int) LanguageCount
);
411 lang
= LanguageTable
[language
];
412 for (i
=0 ; i
< lang
->kindCount
&& result
== NULL
; ++i
)
413 if (lang
->kinds
[i
].letter
== flag
)
414 result
= &lang
->kinds
[i
];
418 static void disableLanguageKinds (const langType language
)
420 const parserDefinition
* lang
;
421 Assert (0 <= language
&& language
< (int) LanguageCount
);
422 lang
= LanguageTable
[language
];
424 disableRegexKinds (language
);
428 for (i
= 0 ; i
< lang
->kindCount
; ++i
)
429 lang
->kinds
[i
].enabled
= FALSE
;
433 static boolean
enableLanguageKind (
434 const langType language
, const int kind
, const boolean mode
)
436 boolean result
= FALSE
;
437 if (LanguageTable
[language
]->regex
)
438 result
= enableRegexKind (language
, kind
, mode
);
441 kindOption
* const opt
= langKindOption (language
, kind
);
451 static void processLangKindOption (
452 const langType language
, const char *const option
,
453 const char *const parameter
)
455 const char *p
= parameter
;
459 Assert (0 <= language
&& language
< (int) LanguageCount
);
460 if (*p
!= '+' && *p
!= '-')
461 disableLanguageKinds (language
);
462 while ((c
= *p
++) != '\0') switch (c
)
464 case '+': mode
= TRUE
; break;
465 case '-': mode
= FALSE
; break;
467 if (! enableLanguageKind (language
, c
, mode
))
468 error (WARNING
, "Unsupported parameter '%c' for --%s option",
474 extern boolean
processKindOption (
475 const char *const option
, const char *const parameter
)
477 boolean handled
= FALSE
;
478 const char* const dash
= strchr (option
, '-');
480 (strcmp (dash
+ 1, "kinds") == 0 || strcmp (dash
+ 1, "types") == 0))
483 vString
* langName
= vStringNew ();
484 vStringNCopyS (langName
, option
, dash
- option
);
485 language
= getNamedLanguage (vStringValue (langName
));
486 if (language
== LANG_IGNORE
)
487 error (WARNING
, "Unknown language \"%s\" in \"%s\" option", vStringValue (langName
), option
);
489 processLangKindOption (language
, option
, parameter
);
490 vStringDelete (langName
);
496 static void printLanguageKind (const kindOption
* const kind
, boolean indent
)
498 const char *const indentation
= indent
? " " : "";
499 printf ("%s%c %s%s\n", indentation
, kind
->letter
,
500 kind
->description
!= NULL
? kind
->description
:
501 (kind
->name
!= NULL
? kind
->name
: ""),
502 kind
->enabled
? "" : " [off]");
505 static void printKinds (langType language
, boolean indent
)
507 const parserDefinition
* lang
;
508 Assert (0 <= language
&& language
< (int) LanguageCount
);
509 lang
= LanguageTable
[language
];
510 if (lang
->kinds
!= NULL
|| lang
->regex
)
513 for (i
= 0 ; i
< lang
->kindCount
; ++i
)
514 printLanguageKind (lang
->kinds
+ i
, indent
);
515 printRegexKinds (language
, indent
);
519 extern void printLanguageKinds (const langType language
)
521 if (language
== LANG_AUTO
)
524 for (i
= 0 ; i
< LanguageCount
; ++i
)
526 const parserDefinition
* const lang
= LanguageTable
[i
];
527 printf ("%s%s\n", lang
->name
, lang
->enabled
? "" : " [disabled]");
528 printKinds (i
, TRUE
);
532 printKinds (language
, FALSE
);
535 static void printMaps (const langType language
)
537 const parserDefinition
* lang
;
539 Assert (0 <= language
&& language
< (int) LanguageCount
);
540 lang
= LanguageTable
[language
];
541 printf ("%-8s", lang
->name
);
542 if (lang
->currentExtensions
!= NULL
)
543 for (i
= 0 ; i
< stringListCount (lang
->currentExtensions
) ; ++i
)
544 printf (" *.%s", vStringValue (
545 stringListItem (lang
->currentExtensions
, i
)));
546 if (lang
->currentPatterns
!= NULL
)
547 for (i
= 0 ; i
< stringListCount (lang
->currentPatterns
) ; ++i
)
548 printf (" %s", vStringValue (
549 stringListItem (lang
->currentPatterns
, i
)));
553 extern void printLanguageMaps (const langType language
)
555 if (language
== LANG_AUTO
)
558 for (i
= 0 ; i
< LanguageCount
; ++i
)
562 printMaps (language
);
565 static void printLanguage (const langType language
)
567 const parserDefinition
* lang
;
568 Assert (0 <= language
&& language
< (int) LanguageCount
);
569 lang
= LanguageTable
[language
];
570 if (lang
->kinds
!= NULL
|| lang
->regex
)
571 printf ("%s%s\n", lang
->name
, lang
->enabled
? "" : " [disabled]");
574 extern void printLanguageList (void)
577 for (i
= 0 ; i
< LanguageCount
; ++i
)
585 static void makeFileTag (const char *const fileName
)
587 if (Option
.include
.fileNames
)
590 initTagEntry (&tag
, baseFilename (fileName
));
592 tag
.isFileEntry
= TRUE
;
593 tag
.lineNumberEntry
= TRUE
;
595 tag
.kindName
= "file";
602 static boolean
createTagsForFile (
603 const char *const fileName
, const langType language
,
604 const unsigned int passCount
)
606 boolean retried
= FALSE
;
607 Assert (0 <= language
&& language
< (int) LanguageCount
);
608 if (fileOpen (fileName
, language
))
610 const parserDefinition
* const lang
= LanguageTable
[language
];
614 makeFileTag (fileName
);
616 if (lang
->parser
!= NULL
)
618 else if (lang
->parser2
!= NULL
)
619 retried
= lang
->parser2 (passCount
);
622 endEtagsFile (getSourceFileTagPath ());
630 static boolean
createTagsWithFallback (
631 const char *const fileName
, const langType language
)
633 const unsigned long numTags
= TagFile
.numTags
.added
;
634 fpos_t tagFilePosition
;
635 unsigned int passCount
= 0;
636 boolean tagFileResized
= FALSE
;
638 fgetpos (TagFile
.fp
, &tagFilePosition
);
639 while (createTagsForFile (fileName
, language
, ++passCount
))
641 /* Restore prior state of tag file.
643 fsetpos (TagFile
.fp
, &tagFilePosition
);
644 TagFile
.numTags
.added
= numTags
;
645 tagFileResized
= TRUE
;
647 return tagFileResized
;
650 extern boolean
parseFile (const char *const fileName
)
652 boolean tagFileResized
= FALSE
;
653 langType language
= Option
.language
;
654 if (Option
.language
== LANG_AUTO
)
655 language
= getFileLanguage (fileName
);
656 Assert (language
!= LANG_AUTO
);
657 if (language
== LANG_IGNORE
)
658 verbose ("ignoring %s (unknown language)\n", fileName
);
659 else if (! LanguageTable
[language
]->enabled
)
660 verbose ("ignoring %s (language disabled)\n", fileName
);
666 tagFileResized
= createTagsWithFallback (fileName
, language
);
669 closeTagFile (tagFileResized
);
670 addTotals (1, 0L, 0L);
672 return tagFileResized
;
674 return tagFileResized
;
677 /* vi:set tabstop=4 shiftwidth=4 nowrap: */