blob: a145a1d7f6f18bdb08481988ffb4942d5a131d0a [file] [log] [blame]
/*
* *****************************************************************************
*
* Copyright 2018 Gavin D. Howard
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* *****************************************************************************
*
* Code for processing command-line arguments.
*
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <status.h>
#include <vector.h>
#include <io.h>
#include <vm.h>
#include <args.h>
static const struct option bc_args_lopt[] = {
{ "expression", required_argument, NULL, 'e' },
{ "file", required_argument, NULL, 'f' },
{ "help", no_argument, NULL, 'h' },
{ "interactive", no_argument, NULL, 'i' },
{ "mathlib", no_argument, NULL, 'l' },
{ "quiet", no_argument, NULL, 'q' },
{ "standard", no_argument, NULL, 's' },
{ "version", no_argument, NULL, 'v' },
{ "warn", no_argument, NULL, 'w' },
{ "extended-register", no_argument, NULL, 'x' },
{ 0, 0, 0, 0 },
};
static const char* const bc_args_opt = "e:f:hilqsvwx";
const char* const bc_args_env_name = "BC_ENV_ARGS";
static BcStatus bc_args_exprs(BcVec *exprs, const char *str) {
BcStatus s;
if ((s = bc_vec_concat(exprs, str))) return s;
return bc_vec_concat(exprs, "\n");
}
static BcStatus bc_args_file(BcVec *exprs, const char *file) {
BcStatus s;
char *buf;
if ((s = bc_io_fread(file, &buf))) return s;
s = bc_args_exprs(exprs, buf);
free(buf);
return s;
}
BcStatus bc_args(int argc, char *argv[], const char* const help,
unsigned int *flags, BcVec *exprs, BcVec *files) {
BcStatus s = BC_STATUS_SUCCESS;
int c, i, idx;
bool do_exit = false;
idx = c = optind = 0;
while ((c = getopt_long(argc, argv, bc_args_opt, bc_args_lopt, &idx)) != -1)
{
switch (c) {
case 0:
{
// This is the case when a long option is found.
if (bc_args_lopt[idx].val == 'e')
s = bc_args_exprs(exprs, optarg);
else if (bc_args_lopt[idx].val == 'f')
s = bc_args_file(exprs, optarg);
break;
}
case 'e':
{
if ((s = bc_args_exprs(exprs, optarg))) return s;
break;
}
case 'f':
{
if ((s = bc_args_file(exprs, optarg))) return s;
break;
}
case 'h':
{
if ((s = bc_vm_header(help))) return s;
do_exit = true;
break;
}
#ifdef BC_ENABLED
case 'i':
{
if (!bcg.bc) return BC_STATUS_INVALID_OPTION;
(*flags) |= BC_FLAG_I;
break;
}
case 'l':
{
if (!bcg.bc) return BC_STATUS_INVALID_OPTION;
(*flags) |= BC_FLAG_L;
break;
}
case 'q':
{
if (!bcg.bc) return BC_STATUS_INVALID_OPTION;
(*flags) |= BC_FLAG_Q;
break;
}
case 's':
{
if (!bcg.bc) return BC_STATUS_INVALID_OPTION;
(*flags) |= BC_FLAG_S;
break;
}
case 'w':
{
if (!bcg.bc) return BC_STATUS_INVALID_OPTION;
(*flags) |= BC_FLAG_W;
break;
}
#endif // BC_ENABLED
case 'V':
case 'v':
{
if ((s = bc_vm_header(NULL))) return s;
do_exit = true;
break;
}
#ifdef DC_ENABLED
case 'x':
{
if (bcg.bc) return BC_STATUS_INVALID_OPTION;
(*flags) |= BC_FLAG_X;
break;
}
#endif // DC_ENABLED
// Getopt printed an error message, but we should exit.
case '?':
default:
{
return BC_STATUS_INVALID_OPTION;
}
}
}
if (do_exit) exit((int) s);
if (exprs->len > 1) (*flags) |= BC_FLAG_Q;
if (argv[optind] && strcmp(argv[optind], "--") == 0) ++optind;
for (i = optind; !s && i < argc; ++i) s = bc_vec_push(files, argv + i);
return s;
}