~ubuntu-branches/ubuntu/maverick/bc/maverick

« back to all changes in this revision

Viewing changes to bc/main.c

  • Committer: Bazaar Package Importer
  • Author(s): Dirk Eddelbuettel
  • Date: 2002-04-13 11:33:49 UTC
  • Revision ID: james.westby@ubuntu.com-20020413113349-hl2r1t730b91ov68
Tags: upstream-1.06
ImportĀ upstreamĀ versionĀ 1.06

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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. */
 
39
static char first_file;
 
40
 
 
41
/* Points to the last node in the file name list for easy adding. */
 
42
static file_node *last = NULL;
 
43
 
 
44
/* long option support */
 
45
static 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
 
 
60
void
 
61
usage (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
 
 
74
void
 
75
parse_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. */
 
152
int
 
153
main (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
 
 
273
int
 
274
open_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
 
 
334
void
 
335
new_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
 
 
346
void
 
347
use_quit (sig)
 
348
     int sig;
 
349
{
 
350
  printf ("\n(interrupt) use quit to exit.\n");
 
351
  signal (SIGINT, use_quit);
 
352
}