blob: 4465d9f0339ea42a878c93b4fe9a390cc9c19a87 [file] [log] [blame]
/*
* *****************************************************************************
*
* Copyright (c) 2018-2019 Gavin D. Howard and contributors.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* *****************************************************************************
*
* Code for processing command-line arguments.
*
*/
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <status.h>
#include <vector.h>
#include <read.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' },
#if BC_ENABLED
{ "global-stacks", no_argument, NULL, 'g' },
{ "interactive", no_argument, NULL, 'i' },
{ "mathlib", no_argument, NULL, 'l' },
{ "quiet", no_argument, NULL, 'q' },
{ "standard", no_argument, NULL, 's' },
{ "warn", no_argument, NULL, 'w' },
#endif // BC_ENABLED
{ "version", no_argument, NULL, 'v' },
#if DC_ENABLED
{ "extended-register", no_argument, NULL, 'x' },
#endif // DC_ENABLED
{ 0, 0, 0, 0 },
};
#if !BC_ENABLED
static const char* const bc_args_opt = "e:f:hvVx";
#elif !DC_ENABLED
static const char* const bc_args_opt = "e:f:ghilqsvVw";
#else // BC_ENABLED && DC_ENABLED
static const char* const bc_args_opt = "e:f:ghilqsvVwx";
#endif // BC_ENABLED && DC_ENABLED
static void bc_args_exprs(BcVec *exprs, const char *str) {
bc_vec_concat(exprs, str);
bc_vec_concat(exprs, "\n");
}
static BcStatus bc_args_file(BcVec *exprs, const char *file) {
BcStatus s;
char *buf;
vm->file = file;
s = bc_read_file(file, &buf);
if (BC_ERR(s)) return s;
bc_args_exprs(exprs, buf);
free(buf);
return s;
}
BcStatus bc_args(int argc, char *argv[]) {
BcStatus s = BC_STATUS_SUCCESS;
int c, i, err = 0;
bool do_exit = false, version = false;
i = optind = 0;
while ((c = getopt_long(argc, argv, bc_args_opt, bc_args_lopt, &i)) != -1) {
switch (c) {
case 0:
{
// This is the case when a long option is found.
break;
}
case 'e':
{
bc_args_exprs(&vm->exprs, optarg);
break;
}
case 'f':
{
s = bc_args_file(&vm->exprs, optarg);
if (BC_ERR(s)) return s;
break;
}
case 'h':
{
bc_vm_info(vm->help);
do_exit = true;
break;
}
#if BC_ENABLED
case 'g':
{
if (BC_ERR(!BC_IS_BC)) err = c;
vm->flags |= BC_FLAG_G;
break;
}
case 'i':
{
if (BC_ERR(!BC_IS_BC)) err = c;
vm->flags |= BC_FLAG_I;
break;
}
case 'l':
{
if (BC_ERR(!BC_IS_BC)) err = c;
vm->flags |= BC_FLAG_L;
break;
}
case 'q':
{
if (BC_ERR(!BC_IS_BC)) err = c;
vm->flags |= BC_FLAG_Q;
break;
}
case 's':
{
if (BC_ERR(!BC_IS_BC)) err = c;
vm->flags |= BC_FLAG_S;
break;
}
case 'w':
{
if (BC_ERR(!BC_IS_BC)) err = c;
vm->flags |= BC_FLAG_W;
break;
}
#endif // BC_ENABLED
case 'V':
case 'v':
{
do_exit = version = true;
break;
}
#if DC_ENABLED
case 'x':
{
if (BC_ERR(BC_IS_BC)) err = c;
vm->flags |= DC_FLAG_X;
break;
}
#endif // DC_ENABLED
// Getopt printed an error message, but we should exit.
case '?':
default:
{
return BC_STATUS_ERROR_VM;
}
}
if (BC_ERR(err)) {
for (i = 0; bc_args_lopt[i].name; ++i) {
if (bc_args_lopt[i].val == err) break;
}
return bc_vm_verr(BC_ERROR_FATAL_OPTION, err, bc_args_lopt[i].name);
}
}
if (version) bc_vm_info(NULL);
if (do_exit) exit((int) s);
if (vm->exprs.len > 1 || !BC_IS_BC) vm->flags |= BC_FLAG_Q;
if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
for (i = optind; i < argc; ++i) bc_vec_push(&vm->files, argv + i);
return s;
}