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
54const char *progname;	/* basename of program invocation */
55
56static void
57bug_report_info DC_DECLVOID()
58{
59	printf("Email bug reports to:  bug-dc@gnu.org .\n");
60}
61
62static void
63show_version DC_DECLVOID()
64{
65	printf("dc (GNU %s %s) %s\n", PACKAGE, VERSION, DC_VERSION);
66	printf("\n%s\n\
67This is free software; see the source for copying conditions.  There is NO\n\
68warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,\n\
69to the extent permitted by law.\n", DC_COPYRIGHT);
70}
71
72/* your generic usage function */
73static void
74usage DC_DECLARG((f))
75	FILE *f DC_DECLEND
76{
77	fprintf(f, "\
78Usage: %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 */
91static char *
92r1bindex 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
103static void
104try_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
122int
123main 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}
184