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