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