]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/bc/bc/main.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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$
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 predefined math routines\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         case 0:
133           /* long options */
134           break;
135
136         default:
137           usage(argv[0]);
138           exit (1);
139         }
140     }
141
142   /* Add file names to a list of files to process. */
143   while (optind < argc)
144     {
145       temp = (file_node *) bc_malloc(sizeof(file_node));
146       temp->name = argv[optind];
147       temp->next = NULL;
148       if (last == NULL)
149         file_names = temp;
150       else
151         last->next = temp;
152       last = temp;
153       optind++;
154     }
155 }
156
157 /* The main program for bc. */
158 int
159 main (argc, argv)
160      int argc;
161      char *argv[];
162 {
163   char *env_value;
164   char *env_argv[30];
165   int   env_argc;
166   
167   /* Initialize many variables. */
168   compile_only = FALSE;
169   use_math = FALSE;
170   warn_not_std = FALSE;
171   std_only = FALSE;
172   if (isatty(0) && isatty(1)) 
173     interactive = TRUE;
174   else
175     interactive = FALSE;
176   quiet = FALSE;
177   file_names = NULL;
178
179 #ifdef HAVE_SETVBUF
180   /* attempt to simplify interaction with applications such as emacs */
181   (void) setvbuf(stdout, NULL, _IOLBF, 0);
182 #endif
183
184   /* Environment arguments. */
185   env_value = getenv ("BC_ENV_ARGS");
186   if (env_value != NULL)
187     {
188       env_argc = 1;
189       env_argv[0] = "BC_ENV_ARGS";
190       while (*env_value != 0)
191         {
192           if (*env_value != ' ')
193             {
194               env_argv[env_argc++] = env_value;
195               while (*env_value != ' ' && *env_value != 0)
196                 env_value++;
197               if (*env_value != 0)
198                 {
199                   *env_value = 0;
200                   env_value++;
201                 }
202             }
203           else
204             env_value++;
205         }
206       parse_args (env_argc, env_argv);
207     }
208
209   /* Command line arguments. */
210   parse_args (argc, argv);
211
212   /* Other environment processing. */
213   if (getenv ("POSIXLY_CORRECT") != NULL)
214     std_only = TRUE;
215
216   env_value = getenv ("BC_LINE_LENGTH");
217   if (env_value != NULL)
218     {
219       line_size = atoi (env_value);
220       if (line_size < 2)
221         line_size = 70;
222     }
223   else
224     line_size = 70;
225
226   /* Initialize the machine.  */
227   init_storage();
228   init_load();
229
230   /* Set up interrupts to print a message. */
231   if (interactive)
232     signal (SIGINT, use_quit);
233
234   /* Initialize the front end. */
235   init_tree();
236   init_gen ();
237   is_std_in = FALSE;
238   first_file = TRUE;
239   if (!open_new_file ())
240     exit (1);
241
242 #if defined(LIBEDIT)
243   if (interactive) {
244     /* Enable libedit support. */
245     edit = el_init ("bc", stdin, stdout, stderr);
246     hist = history_init();
247     el_set (edit, EL_EDITOR, "emacs");
248     el_set (edit, EL_HIST, history, hist);
249     el_set (edit, EL_PROMPT, null_prompt);
250     el_source (edit, NULL);
251     history (hist, &histev, H_SETSIZE, INT_MAX);
252   }
253 #endif
254
255 #if defined(READLINE)
256   if (interactive) {
257     /* Readline support.  Set both application name and input file. */
258     rl_readline_name = "bc";
259     rl_instream = stdin;
260     using_history ();
261   }
262 #endif
263
264   /* Do the parse. */
265   yyparse ();
266
267   /* End the compile only output with a newline. */
268   if (compile_only)
269     printf ("\n");
270
271   exit (0);
272 }
273
274
275 /* This is the function that opens all the files. 
276    It returns TRUE if the file was opened, otherwise
277    it returns FALSE. */
278
279 int
280 open_new_file ()
281 {
282   FILE *new_file;
283   file_node *temp;
284
285   /* Set the line number. */
286   line_no = 1;
287
288   /* Check to see if we are done. */
289   if (is_std_in) return (FALSE);
290
291   /* Open the other files. */
292   if (use_math && first_file)
293     {
294       /* Load the code from a precompiled version of the math libarary. */
295       extern char *libmath[];
296       char **mstr;
297       char tmp;
298       /* These MUST be in the order of first mention of each function.
299          That is why "a" comes before "c" even though "a" is defined after
300          after "c".  "a" is used in "s"! */
301       tmp = lookup ("e", FUNCT);
302       tmp = lookup ("l", FUNCT);
303       tmp = lookup ("s", FUNCT);
304       tmp = lookup ("a", FUNCT);
305       tmp = lookup ("c", FUNCT);
306       tmp = lookup ("j", FUNCT);
307       mstr = libmath;
308       while (*mstr) {
309            load_code (*mstr);
310            mstr++;
311       }
312     }
313   
314   /* One of the argv values. */
315   if (file_names != NULL)
316     {
317       new_file = fopen (file_names->name, "r");
318       if (new_file != NULL)
319         {
320           new_yy_file (new_file);
321           temp = file_names;
322           file_name  = temp->name;
323           file_names = temp->next;
324           free (temp);
325           return TRUE;
326         }
327       fprintf (stderr, "File %s is unavailable.\n", file_names->name);
328       exit (1);
329     }
330   
331   /* If we fall through to here, we should return stdin. */
332   new_yy_file (stdin);
333   is_std_in = TRUE;
334   return TRUE;
335 }
336
337
338 /* Set yyin to the new file. */
339
340 void
341 new_yy_file (file)
342      FILE *file;
343 {
344   if (!first_file) fclose (yyin);
345   yyin = file;
346   first_file = FALSE;
347 }
348
349
350 /* Message to use quit.  */
351
352 void
353 use_quit (sig)
354      int sig;
355 {
356   printf ("\n(interrupt) use quit to exit.\n");
357   signal (SIGINT, use_quit);
358 }