ctags icon indicating copy to clipboard operation
ctags copied to clipboard

main: ctags option processing fails if "Language already defined", including ctags --help

Open berndf opened this issue 5 years ago • 8 comments

Hello,

recently gentoo updated to ctags-20210321.0. Since this version added the BibTeX parser but I had the file ~/.ctags.d/BibTeX.ctags I got the message 'ctags: Language "BibTeX" already defined'. So far so good - but 'ctags --help' or 'ctags --list-languages' only outputs the message above and apparently bails out of option processing. I think that at least such info requests should continue to work.

$ ctags --version
ctags: Language "BibTeX" already defined

After removing ~/.ctags.d/BibTeX.ctags:
$ ctags --version
Universal Ctags 5.9.0, Copyright (C) 2015 Universal Ctags Team
Universal Ctags is derived from Exuberant Ctags.
Exuberant Ctags 5.8, Copyright (C) 1996-2009 Darren Hiebert
Compiled: Mar 30 2021, 09:48:49
URL: https://ctags.io/
Optional compiled features: +wildcards, +regex, +iconv, +option-directory, +xpath, +sandbox, +packcc

How do you get ctags binary:

via gentoo portage

berndf avatar Mar 30 '21 08:03 berndf

I agree with you. Thank you for the sugestion. I will try to fix. However, I cannot find a simple way to implement the behavior now.

masatake avatar Mar 30 '21 15:03 masatake

Maybe I have to rewrite the initialization code.

masatake avatar Mar 30 '21 15:03 masatake

@masatake san,

Maybe I have to rewrite the initialization code.

main.c

    579         initOptions ();
    580         readOptionConfiguration ();         // ~/.ctags.d/BibTeX.ctags is read and causes the error
    581         verbose ("Reading initial options from command line\n");
    582         parseCmdlineOptions (args);         // --version is processed

How about deferring errors in readOptionConfiguration () after parseCmdlineOptions (args) by using setErrorPrinter()?

Something like;

    579         initOptions ();
    xxx         setErrorPrinter (deferredErrorPrinter, NULL);	// register a new ErrorPrinter
    580         readOptionConfiguration ();	// ~/.ctags.d/BibTeX.ctags is read and causes the error
    581         verbose ("Reading initial options from command line\n");
    582         parseCmdlineOptions (args);	// --version is processed
    xxx         if (haveDeferredError()) exit (1);	// check errors defered
    xxx         setErrorPrinter (stderrDefaultErrorPrinter, NULL);	// revert the default ErrorPrinter

hirooih avatar Apr 25 '21 15:04 hirooih

Or how about this?

--- a/main/parse.c
+++ b/main/parse.c
@@ -2173,8 +2173,8 @@ extern void processLanguageDefineOption (
        }
        else if (getNamedLanguage (name, 0) != LANG_IGNORE)
        {
-           /* name cannot be freed because it is used in the FATAL message. */
-           error (FATAL, "Language \"%s\" already defined", name);
+         error (WARNING, "Language \"%s\" already defined. Ignored.", name);
+         eFree (name);
        }
        else if (strcmp(name, RSV_LANG_ALL) == 0)
        {

hirooih avatar Apr 25 '21 15:04 hirooih

The former one is not acceptable. Users expect they can override the configuration given in .ctags.d from options specified in the command line like make command.

The direction of the latter one is good. I got inspiration from the latter one. The latter one is not perfect.

.ctags.d/foo.ctags

--langdef=C
--regex-C=....
...

With the latter one, ctags warns when reading --langdef=C. However, ctags doesn't stop and ctags can parse an input file after reading --regex-C=..... The tags output may be an unwanted one.

As you show in the latter one, ctags should not stop when reading --langdef=C but it should stop before parsing.

+ struct delayedFatalError {
+     const char *msg;
+ };
+
+ static stringList * delayed_fatal_errors = stringListNew();
+ static void flush_delayed_fatal_errors (void)
+ {
+       for_each_msg (delayed_fatal_errors) {
+           fputs(msg, stderr);
+      exit (1);
+ }

...
        else if (getNamedLanguage (name, 0) != LANG_IGNORE)
        {
-           /* name cannot be freed because it is used in the FATAL message. */
-           error (FATAL, "Language \"%s\" already defined", name);
+         enqueue_delayed_fatal_error ( "Language \"%s\" already defined", name);
+         eFree (name);
        }
...
 extern void checkOptions (void)
 {
...
  +flush_delayed_fatal_errors ();
...
  }

masatake avatar Apr 25 '21 22:04 masatake

~I implemented my idea in #2987. What I got is many coredumps.~ I took a mistake.

masatake avatar May 01 '21 03:05 masatake

The fix I proposed in #2987 causes crashes on Windows.

masatake avatar May 04 '21 18:05 masatake

I found another solution to this. Instead of accepting --langdef-<LANG> option for an already defined language, we handle --version and --help in an earlier stage like:

diff --git a/main/options.c b/main/options.c
index ac87072cd..52f1133c6 100644
--- a/main/options.c
+++ b/main/options.c
@@ -3549,7 +3549,10 @@ extern void previewFirstOption (cookedArgs* const args)
 	{
 		if (strcmp (args->item, "V") == 0
 		    || strcmp (args->item, "verbose") == 0
-		    || strcmp (args->item, "quiet") == 0)
+		    || strcmp (args->item, "quiet") == 0
+			|| (strcmp (args->item, "version") == 0 &&
+				(strcmp (args->parameter, RSV_NONE) == 0
+				 ||  (*args->parameter == '\0'))))
 			parseOption (args);
 		else if (strcmp (args->item, "options") == 0  &&
 				strcmp (args->parameter, RSV_NONE) == 0)

masatake avatar May 30 '23 19:05 masatake