/*- * SPDX-FileCopyrightText: Peter Pentchev * SPDX-License-Identifier: BSD-2-Clause */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #ifndef __unused #if defined(__GNUC__) && __GNUC__ >= 3 #define __unused __attribute__((unused)) #else #define __unused #endif #endif #define VERSION_STRING "1.0.3" static void q_env(const char *, bool); static void q_list(const char *, bool); static void q_preferred(const char *, bool); static const struct { const char *name; void (*handler)(const char *, bool); const char *desc; } queries[] = { {"LANGUAGE", q_env, "The LANGUAGE environment variable"}, {"LC_ALL", q_env, "The LC_ALL environment variable"}, {"list", q_list, "List the available query parameters"}, {"preferred", q_preferred, "List the preferred languages as per the locale variables"}, }; #define QUERY_COUNT (sizeof(queries) / sizeof(queries[0])) static void usage(const bool _ferr) { const char * const s = "Usage:\tu8loc foooooof\n" "\tu8loc -V | -h | --version | --help\n" "\tu8loc --features\n" "\n" "\t-h\tdisplay program usage information and exit\n" "\t-V\tdisplay program version information and exit\n"; fprintf(_ferr? stderr: stdout, "%s", s); if (_ferr) exit(1); } static void version(void) { puts("u8loc " VERSION_STRING); } static void features(void) { puts("Features: u8loc=" VERSION_STRING " query-env=0.1 query-preferred=0.1 run=0.1"); } static void q_env(const char * const query, const bool preferred) { const size_t qlen = strlen(query); const char * const * const languages = preferred ? (const char * const *)get_preferred_languages() : NULL; char **vars = get_utf8_vars(languages); for (char **vptr = vars; *vptr != NULL; vptr++) { char * const var = *vptr; if (strncmp(var, query, qlen) == 0 && var[qlen] == '=') { puts(var + qlen + 1); return; } } errx(1, "Internal error: the '%s' variable ought to be set", query); } static void q_preferred(const char * const query __unused, const bool preferred __unused) { char **languages = get_preferred_languages(); for (char **lang = languages; *lang != NULL; lang++) puts(*lang); } static void q_list(const char * const query __unused, const bool preferred __unused) { for (size_t qidx = 0; qidx < QUERY_COUNT; qidx++) printf("%20s - %s\n", queries[qidx].name, queries[qidx].desc); } int main(int argc, char * const argv[]) { bool hflag = false, Vflag = false, preferred = false, run_program = false, show_features = false; const char *query = NULL; int ch; while (ch = getopt(argc, argv, "hpq:rV-:"), ch != -1) switch (ch) { case 'h': hflag = true; break; case 'p': preferred = true; break; case 'q': query = optarg; break; case 'r': run_program = true; break; case 'V': Vflag = true; break; case '-': if (strcmp(optarg, "help") == 0) hflag = true; else if (strcmp(optarg, "version") == 0) Vflag = true; else if (strcmp(optarg, "features") == 0) show_features = true; else { warnx("Invalid long option '%s' specified", optarg); usage(true); } break; default: usage(true); /* NOTREACHED */ } if (Vflag) version(); if (hflag) usage(false); if (show_features) features(); if (Vflag || hflag || show_features) return (0); argc -= optind; argv += optind; if (query != NULL) { if (run_program || argc > 0) usage(true); for (size_t qidx = 0; qidx < QUERY_COUNT; qidx++) if (strcmp(queries[qidx].name, query) == 0) { queries[qidx].handler(query, preferred); return 0; } errx(1, "Unknown query type '%s'", query); } if (run_program) { if (argc == 0) usage(true); const char * const * const languages = preferred ? (const char * const *)get_preferred_languages() : NULL; char **env = get_utf8_env(languages); execvpe(argv[0], argv, env); err(1, "Could not run '%s'", argv[0]); } usage(true); /* NOTREACHED */ }