arif/src/arify_cli.c

190 lines
4.6 KiB
C

/**
* arif/src/arify_cli.c - CLI wrapper for the ARIF preload library
* ----
*
* Copyright (C) 2023 CismonX <admin@cismon.net>
*
* This file is part of ARIF, Another Readline Input Framework.
*
* ARIF is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ARIF is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ARIF. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "arif.h"
#include "arif_defs.h"
#define ARIFY_PRELOAD_LIB ARIF_LIBDIR "/libarify" ARIF_SHLIB_SUFFIX
struct options {
char *frontend;
char *engines;
char *log_file;
char *page_size;
char *preload;
};
// Forward declaration start
static void append_str (char const *, char **, char);
static char * concat_str (char const *, char const *, char);
static int parse_options (int, char *const [], struct options *);
static void print_usage (char const *);
static void set_envs (struct options *);
// Forward declaration end
static void
append_str (
char const *src,
char **dest_ptr,
char sep
) {
char *dest = *dest_ptr;
size_t src_len = strlen(src) + 1;
size_t dest_len = dest == NULL ? 0 : strlen(dest);
*dest_ptr = dest = realloc(dest, src_len + dest_len + 1);
assert(dest != NULL);
dest[dest_len++] = sep;
memcpy(dest + dest_len, src, src_len);
}
static char *
concat_str (
char const *left,
char const *right,
char sep
) {
size_t left_len = strlen(left);
size_t right_len = strlen(right) + 1;
char *dest = malloc(sizeof(char) * (left_len + right_len + 1));
assert(dest != NULL);
memcpy(dest, left, left_len);
dest[left_len++] = sep;
memcpy(dest + left_len, right, right_len);
return dest;
}
static int
parse_options (
int argc,
char *const argv[],
struct options *opts
) {
while (1) {
switch (getopt(argc, argv, "e:f:p:l:n:HV")) {
case 'e':
append_str(optarg, &opts->engines, ' ');
break;
case 'f':
opts->frontend = optarg;
break;
case 'p':
opts->preload = optarg;
break;
case 'l':
opts->log_file = optarg;
break;
case 'n':
opts->page_size = optarg;
break;
case 'V':
fprintf(stderr, "arify (ARIF %d.%d.%d)\n",
ARIF_VER_MAJOR, ARIF_VER_MINOR, ARIF_VER_PATCH);
exit(EXIT_SUCCESS);
case -1:
return optind;
case '?':
default:
print_usage(argv[0]);
break;
}
}
}
static void
print_usage (
char const *program
) {
fputs("Usage: ", stderr);
fputs(program, stderr);
fputs(" [options] filepath [args]\n\n", stderr);
fputs("See the arify(1) man page for details.\n", stderr);
exit(EXIT_FAILURE);
}
static void
set_envs (
struct options *opts
) {
if (opts->frontend != NULL) {
setenv("ARIFY_FRONTEND", opts->frontend, 1);
}
if (opts->engines != NULL) {
setenv("ARIFY_ENGINES", opts->engines, 1);
}
if (opts->log_file != NULL) {
setenv("ARIFY_LOG_FILE", opts->log_file, 1);
}
if (opts->page_size != NULL) {
setenv("ARIFY_PAGE_SIZE", opts->page_size, 1);
}
char *old_preload = getenv("LD_PRELOAD");
if (old_preload == NULL) {
old_preload = "";
}
opts->preload = concat_str(old_preload, opts->preload, ':');
setenv("LD_PRELOAD", opts->preload, 1);
}
int
main (
int argc,
char *argv[]
) {
char const *program = argv[0];
assert(program != NULL);
struct options opts = {
.preload = ARIFY_PRELOAD_LIB,
};
argv += parse_options(argc, argv, &opts);
set_envs(&opts);
free(opts.engines);
free(opts.preload);
if (argv[0] == NULL) {
fprintf(stderr, "%s: no executable file specified\n", program);
print_usage(program);
}
if (-1 == execvp(argv[0], argv)) {
fprintf(stderr, "%s: %s: %s\n", program, argv[0], strerror(errno));
exit(EXIT_FAILURE);
}
}