|
Packit |
70b277 |
/* This file is part of GNU bc.
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
Copyright (C) 1991-1994, 1997, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
This program is free software; you can redistribute it and/or modify
|
|
Packit |
70b277 |
it under the terms of the GNU General Public License as published by
|
|
Packit |
70b277 |
the Free Software Foundation; either version 3 of the License , or
|
|
Packit |
70b277 |
(at your option) any later version.
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
This program is distributed in the hope that it will be useful,
|
|
Packit |
70b277 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
70b277 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
70b277 |
GNU General Public License for more details.
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
You should have received a copy of the GNU General Public License
|
|
Packit |
70b277 |
along with this program; see the file COPYING. If not, see
|
|
Packit |
70b277 |
<http://www.gnu.org/licenses>.
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
You may contact the author by:
|
|
Packit |
70b277 |
e-mail: philnelson@acm.org
|
|
Packit |
70b277 |
us-mail: Philip A. Nelson
|
|
Packit |
70b277 |
Computer Science Department, 9062
|
|
Packit |
70b277 |
Western Washington University
|
|
Packit |
70b277 |
Bellingham, WA 98226-9062
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
*************************************************************************/
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* main.c: The main program for bc. */
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
#include "bcdefs.h"
|
|
Packit |
70b277 |
#include <signal.h>
|
|
Packit |
70b277 |
#include <errno.h>
|
|
Packit |
70b277 |
#include "proto.h"
|
|
Packit |
70b277 |
#include "getopt.h"
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Variables for processing multiple files. */
|
|
Packit |
70b277 |
static char first_file;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Points to the last node in the file name list for easy adding. */
|
|
Packit |
70b277 |
static file_node *last = NULL;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
#if defined(LIBEDIT)
|
|
Packit |
70b277 |
/* The prompt for libedit. */
|
|
Packit |
70b277 |
char el_pmtchars[] = "";
|
|
Packit |
70b277 |
static char *el_pmtfunc(void);
|
|
Packit |
70b277 |
static char *el_pmtfunc(void) { return el_pmtchars; }
|
|
Packit |
70b277 |
#endif
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* long option support */
|
|
Packit |
70b277 |
static struct option long_options[] =
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
{"compile", 0, &compile_only, TRUE},
|
|
Packit |
70b277 |
{"help", 0, 0, 'h'},
|
|
Packit |
70b277 |
{"interactive", 0, 0, 'i'},
|
|
Packit |
70b277 |
{"mathlib", 0, &use_math, TRUE},
|
|
Packit |
70b277 |
{"quiet", 0, &quiet, TRUE},
|
|
Packit |
70b277 |
{"standard", 0, &std_only, TRUE},
|
|
Packit |
70b277 |
{"version", 0, 0, 'v'},
|
|
Packit |
70b277 |
{"warn", 0, &warn_not_std, TRUE},
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
{0, 0, 0, 0}
|
|
Packit |
70b277 |
};
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
static void
|
|
Packit |
70b277 |
usage (const char *progname)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
printf ("usage: %s [options] [file ...]\n%s%s%s%s%s%s%s", progname,
|
|
Packit |
70b277 |
" -h --help print this usage and exit\n",
|
|
Packit |
70b277 |
" -i --interactive force interactive mode\n",
|
|
Packit |
70b277 |
" -l --mathlib use the predefined math routines\n",
|
|
Packit |
70b277 |
" -q --quiet don't print initial banner\n",
|
|
Packit |
70b277 |
" -s --standard non-standard bc constructs are errors\n",
|
|
Packit |
70b277 |
" -w --warn warn about non-standard bc constructs\n",
|
|
Packit |
70b277 |
" -v --version print version information and exit\n");
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
static void
|
|
Packit |
70b277 |
parse_args (int argc, char **argv)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
int optch;
|
|
Packit |
70b277 |
int long_index;
|
|
Packit |
70b277 |
file_node *temp;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Force getopt to initialize. Depends on GNU getopt. */
|
|
Packit |
70b277 |
optind = 0;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Parse the command line */
|
|
Packit |
70b277 |
while (1)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
optch = getopt_long (argc, argv, "chilqswv", long_options, &long_index);
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
if (optch == EOF) /* End of arguments. */
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
switch (optch)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
case 0: /* Long option setting a var. */
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'c': /* compile only */
|
|
Packit |
70b277 |
compile_only = TRUE;
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'h': /* help */
|
|
Packit |
70b277 |
usage(argv[0]);
|
|
Packit |
70b277 |
bc_exit (0);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'i': /* force interactive */
|
|
Packit |
70b277 |
interactive = TRUE;
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'l': /* math lib */
|
|
Packit |
70b277 |
use_math = TRUE;
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'q': /* quiet mode */
|
|
Packit |
70b277 |
quiet = TRUE;
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 's': /* Non standard features give errors. */
|
|
Packit |
70b277 |
std_only = TRUE;
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'v': /* Print the version. */
|
|
Packit |
70b277 |
show_bc_version ();
|
|
Packit |
70b277 |
bc_exit (0);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'w': /* Non standard features give warnings. */
|
|
Packit |
70b277 |
warn_not_std = TRUE;
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
default:
|
|
Packit |
70b277 |
usage(argv[0]);
|
|
Packit |
70b277 |
bc_exit (1);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
#ifdef QUIET
|
|
Packit |
70b277 |
quiet = TRUE;
|
|
Packit |
70b277 |
#endif
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Add file names to a list of files to process. */
|
|
Packit |
70b277 |
while (optind < argc)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
temp = bc_malloc(sizeof(file_node));
|
|
Packit |
70b277 |
temp->name = argv[optind];
|
|
Packit |
70b277 |
temp->next = NULL;
|
|
Packit |
70b277 |
if (last == NULL)
|
|
Packit |
70b277 |
file_names = temp;
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
last->next = temp;
|
|
Packit |
70b277 |
last = temp;
|
|
Packit |
70b277 |
optind++;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* The main program for bc. */
|
|
Packit |
70b277 |
int
|
|
Packit |
70b277 |
main (int argc, char **argv)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
char *env_value;
|
|
Packit |
70b277 |
char *env_argv[30];
|
|
Packit |
70b277 |
int env_argc;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Interactive? */
|
|
Packit |
70b277 |
if (isatty(0) && isatty(1))
|
|
Packit |
70b277 |
interactive = TRUE;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
#ifdef HAVE_SETVBUF
|
|
Packit |
70b277 |
/* attempt to simplify interaction with applications such as emacs */
|
|
Packit |
70b277 |
(void) setvbuf(stdout, NULL, _IOLBF, 0);
|
|
Packit |
70b277 |
#endif
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Environment arguments. */
|
|
Packit |
70b277 |
env_value = getenv ("BC_ENV_ARGS");
|
|
Packit |
70b277 |
if (env_value != NULL)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
env_argc = 1;
|
|
Packit |
70b277 |
env_argv[0] = strdup("BC_ENV_ARGS");
|
|
Packit |
70b277 |
while (*env_value != 0)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
if (*env_value != ' ')
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
env_argv[env_argc++] = env_value;
|
|
Packit |
70b277 |
while (*env_value != ' ' && *env_value != 0)
|
|
Packit |
70b277 |
env_value++;
|
|
Packit |
70b277 |
if (*env_value != 0)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
*env_value = 0;
|
|
Packit |
70b277 |
env_value++;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
env_value++;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
parse_args (env_argc, env_argv);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Command line arguments. */
|
|
Packit |
70b277 |
parse_args (argc, argv);
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Other environment processing. */
|
|
Packit |
70b277 |
if (getenv ("POSIXLY_CORRECT") != NULL)
|
|
Packit |
70b277 |
std_only = TRUE;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
env_value = getenv ("BC_LINE_LENGTH");
|
|
Packit |
70b277 |
if (env_value != NULL)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
line_size = atoi (env_value);
|
|
Packit |
70b277 |
if (line_size < 3 && line_size != 0)
|
|
Packit |
70b277 |
line_size = 70;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
line_size = 70;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Initialize the machine. */
|
|
Packit |
70b277 |
init_storage();
|
|
Packit |
70b277 |
init_load();
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Set up interrupts to print a message. */
|
|
Packit |
70b277 |
if (interactive)
|
|
Packit |
70b277 |
signal (SIGINT, use_quit);
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Initialize the front end. */
|
|
Packit |
70b277 |
init_tree();
|
|
Packit |
70b277 |
init_gen ();
|
|
Packit |
70b277 |
is_std_in = FALSE;
|
|
Packit |
70b277 |
first_file = TRUE;
|
|
Packit |
70b277 |
if (!open_new_file ())
|
|
Packit |
70b277 |
bc_exit (1);
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
#if defined(LIBEDIT)
|
|
Packit |
70b277 |
if (interactive) {
|
|
Packit |
70b277 |
/* Enable libedit support. */
|
|
Packit |
70b277 |
edit = el_init ("bc", stdin, stdout, stderr);
|
|
Packit |
70b277 |
hist = history_init();
|
|
Packit |
70b277 |
el_set (edit, EL_EDITOR, "emacs");
|
|
Packit |
70b277 |
el_set (edit, EL_HIST, history, hist);
|
|
Packit |
70b277 |
el_set (edit, EL_PROMPT, el_pmtfunc);
|
|
Packit |
70b277 |
el_source (edit, NULL);
|
|
Packit |
70b277 |
history (hist, &histev, H_SETSIZE, INT_MAX);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
#endif
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
#if defined(READLINE)
|
|
Packit |
70b277 |
if (interactive) {
|
|
Packit |
70b277 |
/* Readline support. Set both application name and input file. */
|
|
Packit |
70b277 |
rl_readline_name = "bc";
|
|
Packit |
70b277 |
rl_instream = stdin;
|
|
Packit |
70b277 |
using_history ();
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
#endif
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Do the parse. */
|
|
Packit |
70b277 |
yyparse ();
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* End the compile only output with a newline. */
|
|
Packit |
70b277 |
if (compile_only)
|
|
Packit |
70b277 |
printf ("\n");
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
bc_exit (0);
|
|
Packit |
70b277 |
return 0; // to keep the compiler from complaining
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* This is the function that opens all the files.
|
|
Packit |
70b277 |
It returns TRUE if the file was opened, otherwise
|
|
Packit |
70b277 |
it returns FALSE. */
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
int
|
|
Packit |
70b277 |
open_new_file (void)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
FILE *new_file;
|
|
Packit |
70b277 |
file_node *temp;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Set the line number. */
|
|
Packit |
70b277 |
line_no = 1;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Check to see if we are done. */
|
|
Packit |
70b277 |
if (is_std_in) return (FALSE);
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Open the other files. */
|
|
Packit |
70b277 |
if (use_math && first_file)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
/* Load the code from a precompiled version of the math libarary. */
|
|
Packit |
70b277 |
CONST char **mstr;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* These MUST be in the order of first mention of each function.
|
|
Packit |
70b277 |
That is why "a" comes before "c" even though "a" is defined after
|
|
Packit |
70b277 |
after "c". "a" is used in "s"! */
|
|
Packit |
70b277 |
(void) lookup (strdup("e"), FUNCT);
|
|
Packit |
70b277 |
(void) lookup (strdup("l"), FUNCT);
|
|
Packit |
70b277 |
(void) lookup (strdup("s"), FUNCT);
|
|
Packit |
70b277 |
(void) lookup (strdup("a"), FUNCT);
|
|
Packit |
70b277 |
(void) lookup (strdup("c"), FUNCT);
|
|
Packit |
70b277 |
(void) lookup (strdup("j"), FUNCT);
|
|
Packit |
70b277 |
mstr = libmath;
|
|
Packit |
70b277 |
while (*mstr) {
|
|
Packit |
70b277 |
load_code (*mstr);
|
|
Packit |
70b277 |
mstr++;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* One of the argv values. */
|
|
Packit |
70b277 |
if (file_names != NULL)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
new_file = fopen (file_names->name, "r");
|
|
Packit |
70b277 |
if (new_file != NULL)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
new_yy_file (new_file);
|
|
Packit |
70b277 |
temp = file_names;
|
|
Packit |
70b277 |
file_name = temp->name;
|
|
Packit |
70b277 |
file_names = temp->next;
|
|
Packit |
70b277 |
free (temp);
|
|
Packit |
70b277 |
return TRUE;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
fprintf (stderr, "File %s is unavailable.\n", file_names->name);
|
|
Packit |
70b277 |
bc_exit (1);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* If we fall through to here, we should return stdin. */
|
|
Packit |
70b277 |
new_yy_file (stdin);
|
|
Packit |
70b277 |
is_std_in = TRUE;
|
|
Packit |
70b277 |
return TRUE;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Set yyin to the new file. */
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
void
|
|
Packit |
70b277 |
new_yy_file (FILE *file)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
if (!first_file) fclose (yyin);
|
|
Packit |
70b277 |
yyin = file;
|
|
Packit |
70b277 |
first_file = FALSE;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Message to use quit. */
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
void
|
|
Packit |
70b277 |
use_quit (int sig)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
#ifdef DONTEXIT
|
|
Packit |
70b277 |
int save = errno;
|
|
Packit |
70b277 |
write (1, "\n(interrupt) use quit to exit.\n", 31);
|
|
Packit |
70b277 |
signal (SIGINT, use_quit);
|
|
Packit |
70b277 |
errno = save;
|
|
Packit |
70b277 |
#else
|
|
Packit |
70b277 |
write (1, "\n(interrupt) Exiting bc.\n", 26);
|
|
Packit |
70b277 |
bc_exit(0);
|
|
Packit |
70b277 |
#endif
|
|
Packit |
70b277 |
}
|