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 <sys/types.h> 45#include <sys/stat.h> 46#include <errno.h> 47#include "dc.h" 48#include "dc-proto.h" 49 50#ifndef EXIT_SUCCESS /* C89 <stdlib.h> */ 51# define EXIT_SUCCESS 0 52#endif 53#ifndef EXIT_FAILURE /* C89 <stdlib.h> */ 54# define EXIT_FAILURE 1 55#endif 56 57const char *progname; /* basename of program invocation */ 58 59static void 60bug_report_info DC_DECLVOID() 61{ 62 printf("Email bug reports to: bug-dc@gnu.org .\n"); 63} 64 65static void 66show_version DC_DECLVOID() 67{ 68 printf("dc (GNU %s %s) %s\n", PACKAGE, VERSION, DC_VERSION); 69 printf("\n%s\n\ 70This is free software; see the source for copying conditions. There is NO\n\ 71warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,\n\ 72to the extent permitted by law.\n", DC_COPYRIGHT); 73} 74 75/* your generic usage function */ 76static void 77usage DC_DECLARG((f)) 78 FILE *f DC_DECLEND 79{ 80 fprintf(f, "\ 81Usage: %s [OPTION] [file ...]\n\ 82 -e, --expression=EXPR evaluate expression\n\ 83 -f, --file=FILE evaluate contents of file\n\ 84 -h, --help display this help and exit\n\ 85 -V, --version output version information and exit\n\ 86\n\ 87", progname); 88 bug_report_info(); 89} 90 91/* returns a pointer to one past the last occurance of c in s, 92 * or s if c does not occur in s. 93 */ 94static char * 95r1bindex DC_DECLARG((s, c)) 96 char *s DC_DECLSEP 97 int c DC_DECLEND 98{ 99 char *p = strrchr(s, c); 100 101 if (!p) 102 return s; 103 return p + 1; 104} 105 106static void 107try_file(const char *filename) 108{ 109 FILE *input; 110 111 if (strcmp(filename, "-") == 0) { 112 input = stdin; 113 } else { 114 struct stat sb; 115 if (stat(filename, &sb) < 0) { 116 fprintf(stderr, "Cannot stat %s: %s\n", 117 filename, strerror(errno)); 118 exit(EXIT_FAILURE); 119 } 120 if (S_ISDIR(sb.st_mode)) { 121 fprintf(stderr, "Cannot use directory as input!\n"); 122 exit(EXIT_FAILURE); 123 } 124 if ( !(input=fopen(filename, "r")) ) { 125 fprintf(stderr, "Could not open file "); 126 perror(filename); 127 exit(EXIT_FAILURE); 128 } 129 } 130 if (dc_evalfile(input)) 131 exit(EXIT_FAILURE); 132 if (input != stdin) 133 fclose(input); 134} 135 136 137int 138main DC_DECLARG((argc, argv)) 139 int argc DC_DECLSEP 140 char **argv DC_DECLEND 141{ 142 static struct option const long_opts[] = { 143 {"expression", required_argument, NULL, 'e'}, 144 {"file", required_argument, NULL, 'f'}, 145 {"help", no_argument, NULL, 'h'}, 146 {"version", no_argument, NULL, 'V'}, 147 {NULL, 0, NULL, 0} 148 }; 149 int did_eval = 0; 150 int c; 151 152 progname = r1bindex(*argv, '/'); 153#ifdef HAVE_SETVBUF 154 /* attempt to simplify interaction with applications such as emacs */ 155 (void) setvbuf(stdout, NULL, _IOLBF, 0); 156#endif 157 dc_math_init(); 158 dc_string_init(); 159 dc_register_init(); 160 dc_array_init(); 161 162 while ((c = getopt_long(argc, argv, "hVe:f:", long_opts, (int *)0)) != EOF) { 163 switch (c) { 164 case 'e': 165 { dc_data string = dc_makestring(optarg, strlen(optarg)); 166 if (dc_evalstr(string)) 167 return EXIT_SUCCESS; 168 dc_free_str(&string.v.string); 169 did_eval = 1; 170 } 171 break; 172 case 'f': 173 try_file(optarg); 174 did_eval = 1; 175 break; 176 case 'h': 177 usage(stdout); 178 return EXIT_SUCCESS; 179 case 'V': 180 show_version(); 181 return EXIT_SUCCESS; 182 default: 183 usage(stderr); 184 return EXIT_FAILURE; 185 } 186 } 187 188 for (; optind < argc; ++optind) { 189 try_file(argv[optind]); 190 did_eval = 1; 191 } 192 if (!did_eval) { 193 /* if no -e commands and no command files, then eval stdin */ 194 if (dc_evalfile(stdin)) 195 return EXIT_FAILURE; 196 } 197 return EXIT_SUCCESS; 198} 199