#include <ctype.h>
#include <demangle-sys.h>
#include <err.h>
#include <errno.h>
#include <libcustr.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#define _(x) gettext(x)
locale_t c_locale;
static int do_symbols(sysdem_lang_t, int, char * const *);
static int do_input(sysdem_lang_t, FILE *restrict, FILE *restrict);
static int do_demangle(const char *, sysdem_lang_t, FILE *);
static void appendc(custr_t *, char);
static void xputc(int, FILE *);
static void
usage(void)
{
(void) fprintf(stderr, _("Usage: %s [-l lang] [sym...]\n"),
getprogname());
exit(2);
}
int
main(int argc, char * const *argv)
{
sysdem_lang_t lang = SYSDEM_LANG_AUTO;
int c;
int ret;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
if ((c_locale = newlocale(LC_CTYPE_MASK, "C", NULL)) == NULL)
err(EXIT_FAILURE, _("failed to construct C locale"));
while ((c = getopt(argc, argv, "hl:")) != -1) {
switch (c) {
case 'l':
if (sysdem_parse_lang(optarg, &lang))
break;
errx(EXIT_FAILURE, _("Unsupported language '%s'\n"),
optarg);
case 'h':
case '?':
usage();
}
}
argc -= optind;
argv += optind;
if (argc > 0)
ret = do_symbols(lang, argc, argv);
else
ret = do_input(lang, stdin, stdout);
return ((ret < 0) ? EXIT_FAILURE : EXIT_SUCCESS);
}
static int
do_symbols(sysdem_lang_t lang, int argc, char * const *argv)
{
int ret = 0;
for (int i = 0; i < argc; i++) {
if (do_demangle(argv[i], lang, stdout) < 0)
ret = -1;
else
xputc('\n', stdout);
}
return (ret);
}
static int
do_input(sysdem_lang_t lang, FILE *restrict in, FILE *restrict out)
{
custr_t *word = NULL;
int c;
int ret = 0;
boolean_t in_symbol = B_FALSE;
if (custr_alloc(&word) != 0)
err(EXIT_FAILURE, _("failed to allocate memory"));
while ((c = fgetc(in)) != EOF) {
if (in_symbol) {
if (isalnum_l(c, c_locale) || c == '.' || c == '_' ||
c == '$') {
appendc(word, c);
continue;
}
if (do_demangle(custr_cstr(word), lang, out) < 0)
ret = -1;
custr_reset(word);
in_symbol = B_FALSE;
}
if (c != '_') {
xputc(c, out);
} else {
in_symbol = B_TRUE;
appendc(word, c);
}
}
if (ferror(in))
err(EXIT_FAILURE, _("error reading input"));
if (custr_len(word) > 0 && do_demangle(custr_cstr(word), lang, out) < 0)
ret = -1;
custr_free(word);
return (ret);
}
static int
do_demangle(const char *sym, sysdem_lang_t lang, FILE *out)
{
char *demangled = sysdemangle(sym, lang, NULL);
if (demangled == NULL && errno != EINVAL && errno != ENOTSUP) {
warn(_("error while demangling '%s'"), sym);
return (-1);
}
if (fprintf(out, "%s", (demangled != NULL) ? demangled : sym) < 0)
err(EXIT_FAILURE, _("failed to write to output"));
free(demangled);
return (0);
}
static void
appendc(custr_t *cus, char c)
{
if (custr_appendc(cus, c) == 0)
return;
err(EXIT_FAILURE, _("failed to save character from input"));
}
static void
xputc(int c, FILE *out)
{
if (fputc(c, out) < 0)
err(EXIT_FAILURE, _("failed to write output"));
}