-
-/* totp_args.c
- *
- * Copyright (c) 2024, mar77i <mar77i at protonmail dot ch>
- *
- * This software may be modified and distributed under the terms
- * of the ISC license. See the LICENSE file for details.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "totp_args.h"
-
-static inline int print_help(const char *argv0) {
- printf(
- "Usage: %s -h|--help\n"
- " %s [-f<file>] [--] [search]\n"
- "\n"
- "Options:\n"
- "-h, --help: display this help\n"
- "-f<file>: specify input file.\n"
- "search: output filter string.\n"
- "\n"
- "Environment:\n"
- "OTP_SECRETS set a default input file (defaults to ~/.otp_secrets)\n"
- "\n",
- argv0,
- argv0
- );
- return 1;
-}
-
-#define ARG (ta->argv[ta->argi])
-static inline int parse_arg_file(struct totp_args *ta) {
- char *ptr = ARG + 2;
- if (*ptr == '\0') {
- if (++ta->argi >= ta->argc) {
- fprintf(stderr, "Error: filename missing.\n");
- return -1;
- }
- ptr = ARG;
- }
- ta->path = strdup(ptr);
- if (ta->path == NULL) {
- perror("strdup");
- return -1;
- }
- return 0;
-}
-
-#define TOTP_DEFAULT_FILE "/.otp_secrets"
-static inline char *get_otp_secrets_path(void) {
- size_t len;
- char *ptr, *env = getenv("OTP_SECRETS");
- if (env == NULL)
- goto default_path;
- len = strlen(env);
- if (len == 0) {
- fprintf(stderr, "Error: path is empty: OTP_SECRETS\n");
- return NULL;
- }
- ptr = strdup(env);
- if (ptr == NULL)
- perror("strdup");
- return ptr;
-default_path:
- env = getenv("HOME");
- if (env == NULL) {
- fprintf(stderr, "Error: HOME is unset.\n");
- return NULL;
- } else if (*env == '\0') {
- fprintf(stderr, "Error: HOME is empty.\n");
- return NULL;
- }
- len = strlen(env);
- while (env[--len] == '/');
- len++;
- ptr = malloc(len + sizeof TOTP_DEFAULT_FILE);
- if (ptr != NULL) {
- memcpy(ptr, env, len);
- memcpy(ptr + len, TOTP_DEFAULT_FILE, sizeof TOTP_DEFAULT_FILE);
- } else
- perror("malloc");
- return ptr;
-}
-
-static inline int parse_arg(struct totp_args *ta) {
- if (ta->double_minus != 0)
- goto double_minus_set;
- if (!strcmp(ARG, "-h") || !strcmp(ARG, "--help"))
- return print_help(ta->argv[0]);
- else if (!strncmp(ARG, "-f", 2))
- return parse_arg_file(ta);
- else if (!strcmp(ARG, "--")) {
- ta->double_minus = 1;
- return 0;
- }
-double_minus_set:
- if (ta->search != NULL) {
- fprintf(stderr, "Error: search string has already been passed.\n");
- return -1;
- }
- ta->search = ARG;
- return 0;
-}
-
-int totp_args_setup(struct totp_args *ta) {
- int ret = -1;
- for (; ta->argi < ta->argc; ta->argi++)
- switch (parse_arg(ta)) {
- case 1:
- ret = 1;
- // FALLTHROUGH
- case -1:
- goto error;
- }
- if (ta->path == NULL)
- ta->path = get_otp_secrets_path();
- if (ta->path == NULL)
- goto error;
- if (strcmp(ta->path, "-")) {
- ta->fh = fopen(ta->path, "rb");
- if (ta->fh == NULL) {
- perror("fopen");
- goto error;
- }
- } else
- ta->fh = stdin;
- ret = 0;
-error:
- return ret;
-}
-#undef ARG
-
-void totp_args_cleanup(const struct totp_args ta) {
- if (ta.fh != NULL && ta.fh != stdin)
- fclose(ta.fh);
- free(ta.path);
-}