* Sync comment with code's reality.
[dragonfly.git] / contrib / bc / dc / dc.c
1 /* 
2  * implement the "dc" Desk Calculator language.
3  *
4  * Copyright (C) 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, or (at your option)
9  * 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; if not, you can either send email to this
18  * program's author (see below) or write to:
19  *   The Free Software Foundation, Inc.
20  *   59 Temple Place, Suite 330
21  *   Boston, MA 02111 USA
22  */
23
24 /* Written with strong hiding of implementation details
25  * in their own specialized modules.
26  */
27 /* This module contains the argument processing/main functions.
28  */
29
30 #include "config.h"
31
32 #include <stdio.h>
33 #ifdef HAVE_STDLIB_H
34 # include <stdlib.h>
35 #endif
36 #ifdef HAVE_STRING_H
37 # include <string.h>
38 #else
39 # ifdef HAVE_STRINGS_H
40 #  include <strings.h>
41 # endif
42 #endif
43 #include <getopt.h>
44 #include "dc.h"
45 #include "dc-proto.h"
46
47 #ifndef EXIT_SUCCESS    /* C89 <stdlib.h> */
48 # define EXIT_SUCCESS   0
49 #endif
50 #ifndef EXIT_FAILURE    /* C89 <stdlib.h> */
51 # define EXIT_FAILURE   1
52 #endif
53
54 const char *progname;   /* basename of program invocation */
55
56 static void
57 bug_report_info DC_DECLVOID()
58 {
59         printf("Email bug reports to:  bug-dc@gnu.org .\n");
60 }
61
62 static void
63 show_version DC_DECLVOID()
64 {
65         printf("dc (GNU %s %s) %s\n", PACKAGE, VERSION, DC_VERSION);
66         printf("\n%s\n\
67 This is free software; see the source for copying conditions.  There is NO\n\
68 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,\n\
69 to the extent permitted by law.\n", DC_COPYRIGHT); 
70 }
71
72 /* your generic usage function */
73 static void
74 usage DC_DECLARG((f))
75         FILE *f DC_DECLEND
76 {
77         fprintf(f, "\
78 Usage: %s [OPTION] [file ...]\n\
79   -e, --expression=EXPR    evaluate expression\n\
80   -f, --file=FILE          evaluate contents of file\n\
81   -h, --help               display this help and exit\n\
82   -V, --version            output version information and exit\n\
83 \n\
84 ", progname);
85         bug_report_info();
86 }
87
88 /* returns a pointer to one past the last occurance of c in s,
89  * or s if c does not occur in s.
90  */
91 static char *
92 r1bindex DC_DECLARG((s, c))
93         char *s DC_DECLSEP
94         int  c DC_DECLEND
95 {
96         char *p = strrchr(s, c);
97
98         if (!p)
99                 return s;
100         return p + 1;
101 }
102
103 static void
104 try_file(const char *filename)
105 {
106         FILE *input;
107
108         if (strcmp(filename, "-") == 0) {
109                 input = stdin;
110         } else if ( !(input=fopen(filename, "r")) ) {
111                 fprintf(stderr, "Could not open file ");
112                 perror(filename);
113                 exit(EXIT_FAILURE);
114         }
115         if (dc_evalfile(input))
116                 exit(EXIT_FAILURE);
117         if (input != stdin)
118                 fclose(input);
119 }
120
121 \f
122 int
123 main DC_DECLARG((argc, argv))
124         int  argc DC_DECLSEP
125         char **argv DC_DECLEND
126 {
127         static struct option const long_opts[] = {
128                 {"expression", required_argument, NULL, 'e'},
129                 {"file", required_argument, NULL, 'f'},
130                 {"help", no_argument, NULL, 'h'},
131                 {"version", no_argument, NULL, 'V'},
132                 {NULL, 0, NULL, 0}
133         };
134         int did_eval = 0;
135         int c;
136
137         progname = r1bindex(*argv, '/');
138 #ifdef HAVE_SETVBUF
139         /* attempt to simplify interaction with applications such as emacs */
140         (void) setvbuf(stdout, NULL, _IOLBF, 0);
141 #endif
142         dc_math_init();
143         dc_string_init();
144         dc_register_init();
145         dc_array_init();
146
147         while ((c = getopt_long(argc, argv, "hVe:f:", long_opts, (int *)0)) != EOF) {
148                 switch (c) {
149                 case 'e':
150                         {       dc_data string = dc_makestring(optarg, strlen(optarg));
151                                 if (dc_evalstr(string))
152                                         return EXIT_SUCCESS;
153                                 dc_free_str(&string.v.string);
154                                 did_eval = 1;
155                         }
156                         break;
157                 case 'f':
158                         try_file(optarg);
159                         did_eval = 1;
160                         break;
161                 case 'h':
162                         usage(stdout);
163                         return EXIT_SUCCESS;
164                 case 'V':
165                         show_version();
166                         return EXIT_SUCCESS;
167                 default:
168                         usage(stderr);
169                         return EXIT_FAILURE;
170                 }
171         }
172
173         for (; optind < argc; ++optind) {
174                 try_file(argv[optind]);
175                 did_eval = 1;
176         }
177         if (!did_eval) {
178                 /* if no -e commands and no command files, then eval stdin */
179                 if (dc_evalfile(stdin))
180                         return EXIT_FAILURE;
181         }
182         return EXIT_SUCCESS;
183 }