Blame bc/main.c

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
}