Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / contrib / bc / bc / main.c
CommitLineData
984263bc
MD
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 $
1de703da 30$DragonFly: src/contrib/bc/bc/Attic/main.c,v 1.2 2003/06/17 04:23:58 dillon Exp $
984263bc
MD
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. */
42static char first_file;
43
44/* Points to the last node in the file name list for easy adding. */
45static file_node *last = NULL;
46
47/* long option support */
48static 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
63void
64usage (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
77void
78parse_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. */
155int
156main (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
276int
277open_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
337void
338new_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
349void
350use_quit (sig)
351 int sig;
352{
353 printf ("\n(interrupt) use quit to exit.\n");
354 signal (SIGINT, use_quit);
355}