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