diff --git a/link-parser/command-line.c b/link-parser/command-line.c index bb9b76252..dfe332af4 100644 --- a/link-parser/command-line.c +++ b/link-parser/command-line.c @@ -122,15 +122,24 @@ Switch default_switches[] = {NULL, Cmd, NULL, NULL} }; -static void put_opts_in_local_vars(Command_Options *); - /* - * A way to record the options default values. + * Record the parse options default values. + * + * Set the string parse options to their static default value so they + * don't point to a static (test, debug) or dynamic (dialect) memory of + * the library (but anyway we need to do that for the test,debug and + * verbosity parse options because they might have been set by command + * line arguments just before this function is invoked.) */ void save_default_opts(Command_Options *copts) { put_opts_in_local_vars(copts); saved_defaults = local; + // XXX Set defaults assuming stable library settings + saved_defaults.test = (char *)""; + saved_defaults.debug = (char *)""; + saved_defaults.dialect = (char *)""; + saved_defaults.verbosity = 1; } static void restore_default_local_vars(void) @@ -138,8 +147,17 @@ static void restore_default_local_vars(void) local = saved_defaults; } +// Return the value of the static verbosity. +// This avoids the need to define "verbosity" as extern, which may clash +// with the library "verbosity", and make the parse options "verbosity" +// available before the main loop in link-parser.c. +int get_verbosity(void) +{ + return local.verbosity; +} + /** - * Gets rid of all the white space in the string s. + * Gets rid of all the white space in the string s. */ static void clean_up_string(char * s) { @@ -157,7 +175,7 @@ static void clean_up_string(char * s) if (0 == w) break; if (0 > (ssize_t)w) { - prt_error("Unable to process UTF8 command input string.\n"); + prt_error("Error: Unable to process UTF8 command input string.\n"); break; } len -= w; @@ -194,7 +212,7 @@ static bool is_numerical_rhs(char *s) if (0 == w) break; if (0 > (ssize_t)w) { - prt_error("Unable to process UTF8 command input string.\n"); + prt_error("Error: Unable to process UTF8 command input string.\n"); break; } len -= w; @@ -272,7 +290,6 @@ static const char *switch_value_string(const Switch *as) #define HELPFILE_LANG_TEMPLATE_SIZE (sizeof(HELPFILE_LANG_TEMPLATE)-1) #define HELPFILE_TEMPLATE_SIZE \ (sizeof(HELPFILE_BASE HELPFILE_EXT)+HELPFILE_LANG_TEMPLATE_SIZE) -#define D_USER_FILES 4 /* Debug level for files, see error.h. */ #define DEFAULT_HELP_LANG "en" static FILE *help_file; @@ -411,7 +428,7 @@ static FILE *open_help_file(int verbosity) help_file = linkgrammar_open_data_file(help_filename); } - if ((NULL == help_file) && (verbosity > D_USER_FILES)) + if ((NULL == help_file) && (verbosity == D_USER_FILES)) { prt_error("Error: Cannot open help file '%s': %s\n", help_filename, strerror(errno)); @@ -514,7 +531,7 @@ static void display_help(const Switch *sp, Command_Options *copts) if (feof(hf)) { - if (local.verbosity >= D_USER_FILES) + if (local.verbosity == D_USER_FILES) prt_error("Error: Cannot find command \"%s\" in help file\n", sp->string); } @@ -772,9 +789,9 @@ static int handle_help_command(const Switch *as, char *line, { rc = -1; /* Error indication. */ if (count > 1) - prt_error("Ambiguous command: \"%s\". %s\n", s, helpmsg); + prt_error("Error: Ambiguous command: \"%s\". %s\n", s, helpmsg); else - prt_error("Undefined command: \"%s\". %s\n", s, helpmsg); + prt_error("Error: Undefined command: \"%s\". %s\n", s, helpmsg); } } } @@ -851,7 +868,7 @@ static int x_issue_special_command(char * line, Command_Options *copts, Dictiona if (count > 1) { - prt_error("Ambiguous command \"%s\". %s\n", s, helpmsg); + prt_error("Error: Ambiguous command \"%s\". %s\n", s, helpmsg); return -1; } if (count == 1) @@ -862,7 +879,7 @@ static int x_issue_special_command(char * line, Command_Options *copts, Dictiona size_t junk = strcspn(s, WHITESPACE); if (junk != strlen(s)) { - prt_error("Junk after a boolean variable: \"%s\". %s\n", + prt_error("Error: Junk after a boolean variable: \"%s\". %s\n", &s[junk], helpmsg); return -1; } @@ -999,7 +1016,7 @@ static int x_issue_special_command(char * line, Command_Options *copts, Dictiona return -1; } -static void put_opts_in_local_vars(Command_Options* copts) +void put_opts_in_local_vars(Command_Options* copts) { Parse_Options opts = copts->popts; local.verbosity = parse_options_get_verbosity(opts); diff --git a/link-parser/command-line.h b/link-parser/command-line.h index 6badb0df8..f98076dde 100644 --- a/link-parser/command-line.h +++ b/link-parser/command-line.h @@ -16,6 +16,8 @@ #include +#define D_USER_FILES 4 /* Debug level for files, see error.h. */ + #define COMMENT_CHAR '%' /* input lines beginning with this are ignored */ #define WHITESPACE " \t\v\r\n" /* ASCII-only is sufficient here */ #define FIELD_WIDTH(str, width) (int)((width)+strlen(str)-utf8_strwidth(str)) @@ -61,6 +63,7 @@ typedef struct { } Command_Options; void put_local_vars_in_opts(Command_Options *); +void put_opts_in_local_vars(Command_Options *); void setup_panic_parse_options(Command_Options *, int); typedef enum diff --git a/link-parser/lg_readline.c b/link-parser/lg_readline.c index bf715d1ee..4bcdf1c1b 100644 --- a/link-parser/lg_readline.c +++ b/link-parser/lg_readline.c @@ -83,10 +83,11 @@ void find_history_filepath(const char *dictname, const char *argv0, prt_error("Warning: xdg_get_home(XDG_BD_STATE) failed; " "input history will not be supported.\n"); history_file = strdup("dev/null"); - return; } history_file = hfile; + if (get_verbosity() == D_USER_FILES) + prt_error("Debug: Using history file \"%s\"\n", history_file); } /** @@ -375,8 +376,9 @@ static unsigned char lg_complete(EditLine *el, int ch) { if (fchdir(cwdfd) < 0) { - /* This shouldn't happen, unless maybe the directory to which - * cwdfd reveres becomes unreadable after cwdfd is created. */ + /* Unexpected error: may occur only if the directory + * referenced by cwdfd becomes unreadable after cwdfd + * has been established. */ printf("\nfchdir(): Cannot change directory back: %s\n", strerror(errno)); } @@ -419,7 +421,7 @@ char *lg_readline(const char *mb_prompt) wc_prompt = malloc (sz*sizeof(wchar_t)); mbstowcs(wc_prompt, mb_prompt, sz); - hist = history_winit(); /* Init built-in history */ + hist = history_winit(); /* Init built-in history */ el = el_init("link-parser", stdin, stdout, stderr); history_w(hist, &ev, H_SETSIZE, 100); history_w(hist, &ev, H_SETUNIQUE, 1); @@ -442,7 +444,7 @@ char *lg_readline(const char *mb_prompt) el_source(el, NULL); /* Source the user's defaults file. */ } - int numc = 1; /* Uninitialized at libedit. */ + int numc = 1; /* Uninitialized at libedit. */ const wchar_t *wc_line = el_wgets(el, &numc); /* Received end-of-file */ @@ -467,7 +469,7 @@ char *lg_readline(const char *mb_prompt) /* fwprintf(stderr, L"==> got %d %ls", numc, wc_line); */ size_t byte_len = wcstombs(NULL, wc_line, 0) + 4; - free(mb_line); // free previous. + free(mb_line); // free previous. if (byte_len == (size_t)-1) { prt_error("Error: Unable to process UTF8 in input string.\n"); diff --git a/link-parser/lg_xdg.c b/link-parser/lg_xdg.c index 955efc48d..74aeb0586 100644 --- a/link-parser/lg_xdg.c +++ b/link-parser/lg_xdg.c @@ -38,7 +38,7 @@ typedef struct xdg_definition xdg_def[] = { - { "/.local/state", "XDG_STATE_HOME" }, + { "/.local/state", "XDG_STATE_HOME" }, // Add more definitions if needed. }; @@ -84,22 +84,23 @@ static bool is_sep(int c) */ static bool make_dirpath(const char *path) { - char *dir = strdup(path); struct stat sb; #if defined(_WIN32) || defined(__CYGWIN__) // Skip Windows UNC path \\X - if (is_sep(dir[0]) && is_sep(dir[1])) + if (is_sep(path[0]) && is_sep(path[1])) { const char *p; // Start from the root or network share - for (p = dir + 2; *p != '\0'; p++) + for (p = path + 2; *p != '\0'; p++) if (is_sep(*p)) break; if (*p == '\0') return true; // No further subdirectories } #endif + char *dir = strdup(path); + for (char *p = dir+1; '\0' != *p; p++) { char sep = *p; @@ -107,7 +108,7 @@ static bool make_dirpath(const char *path) { if (is_sep(p[-1])) continue; // Ignore directory separator sequences *p = '\0'; // Now dir is the path up to this point - //prt_error("DEBUG: mkdir: '%s'\n", dir); + //prt_error("Debug: mkdir: '%s'\n", dir); if (mkdir(dir, S_IRWXU) == -1) { int save_errno = errno; diff --git a/link-parser/link-parser.c b/link-parser/link-parser.c index 335a2de7d..09837d7d2 100644 --- a/link-parser/link-parser.c +++ b/link-parser/link-parser.c @@ -69,6 +69,21 @@ static const char *use_prompt(int verbosity_level) return (0 == verbosity_level)? "" : prompt; } +/** + * Set link-parser's default parse options. + */ +static void set_default_parse_options(Parse_Options opts) +{ + parse_options_set_max_parse_time(opts, 30); + parse_options_set_linkage_limit(opts, 1000); + parse_options_set_min_null_count(opts, 0); + parse_options_set_max_null_count(opts, 0); + parse_options_set_short_length(opts, 16); + parse_options_set_islands_ok(opts, false); + parse_options_set_display_morphology(opts, false); + parse_options_set_spell_guess(opts, 7); +} + typedef enum { UNGRAMMATICAL = '*', @@ -482,6 +497,43 @@ static const char *fbasename(const char *fpath) return progf + 1; } +/** + * Return a dictionary handle for \p languege. Return NULL on failure. + * silence library verbose output if needed. + */ +static Dictionary dictionary_setup(const char *language, bool quiet, + Parse_Options opts) +{ + Dictionary dict; + int save_verbosity = parse_options_get_verbosity(opts); + + if (quiet && (save_verbosity == 1)) + parse_options_set_verbosity(opts, 0); + + if (language && *language) + { + dict = dictionary_create_lang(language); + if (dict == NULL) + { + prt_error("Fatal error: Unable to open dictionary.\n"); + return NULL; + } + } + else + { + dict = dictionary_create_default_lang(); + if (dict == NULL) + { + prt_error("Fatal error: Unable to open default dictionary.\n"); + return NULL; + } + } + + parse_options_set_verbosity(opts, save_verbosity); + + return dict; +} + static void print_usage(FILE *out, char *argv0, Command_Options *copts, int exit_value) { @@ -517,6 +569,12 @@ int main(int argc, char * argv[]) } copts = command_options_create(); + if (copts == NULL || copts->popts == NULL) + { + prt_error("Fatal error: unable to create parse options\n"); + exit(-1); + } + opts = copts->popts; /* First set the debug options, to allow dictionary-related debug. */ const char * const debug_vars[] = { "verbosity", "debug", "test" }; @@ -578,40 +636,10 @@ int main(int argc, char * argv[]) } /* End of debug options setup. */ - if (language && *language) - { - dict = dictionary_create_lang(language); - if (dict == NULL) - { - prt_error("Fatal error: Unable to open dictionary.\n"); - exit(-1); - } - } - else - { - dict = dictionary_create_default_lang(); - if (dict == NULL) - { - prt_error("Fatal error: Unable to open default dictionary.\n"); - exit(-1); - } - } - - if (copts == NULL || copts->popts == NULL) - { - prt_error("Fatal error: unable to create parse options\n"); - exit(-1); - } - opts = copts->popts; + dict = dictionary_setup(language, quiet_start > 0, opts); + if (dict == NULL) exit(-1); - parse_options_set_max_parse_time(opts, 30); - parse_options_set_linkage_limit(opts, 1000); - parse_options_set_min_null_count(opts, 0); - parse_options_set_max_null_count(opts, 0); - parse_options_set_short_length(opts, 16); - parse_options_set_islands_ok(opts, false); - parse_options_set_display_morphology(opts, false); - parse_options_set_spell_guess(opts, 7); + set_default_parse_options(opts); /* Get the panic disjunct cost from the dictionary. */ const char *panic_max_cost_str = @@ -641,22 +669,10 @@ int main(int argc, char * argv[]) parse_options_set_disjunct_cost(opts, linkgrammar_get_dict_max_disjunct_cost(dict)); - /* Remember the debug setting, because we temporary neglect it below. */ - int verbosity_tmp = parse_options_get_verbosity(opts); - char *debug_tmp = strdup(parse_options_get_debug(opts)); - char *test_tmp = strdup(parse_options_get_test(opts)); - - parse_options_set_verbosity(opts, 1); /* XXX assuming 1 is the default */ - parse_options_set_debug(opts, ""); - parse_options_set_test(opts, ""); - save_default_opts(copts); /* Options so far are the defaults */ - - /* Restore the debug setting. */ - parse_options_set_verbosity(opts, verbosity_tmp); - parse_options_set_debug(opts, debug_tmp); - parse_options_set_test(opts, test_tmp); - free(debug_tmp); - free(test_tmp); + /* Options so far are the defaults (save_default_opts() ensures + * saving the defaults for debug, test, and verbosity, which may have + * already been set by the program's arguments at this point.) */ + save_default_opts(copts); /* Process non-debug command line variable-setting commands (only). */ for (int i = 1; i < argc; i++) @@ -688,8 +704,6 @@ int main(int argc, char * argv[]) } } - initialize_screen_width(copts); - if ((parse_options_get_verbosity(opts)) > 0 && (quiet_start == 0)) { prt_error("Info: Dictionary version %s, locale %s\n", @@ -699,6 +713,8 @@ int main(int argc, char * argv[]) linkgrammar_get_version()); } + put_opts_in_local_vars(copts); /* Update local.verbosity etc. */ + initialize_screen_width(copts); if (isatty_io) { find_history_filepath(dictionary_get_lang(dict), argv[0], "link-parser"); diff --git a/link-parser/parser-utilities.c b/link-parser/parser-utilities.c index a0d361059..64578061f 100644 --- a/link-parser/parser-utilities.c +++ b/link-parser/parser-utilities.c @@ -11,10 +11,6 @@ /* */ /***************************************************************************/ -/* Used for terminal resizing */ -#ifndef _WIN32 -#endif /* _WIN32 */ - #ifdef _WIN32 #include #include @@ -146,7 +142,7 @@ int get_console_line(char *inbuf, int inbuf_size) snprintf(inbuf, inbuf_size, "ReadConsoleW: Error %lu\n", GetLastError()); return -1; } - winbuf[nchar] = L'\0'; /* nchar is always <= INPUT_UTF16_SIZE-1. */ + winbuf[nchar] = L'\0'; /* nchar is always <= INPUT_UTF16_SIZE-1. */ nchar = WideCharToMultiByte(CP_UTF8, 0, winbuf, -1, inbuf, inbuf_size, NULL, NULL); diff --git a/link-parser/parser-utilities.h b/link-parser/parser-utilities.h index 3322ec864..62f660a60 100644 --- a/link-parser/parser-utilities.h +++ b/link-parser/parser-utilities.h @@ -21,6 +21,7 @@ char *expand_homedir(const char *fn); void set_screen_width(Command_Options*); void initialize_screen_width(Command_Options *); +int get_verbosity(void); // Defined in command-line.c #define MAX_INPUT_LINE 2048