diff options
Diffstat (limited to 'dc/dc.c')
-rw-r--r-- | dc/dc.c | 172 |
1 files changed, 154 insertions, 18 deletions
@@ -1,7 +1,7 @@ -/* +/* * implement the "dc" Desk Calculator language. * - * Copyright (C) 1994, 1997, 1998, 2000 Free Software Foundation, Inc. + * Copyright (C) 1994, 1997, 1998, 2000, 2003, 2006 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,8 +17,8 @@ * along with this program; if not, you can either send email to this * program's author (see below) or write to: * The Free Software Foundation, Inc. - * 59 Temple Place, Suite 330 - * Boston, MA 02111 USA + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA */ /* Written with strong hiding of implementation details @@ -40,6 +40,10 @@ # include <strings.h> # endif #endif +#ifdef HAVE_FSTAT +# include <sys/types.h> +# include <sys/stat.h> +#endif #include <getopt.h> #include "dc.h" #include "dc-proto.h" @@ -66,7 +70,7 @@ show_version DC_DECLVOID() printf("\n%s\n\ This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,\n\ -to the extent permitted by law.\n", DC_COPYRIGHT); +to the extent permitted by law.\n", DC_COPYRIGHT); } /* your generic usage function */ @@ -95,7 +99,7 @@ r1bindex DC_DECLARG((s, c)) { char *p = strrchr(s, c); - if (!p) + if (p == NULL) return s; return p + 1; } @@ -107,18 +111,141 @@ try_file(const char *filename) if (strcmp(filename, "-") == 0) { input = stdin; - } else if ( !(input=fopen(filename, "r")) ) { - fprintf(stderr, "Could not open file "); - perror(filename); - exit(EXIT_FAILURE); + } else if ( (input=fopen(filename, "r")) == NULL ) { + fprintf(stderr, "%s: Could not open file %s\n", progname, filename); + return; } - if (dc_evalfile(input)) + { + /* Several complaints have been filed about dc's silence + * when a "cd" typo is made. I really wanted to avoid + * this mess, but I guess it really should be added... + */ +#ifndef HAVE_FSTAT + /* non-POSIXish system; this code _might_ notice a directory */ + int c = getc(input); + if (c == EOF && ferror(input)) { + perror(filename); + goto close; + } + ungetc(c, input); + +#else /* HAVE_FSTAT */ + /* If HAVE_FSTAT and no S_IS*() macros, it must be a pre-POSIX + * Unix-ish system? + */ +# ifndef S_ISREG +# ifdef S_IFREG +# define S_ISREG(m) (((m)&S_IFMT)==S_IFREG) +# else +# define S_ISREG(m) 0 +# endif +# endif +# ifndef S_ISCHR +# ifdef S_IFCHR +# define S_ISCHR(m) (((m)&S_IFMT)==S_IFCHR) +# endif +# endif +# ifndef S_ISFIFO +# ifdef S_IFIFO +# define S_ISFIFO(m) (((m)&S_IFMT)==S_IFIFO) +# endif +# endif +# ifndef S_ISSOCK +# ifdef S_IFSOCK +# define S_ISSOCK(m) (((m)&S_IFMT)==S_IFSOCK) +# endif +# endif +# ifndef S_ISDIR +# ifdef S_IFDIR +# define S_ISDIR(m) (((m)&S_IFMT)==S_IFDIR) +# endif +# endif +# ifndef S_ISBLK +# ifdef S_IFBLK +# define S_ISBLK(m) (((m)&S_IFMT)==S_IFBLK) +# endif +# endif + struct stat s; + if (fstat(fileno(input), &s) == -1) { + /* "can't happen" */ + fprintf(stderr, "%s: Could not fstat file ", progname); + perror(filename); + goto close; + } + +#ifdef S_ISDIR + if (S_ISDIR(s.st_mode)) { + fprintf(stderr, + "%s: Will not attempt to process directory %s\n", + progname, filename); + goto close; + } else +#endif +#ifdef S_ISBLK + if (S_ISBLK(s.st_mode)) { + fprintf(stderr, + "%s: Will not attempt to process block-special file %s\n", + progname, filename); + goto close; + } else +#endif + if (!S_ISREG(s.st_mode) +# ifdef S_ISCHR + /* typically will be /dev/null or some sort of tty */ + && !S_ISCHR(s.st_mode) +# endif +# ifdef S_ISFIFO + && !S_ISFIFO(s.st_mode) +# endif +# ifdef S_ISSOCK + && !S_ISSOCK(s.st_mode) +# endif + ) { + fprintf(stderr, + "%s: Will not attempt to process file of unusual type: %s\n", + progname, filename); + goto close; + } +#endif /* HAVE_FSTAT */ + } + if (dc_evalfile(input) != DC_SUCCESS) exit(EXIT_FAILURE); +close: if (input != stdin) fclose(input); } + +/* Check to see if there were any output errors; if so, then give + * an error message (if stderr is not known to be unhappy), and + * ensure that the program exits with an error indication. + */ +static int +flush_okay DC_DECLVOID() +{ + const char *errmsg = NULL; + int r = EXIT_SUCCESS; + + if (ferror(stdout)) + errmsg = "error writing to stdout"; + else if (fflush(stdout)) + errmsg = "error flushing stdout"; + else if (fclose(stdout)) + errmsg = "error closing stdout"; + + if (errmsg) { + fprintf(stderr, "%s: ", progname); + perror(errmsg); + r = EXIT_FAILURE; + } + + if (ferror(stderr) || fclose(stderr)) + r = EXIT_FAILURE; + return r; +} + + int main DC_DECLARG((argc, argv)) int argc DC_DECLSEP @@ -148,8 +275,8 @@ main DC_DECLARG((argc, argv)) switch (c) { case 'e': { dc_data string = dc_makestring(optarg, strlen(optarg)); - if (dc_evalstr(string)) - return EXIT_SUCCESS; + if (dc_evalstr(&string) != DC_SUCCESS) + return flush_okay(); dc_free_str(&string.v.string); did_eval = 1; } @@ -160,10 +287,10 @@ main DC_DECLARG((argc, argv)) break; case 'h': usage(stdout); - return EXIT_SUCCESS; + return flush_okay(); case 'V': show_version(); - return EXIT_SUCCESS; + return flush_okay(); default: usage(stderr); return EXIT_FAILURE; @@ -174,10 +301,19 @@ main DC_DECLARG((argc, argv)) try_file(argv[optind]); did_eval = 1; } - if (!did_eval) { + if (did_eval == 0) { /* if no -e commands and no command files, then eval stdin */ - if (dc_evalfile(stdin)) + if (dc_evalfile(stdin) != DC_SUCCESS) return EXIT_FAILURE; } - return EXIT_SUCCESS; + return flush_okay(); } + + +/* + * Local Variables: + * mode: C + * tab-width: 4 + * End: + * vi: set ts=4 : + */ |