1*341df644Smaya /* $NetBSD: main.c,v 1.2 2017/04/18 04:35:18 maya Exp $ */
2ed857e95Sphil
3ed857e95Sphil /*
4ed857e95Sphil * Copyright (C) 1991-1994, 1997, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
5ed857e95Sphil * Copyright (C) 2016-2017 Philip A. Nelson.
6ed857e95Sphil * All rights reserved.
7ed857e95Sphil *
8ed857e95Sphil * Redistribution and use in source and binary forms, with or without
9ed857e95Sphil * modification, are permitted provided that the following conditions
10ed857e95Sphil * are met:
11ed857e95Sphil *
12ed857e95Sphil * 1. Redistributions of source code must retain the above copyright
13ed857e95Sphil * notice, this list of conditions and the following disclaimer.
14ed857e95Sphil * 2. Redistributions in binary form must reproduce the above copyright
15ed857e95Sphil * notice, this list of conditions and the following disclaimer in the
16ed857e95Sphil * documentation and/or other materials provided with the distribution.
17ed857e95Sphil * 3. The names Philip A. Nelson and Free Software Foundation may not be
18ed857e95Sphil * used to endorse or promote products derived from this software
19ed857e95Sphil * without specific prior written permission.
20ed857e95Sphil *
21ed857e95Sphil * THIS SOFTWARE IS PROVIDED BY PHILIP A. NELSON ``AS IS'' AND ANY EXPRESS OR
22ed857e95Sphil * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23ed857e95Sphil * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24ed857e95Sphil * IN NO EVENT SHALL PHILIP A. NELSON OR THE FREE SOFTWARE FOUNDATION BE
25ed857e95Sphil * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26ed857e95Sphil * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27ed857e95Sphil * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28ed857e95Sphil * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29ed857e95Sphil * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30ed857e95Sphil * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31ed857e95Sphil * THE POSSIBILITY OF SUCH DAMAGE.
32ed857e95Sphil */
33ed857e95Sphil
34ed857e95Sphil /* main.c: The main program for bc. */
35ed857e95Sphil
36ed857e95Sphil #include "bcdefs.h"
37ed857e95Sphil #include <signal.h>
38ed857e95Sphil #include <errno.h>
39ed857e95Sphil #include "proto.h"
40ed857e95Sphil #include "getopt.h"
41ed857e95Sphil
42ed857e95Sphil
43ed857e95Sphil /* Variables for processing multiple files. */
44ed857e95Sphil static char first_file;
45ed857e95Sphil
46ed857e95Sphil /* Points to the last node in the file name list for easy adding. */
47ed857e95Sphil static file_node *last = NULL;
48ed857e95Sphil
49ed857e95Sphil #if defined(LIBEDIT)
50ed857e95Sphil /* The prompt for libedit. */
51ed857e95Sphil char el_pmtchars[] = "";
52ed857e95Sphil static char *el_pmtfunc(void);
el_pmtfunc(void)53ed857e95Sphil static char *el_pmtfunc(void) { return el_pmtchars; }
54ed857e95Sphil #endif
55ed857e95Sphil
56ed857e95Sphil /* long option support */
57ed857e95Sphil static struct option long_options[] =
58ed857e95Sphil {
59ed857e95Sphil {"compile", 0, &compile_only, TRUE},
60ed857e95Sphil {"help", 0, 0, 'h'},
61ed857e95Sphil {"interactive", 0, 0, 'i'},
62ed857e95Sphil {"mathlib", 0, &use_math, TRUE},
63ed857e95Sphil {"quiet", 0, &quiet, TRUE},
64ed857e95Sphil {"standard", 0, &std_only, TRUE},
65ed857e95Sphil {"version", 0, 0, 'v'},
66ed857e95Sphil {"warn", 0, &warn_not_std, TRUE},
67ed857e95Sphil
68ed857e95Sphil {0, 0, 0, 0}
69ed857e95Sphil };
70ed857e95Sphil
71ed857e95Sphil
72ed857e95Sphil static void
usage(const char * progname)73ed857e95Sphil usage (const char *progname)
74ed857e95Sphil {
75ed857e95Sphil printf ("usage: %s [options] [file ...]\n%s%s%s%s%s%s%s", progname,
76ed857e95Sphil " -h --help print this usage and exit\n",
77ed857e95Sphil " -i --interactive force interactive mode\n",
78ed857e95Sphil " -l --mathlib use the predefined math routines\n",
79ed857e95Sphil " -q --quiet don't print initial banner\n",
80ed857e95Sphil " -s --standard non-standard bc constructs are errors\n",
81ed857e95Sphil " -w --warn warn about non-standard bc constructs\n",
82ed857e95Sphil " -v --version print version information and exit\n");
83ed857e95Sphil }
84ed857e95Sphil
85ed857e95Sphil
86ed857e95Sphil static void
parse_args(int argc,char ** argv)87ed857e95Sphil parse_args (int argc, char **argv)
88ed857e95Sphil {
89ed857e95Sphil int optch;
90ed857e95Sphil int long_index;
91ed857e95Sphil file_node *temp;
92ed857e95Sphil
93ed857e95Sphil /* Force getopt to initialize. Depends on GNU getopt. */
94ed857e95Sphil optind = 0;
95ed857e95Sphil
96ed857e95Sphil /* Parse the command line */
97ed857e95Sphil while (1)
98ed857e95Sphil {
99ed857e95Sphil optch = getopt_long (argc, argv, "chilqswv", long_options, &long_index);
100ed857e95Sphil
101ed857e95Sphil if (optch == EOF) /* End of arguments. */
102ed857e95Sphil break;
103ed857e95Sphil
104ed857e95Sphil switch (optch)
105ed857e95Sphil {
106ed857e95Sphil case 0: /* Long option setting a var. */
107ed857e95Sphil break;
108ed857e95Sphil
109ed857e95Sphil case 'c': /* compile only */
110ed857e95Sphil compile_only = TRUE;
111ed857e95Sphil break;
112ed857e95Sphil
113ed857e95Sphil case 'h': /* help */
114ed857e95Sphil usage(argv[0]);
115ed857e95Sphil bc_exit (0);
116*341df644Smaya /* NOTREACHED */
117ed857e95Sphil
118ed857e95Sphil case 'i': /* force interactive */
119ed857e95Sphil interactive = TRUE;
120ed857e95Sphil break;
121ed857e95Sphil
122ed857e95Sphil case 'l': /* math lib */
123ed857e95Sphil use_math = TRUE;
124ed857e95Sphil break;
125ed857e95Sphil
126ed857e95Sphil case 'q': /* quiet mode */
127ed857e95Sphil quiet = TRUE;
128ed857e95Sphil break;
129ed857e95Sphil
130ed857e95Sphil case 's': /* Non standard features give errors. */
131ed857e95Sphil std_only = TRUE;
132ed857e95Sphil break;
133ed857e95Sphil
134ed857e95Sphil case 'v': /* Print the version. */
135ed857e95Sphil show_bc_version ();
136ed857e95Sphil bc_exit (0);
137*341df644Smaya /* NOTREACHED */
138ed857e95Sphil
139ed857e95Sphil case 'w': /* Non standard features give warnings. */
140ed857e95Sphil warn_not_std = TRUE;
141ed857e95Sphil break;
142ed857e95Sphil
143ed857e95Sphil default:
144ed857e95Sphil usage(argv[0]);
145ed857e95Sphil bc_exit (1);
146ed857e95Sphil }
147ed857e95Sphil }
148ed857e95Sphil
149ed857e95Sphil #ifdef QUIET
150ed857e95Sphil quiet = TRUE;
151ed857e95Sphil #endif
152ed857e95Sphil
153ed857e95Sphil /* Add file names to a list of files to process. */
154ed857e95Sphil while (optind < argc)
155ed857e95Sphil {
156ed857e95Sphil temp = bc_malloc(sizeof(file_node));
157ed857e95Sphil temp->name = argv[optind];
158ed857e95Sphil temp->next = NULL;
159ed857e95Sphil if (last == NULL)
160ed857e95Sphil file_names = temp;
161ed857e95Sphil else
162ed857e95Sphil last->next = temp;
163ed857e95Sphil last = temp;
164ed857e95Sphil optind++;
165ed857e95Sphil }
166ed857e95Sphil }
167ed857e95Sphil
168ed857e95Sphil /* The main program for bc. */
169ed857e95Sphil int
main(int argc,char ** argv)170ed857e95Sphil main (int argc, char **argv)
171ed857e95Sphil {
172ed857e95Sphil char *env_value;
173ed857e95Sphil char *env_argv[30];
174ed857e95Sphil int env_argc;
175ed857e95Sphil
176ed857e95Sphil /* Interactive? */
177ed857e95Sphil if (isatty(0) && isatty(1))
178ed857e95Sphil interactive = TRUE;
179ed857e95Sphil
180ed857e95Sphil #ifdef HAVE_SETVBUF
181ed857e95Sphil /* attempt to simplify interaction with applications such as emacs */
182ed857e95Sphil (void) setvbuf(stdout, NULL, _IOLBF, 0);
183ed857e95Sphil #endif
184ed857e95Sphil
185ed857e95Sphil /* Environment arguments. */
186ed857e95Sphil env_value = getenv ("BC_ENV_ARGS");
187ed857e95Sphil if (env_value != NULL)
188ed857e95Sphil {
189ed857e95Sphil env_argc = 1;
190ed857e95Sphil env_argv[0] = strdup("BC_ENV_ARGS");
191ed857e95Sphil while (*env_value != 0)
192ed857e95Sphil {
193ed857e95Sphil if (*env_value != ' ')
194ed857e95Sphil {
195ed857e95Sphil env_argv[env_argc++] = env_value;
196ed857e95Sphil while (*env_value != ' ' && *env_value != 0)
197ed857e95Sphil env_value++;
198ed857e95Sphil if (*env_value != 0)
199ed857e95Sphil {
200ed857e95Sphil *env_value = 0;
201ed857e95Sphil env_value++;
202ed857e95Sphil }
203ed857e95Sphil }
204ed857e95Sphil else
205ed857e95Sphil env_value++;
206ed857e95Sphil }
207ed857e95Sphil parse_args (env_argc, env_argv);
208ed857e95Sphil }
209ed857e95Sphil
210ed857e95Sphil /* Command line arguments. */
211ed857e95Sphil parse_args (argc, argv);
212ed857e95Sphil
213ed857e95Sphil /* Other environment processing. */
214ed857e95Sphil if (getenv ("POSIXLY_CORRECT") != NULL)
215ed857e95Sphil std_only = TRUE;
216ed857e95Sphil
217ed857e95Sphil env_value = getenv ("BC_LINE_LENGTH");
218ed857e95Sphil if (env_value != NULL)
219ed857e95Sphil {
220ed857e95Sphil line_size = atoi (env_value);
221ed857e95Sphil if (line_size < 3 && line_size != 0)
222ed857e95Sphil line_size = 70;
223ed857e95Sphil }
224ed857e95Sphil else
225ed857e95Sphil line_size = 70;
226ed857e95Sphil
227ed857e95Sphil /* Initialize the machine. */
228ed857e95Sphil init_storage();
229ed857e95Sphil init_load();
230ed857e95Sphil
231ed857e95Sphil /* Set up interrupts to print a message. */
232ed857e95Sphil if (interactive)
233ed857e95Sphil signal (SIGINT, use_quit);
234ed857e95Sphil
235ed857e95Sphil /* Initialize the front end. */
236ed857e95Sphil init_tree();
237ed857e95Sphil init_gen ();
238ed857e95Sphil is_std_in = FALSE;
239ed857e95Sphil first_file = TRUE;
240ed857e95Sphil if (!open_new_file ())
241ed857e95Sphil bc_exit (1);
242ed857e95Sphil
243ed857e95Sphil #if defined(LIBEDIT)
244ed857e95Sphil if (interactive) {
245ed857e95Sphil /* Enable libedit support. */
246ed857e95Sphil edit = el_init ("bc", stdin, stdout, stderr);
247ed857e95Sphil hist = history_init();
248ed857e95Sphil el_set (edit, EL_EDITOR, "emacs");
249ed857e95Sphil el_set (edit, EL_HIST, history, hist);
250ed857e95Sphil el_set (edit, EL_PROMPT, el_pmtfunc);
251ed857e95Sphil el_source (edit, NULL);
252ed857e95Sphil history (hist, &histev, H_SETSIZE, INT_MAX);
253ed857e95Sphil }
254ed857e95Sphil #endif
255ed857e95Sphil
256ed857e95Sphil #if defined(READLINE)
257ed857e95Sphil if (interactive) {
258ed857e95Sphil /* Readline support. Set both application name and input file. */
259ed857e95Sphil rl_readline_name = "bc";
260ed857e95Sphil rl_instream = stdin;
261ed857e95Sphil using_history ();
262ed857e95Sphil }
263ed857e95Sphil #endif
264ed857e95Sphil
265ed857e95Sphil /* Do the parse. */
266ed857e95Sphil yyparse ();
267ed857e95Sphil
268ed857e95Sphil /* End the compile only output with a newline. */
269ed857e95Sphil if (compile_only)
270ed857e95Sphil printf ("\n");
271ed857e95Sphil
272ed857e95Sphil bc_exit (0);
273ed857e95Sphil }
274ed857e95Sphil
275ed857e95Sphil
276ed857e95Sphil /* This is the function that opens all the files.
277ed857e95Sphil It returns TRUE if the file was opened, otherwise
278ed857e95Sphil it returns FALSE. */
279ed857e95Sphil
280ed857e95Sphil int
open_new_file(void)281ed857e95Sphil open_new_file (void)
282ed857e95Sphil {
283ed857e95Sphil FILE *new_file;
284ed857e95Sphil file_node *temp;
285ed857e95Sphil
286ed857e95Sphil /* Set the line number. */
287ed857e95Sphil line_no = 1;
288ed857e95Sphil
289ed857e95Sphil /* Check to see if we are done. */
290ed857e95Sphil if (is_std_in) return (FALSE);
291ed857e95Sphil
292ed857e95Sphil /* Open the other files. */
293ed857e95Sphil if (use_math && first_file)
294ed857e95Sphil {
295ed857e95Sphil /* Load the code from a precompiled version of the math libarary. */
296ed857e95Sphil CONST char **mstr;
297ed857e95Sphil
298ed857e95Sphil /* These MUST be in the order of first mention of each function.
299ed857e95Sphil That is why "a" comes before "c" even though "a" is defined after
300ed857e95Sphil after "c". "a" is used in "s"! */
301ed857e95Sphil (void) lookup (strdup("e"), FUNCT);
302ed857e95Sphil (void) lookup (strdup("l"), FUNCT);
303ed857e95Sphil (void) lookup (strdup("s"), FUNCT);
304ed857e95Sphil (void) lookup (strdup("a"), FUNCT);
305ed857e95Sphil (void) lookup (strdup("c"), FUNCT);
306ed857e95Sphil (void) lookup (strdup("j"), FUNCT);
307ed857e95Sphil mstr = libmath;
308ed857e95Sphil while (*mstr) {
309ed857e95Sphil load_code (*mstr);
310ed857e95Sphil mstr++;
311ed857e95Sphil }
312ed857e95Sphil }
313ed857e95Sphil
314ed857e95Sphil /* One of the argv values. */
315ed857e95Sphil if (file_names != NULL)
316ed857e95Sphil {
317ed857e95Sphil new_file = fopen (file_names->name, "r");
318ed857e95Sphil if (new_file != NULL)
319ed857e95Sphil {
320ed857e95Sphil new_yy_file (new_file);
321ed857e95Sphil temp = file_names;
322ed857e95Sphil file_name = temp->name;
323ed857e95Sphil file_names = temp->next;
324ed857e95Sphil free (temp);
325ed857e95Sphil return TRUE;
326ed857e95Sphil }
327ed857e95Sphil fprintf (stderr, "File %s is unavailable.\n", file_names->name);
328ed857e95Sphil bc_exit (1);
329ed857e95Sphil }
330ed857e95Sphil
331ed857e95Sphil /* If we fall through to here, we should return stdin. */
332ed857e95Sphil new_yy_file (stdin);
333ed857e95Sphil is_std_in = TRUE;
334ed857e95Sphil return TRUE;
335ed857e95Sphil }
336ed857e95Sphil
337ed857e95Sphil
338ed857e95Sphil /* Set yyin to the new file. */
339ed857e95Sphil
340ed857e95Sphil void
new_yy_file(FILE * file)341ed857e95Sphil new_yy_file (FILE *file)
342ed857e95Sphil {
343ed857e95Sphil if (!first_file) fclose (yyin);
344ed857e95Sphil yyin = file;
345ed857e95Sphil first_file = FALSE;
346ed857e95Sphil }
347ed857e95Sphil
348ed857e95Sphil
349ed857e95Sphil /* Message to use quit. */
350ed857e95Sphil
351ed857e95Sphil void
use_quit(int sig)352ed857e95Sphil use_quit (int sig)
353ed857e95Sphil {
354ed857e95Sphil #ifdef DONTEXIT
355ed857e95Sphil int save = errno;
356ed857e95Sphil write (1, "\n(interrupt) use quit to exit.\n", 31);
357ed857e95Sphil signal (SIGINT, use_quit);
358ed857e95Sphil errno = save;
359ed857e95Sphil #else
360ed857e95Sphil write (1, "\n(interrupt) Exiting bc.\n", 26);
361ed857e95Sphil bc_exit(0);
362ed857e95Sphil #endif
363ed857e95Sphil }
364