/*
* Copyright © 2021 Ran Benita <ran@unusedvar.com>
* SPDX-License-Identifier: MIT
*/
#include "config.h"
#include <getopt.h>
#include <locale.h>
#include <stdbool.h>
#include "xkbcommon/xkbcommon.h"
#include "xkbcommon/xkbcommon-keysyms.h"
#include "xkbcommon/xkbcommon-compose.h"
#include "src/compose/dump.h"
#include "src/keysym.h"
#include "tools/tools-common.h"
static void
usage(FILE *fp, char *progname)
{
fprintf(fp,
"Usage: %s [--help] [--verbose] [--locale LOCALE] [--test] [FILE]\n",
progname);
fprintf(fp,
"\n"
"Compile a Compose file and print it\n"
"\n"
"Options:\n"
" --help\n"
" Print this help and exit\n"
" --verbose\n"
" Enable verbose debugging output\n"
" --file FILE\n"
" Specify a Compose file to load.\n"
" DEPRECATED: use the positional argument instead.\n"
" --locale LOCALE\n"
" Specify the locale directly, instead of relying on the environment variables\n"
" LC_ALL, LC_TYPE and LANG.\n"
" --test\n"
" Test compilation but do not print the Compose file.\n");
}
int
main(int argc, char *argv[])
{
const char *locale = NULL;
const char *path = NULL;
enum xkb_compose_format format = XKB_COMPOSE_FORMAT_TEXT_V1;
bool verbose = false;
bool test = false;
enum options {
OPT_VERBOSE,
OPT_FILE,
OPT_LOCALE,
OPT_TEST,
};
static struct option opts[] = {
{"help", no_argument, 0, 'h'},
{"verbose", no_argument, 0, OPT_VERBOSE},
{"file", required_argument, 0, OPT_FILE},
{"locale", required_argument, 0, OPT_LOCALE},
{"test", no_argument, 0, OPT_TEST},
{0, 0, 0, 0},
};
setlocale(LC_ALL, "");
/* Initialize the locale to use */
locale = setlocale(LC_CTYPE, NULL);
if (!locale)
locale = "C";
while (1) {
int opt;
int option_index = 0;
opt = getopt_long(argc, argv, "h", opts, &option_index);
if (opt == -1)
break;
switch (opt) {
case OPT_VERBOSE:
verbose = true;
break;
case OPT_FILE:
path = optarg;
fprintf(stderr, "WARNING: the flag --file is deprecated\n");
break;
case OPT_LOCALE:
locale = optarg;
break;
case OPT_TEST:
test = true;
break;
case 'h':
usage(stdout, argv[0]);
return EXIT_SUCCESS;
default:
usage(stderr, argv[0]);
return EXIT_INVALID_USAGE;
}
}
if (locale == NULL) {
fprintf(stderr, "ERROR: Cannot determine the locale.\n");
usage(stderr, argv[0]);
return EXIT_INVALID_USAGE;
}
if (optind < argc && !isempty(argv[optind])) {
/* Some positional arguments left: use a file */
if (path) {
fprintf(stderr,
"ERROR: Path already provided via the flag: --file\n");
usage(stderr, argv[0]);
exit(EXIT_INVALID_USAGE);
}
path = argv[optind++];
if (optind < argc) {
fprintf(stderr, "ERROR: Too many positional arguments\n");
usage(stderr, argv[0]);
exit(EXIT_INVALID_USAGE);
}
} else if (is_pipe_or_regular_file(STDIN_FILENO)) {
/* No positional argument: detect piping */
path = "-";
}
struct xkb_context *ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!ctx) {
fprintf(stderr, "ERROR: Couldn't create xkb context\n");
return EXIT_FAILURE;
}
if (verbose)
tools_enable_verbose_logging(ctx);
int ret = EXIT_FAILURE;
struct xkb_compose_table *compose_table = NULL;
if (path != NULL) {
FILE *file;
if (isempty(path) || strcmp(path, "-") == 0) {
/* Read from stdin */
file = tools_read_stdin();
} else {
/* Read from regular file */
file = fopen(path, "rb");
}
if (file == NULL) {
perror(path);
goto file_error;
}
compose_table =
xkb_compose_table_new_from_file(ctx, file, locale, format,
XKB_COMPOSE_COMPILE_NO_FLAGS);
fclose(file);
if (!compose_table) {
fprintf(stderr,
"ERROR: Couldn't create compose from file: %s\n", path);
goto out;
}
} else {
compose_table =
xkb_compose_table_new_from_locale(ctx, locale,
XKB_COMPOSE_COMPILE_NO_FLAGS);
if (!compose_table) {
fprintf(stderr,
"ERROR: Couldn't create compose from locale \"%s\"\n",
locale);
goto out;
}
}
if (test) {
ret = EXIT_SUCCESS;
goto out;
}
ret = xkb_compose_table_dump(stdout, compose_table)
? EXIT_SUCCESS
: EXIT_FAILURE;
out:
xkb_compose_table_unref(compose_table);
file_error:
xkb_context_unref(ctx);
return ret;
}