Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / bc / bc / main.c
1 /* main.c: The main program for bc.  */
2
3 /*  This file is part of GNU bc.
4     Copyright (C) 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License , or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; see the file COPYING.  If not, write to
18       The Free Software Foundation, Inc.
19       59 Temple Place, Suite 330
20       Boston, MA 02111 USA
21
22     You may contact the author by:
23        e-mail:  philnelson@acm.org
24       us-mail:  Philip A. Nelson
25                 Computer Science Department, 9062
26                 Western Washington University
27                 Bellingham, WA 98226-9062
28
29 $FreeBSD: src/contrib/bc/bc/main.c,v 1.4.2.1 2001/03/04 09:34:54 kris Exp $
30        
31 *************************************************************************/
32
33 #include "bcdefs.h"
34 #include <signal.h>
35 #include "global.h"
36 #include "proto.h"
37 #include "getopt.h"
38
39
40 /* Variables for processing multiple files. */
41 static char first_file;
42
43 /* Points to the last node in the file name list for easy adding. */
44 static file_node *last = NULL;
45
46 /* long option support */
47 static struct option long_options[] =
48 {
49   {"compile",  0, &compile_only, TRUE},
50   {"help",     0, 0,             'h'},
51   {"interactive", 0, 0,          'i'},
52   {"mathlib",  0, &use_math,     TRUE},
53   {"quiet",    0, &quiet,        TRUE},
54   {"standard", 0, &std_only,     TRUE},
55   {"version",  0, 0,             'v'},
56   {"warn",     0, &warn_not_std, TRUE},
57
58   {0, 0, 0, 0}
59 };
60
61
62 void
63 usage (char *progname)
64 {
65   printf ("usage: %s [options] [file ...]\n%s%s%s%s%s%s%s", progname,
66           "  -h  --help         print this usage and exit\n",
67           "  -i  --interactive  force interactive mode\n",
68           "  -l  --mathlib      use the predefine math routnes\n",
69           "  -q  --quiet        don't print initial banner\n",
70           "  -s  --standard     non-standard bc constructs are errors\n",
71           "  -w  --warn         warn about non-standard bc constructs\n",
72           "  -v  --version      print version information and exit\n");
73 }
74
75
76 void
77 parse_args (argc, argv)
78      int argc;
79      char **argv;
80 {
81   int optch;
82   int long_index;
83   file_node *temp;
84
85   /* Force getopt to initialize.  Depends on GNU getopt. */
86   optind = 0;
87
88   /* Parse the command line */
89   while (1)
90     {
91       optch = getopt_long (argc, argv, "chilqswv", long_options, &long_index);
92
93       if (optch == EOF)  /* End of arguments. */
94         break;
95
96       switch (optch)
97         {
98         case 'c':  /* compile only */
99           compile_only = TRUE;
100           break;
101
102         case 'h':  /* help */
103           usage(argv[0]);
104           exit (0);
105           break;
106
107         case 'i':  /* force interactive */
108           interactive = TRUE;
109           break;
110
111         case 'l':  /* math lib */
112           use_math = TRUE;
113           break;
114
115         case 'q':  /* quiet mode */
116           quiet = TRUE;
117           break;
118
119         case 's':  /* Non standard features give errors. */
120           std_only = TRUE;
121           break;
122
123         case 'v':  /* Print the version. */
124           show_bc_version ();
125           exit (0);
126           break;
127
128         case 'w':  /* Non standard features give warnings. */
129           warn_not_std = TRUE;
130           break;
131
132         default:
133           usage(argv[0]);
134           exit (1);
135         }
136     }
137
138   /* Add file names to a list of files to process. */
139   while (optind < argc)
140     {
141       temp = (file_node *) bc_malloc(sizeof(file_node));
142       temp->name = argv[optind];
143       temp->next = NULL;
144       if (last == NULL)
145         file_names = temp;
146       else
147         last->next = temp;
148       last = temp;
149       optind++;
150     }
151 }
152
153 /* The main program for bc. */
154 int
155 main (argc, argv)
156      int argc;
157      char *argv[];
158 {
159   char *env_value;
160   char *env_argv[30];
161   int   env_argc;
162   
163   /* Initialize many variables. */
164   compile_only = FALSE;
165   use_math = FALSE;
166   warn_not_std = FALSE;
167   std_only = FALSE;
168   if (isatty(0) && isatty(1)) 
169     interactive = TRUE;
170   else
171     interactive = FALSE;
172   quiet = FALSE;
173   file_names = NULL;
174
175 #ifdef HAVE_SETVBUF
176   /* attempt to simplify interaction with applications such as emacs */
177   (void) setvbuf(stdout, NULL, _IOLBF, 0);
178 #endif
179
180   /* Environment arguments. */
181   env_value = getenv ("BC_ENV_ARGS");
182   if (env_value != NULL)
183     {
184       env_argc = 1;
185       env_argv[0] = "BC_ENV_ARGS";
186       while (*env_value != 0)
187         {
188           if (*env_value != ' ')
189             {
190               env_argv[env_argc++] = env_value;
191               while (*env_value != ' ' && *env_value != 0)
192                 env_value++;
193               if (*env_value != 0)
194                 {
195                   *env_value = 0;
196                   env_value++;
197                 }
198             }
199           else
200             env_value++;
201         }
202       parse_args (env_argc, env_argv);
203     }
204
205   /* Command line arguments. */
206   parse_args (argc, argv);
207
208   /* Other environment processing. */
209   if (getenv ("POSIXLY_CORRECT") != NULL)
210     std_only = TRUE;
211
212   env_value = getenv ("BC_LINE_LENGTH");
213   if (env_value != NULL)
214     {
215       line_size = atoi (env_value);
216       if (line_size < 2)
217         line_size = 70;
218     }
219   else
220     line_size = 70;
221
222   /* Initialize the machine.  */
223   init_storage();
224   init_load();
225
226   /* Set up interrupts to print a message. */
227   if (interactive)
228     signal (SIGINT, use_quit);
229
230   /* Initialize the front end. */
231   init_tree();
232   init_gen ();
233   is_std_in = FALSE;
234   first_file = TRUE;
235   if (!open_new_file ())
236     exit (1);
237
238 #if defined(LIBEDIT)
239   if (interactive) {
240     /* Enable libedit support. */
241     edit = el_init ("bc", stdin, stdout, stderr);
242     hist = history_init();
243     el_set (edit, EL_EDITOR, "emacs");
244     el_set (edit, EL_HIST, history, hist);
245     el_set (edit, EL_PROMPT, null_prompt);
246     el_source (edit, NULL);
247     history (hist, &histev, H_SETSIZE, INT_MAX);
248   }
249 #endif
250
251 #if defined(READLINE)
252   if (interactive) {
253     /* Readline support.  Set both application name and input file. */
254     rl_readline_name = "bc";
255     rl_instream = stdin;
256     using_history ();
257   }
258 #endif
259
260   /* Do the parse. */
261   yyparse ();
262
263   /* End the compile only output with a newline. */
264   if (compile_only)
265     printf ("\n");
266
267   exit (0);
268 }
269
270
271 /* This is the function that opens all the files. 
272    It returns TRUE if the file was opened, otherwise
273    it returns FALSE. */
274
275 int
276 open_new_file ()
277 {
278   FILE *new_file;
279   file_node *temp;
280
281   /* Set the line number. */
282   line_no = 1;
283
284   /* Check to see if we are done. */
285   if (is_std_in) return (FALSE);
286
287   /* Open the other files. */
288   if (use_math && first_file)
289     {
290       /* Load the code from a precompiled version of the math libarary. */
291       extern char *libmath[];
292       char **mstr;
293       char tmp;
294       /* These MUST be in the order of first mention of each function.
295          That is why "a" comes before "c" even though "a" is defined after
296          after "c".  "a" is used in "s"! */
297       tmp = lookup ("e", FUNCT);
298       tmp = lookup ("l", FUNCT);
299       tmp = lookup ("s", FUNCT);
300       tmp = lookup ("a", FUNCT);
301       tmp = lookup ("c", FUNCT);
302       tmp = lookup ("j", FUNCT);
303       mstr = libmath;
304       while (*mstr) {
305            load_code (*mstr);
306            mstr++;
307       }
308     }
309   
310   /* One of the argv values. */
311   if (file_names != NULL)
312     {
313       new_file = fopen (file_names->name, "r");
314       if (new_file != NULL)
315         {
316           new_yy_file (new_file);
317           temp = file_names;
318           file_name  = temp->name;
319           file_names = temp->next;
320           free (temp);
321           return TRUE;
322         }
323       fprintf (stderr, "File %s is unavailable.\n", file_names->name);
324       exit (1);
325     }
326   
327   /* If we fall through to here, we should return stdin. */
328   new_yy_file (stdin);
329   is_std_in = TRUE;
330   return TRUE;
331 }
332
333
334 /* Set yyin to the new file. */
335
336 void
337 new_yy_file (file)
338      FILE *file;
339 {
340   if (!first_file) fclose (yyin);
341   yyin = file;
342   first_file = FALSE;
343 }
344
345
346 /* Message to use quit.  */
347
348 void
349 use_quit (sig)
350      int sig;
351 {
352   printf ("\n(interrupt) use quit to exit.\n");
353   signal (SIGINT, use_quit);
354 }