summaryrefslogtreecommitdiff
path: root/dc/dc.c
diff options
context:
space:
mode:
Diffstat (limited to 'dc/dc.c')
-rw-r--r--dc/dc.c172
1 files changed, 154 insertions, 18 deletions
diff --git a/dc/dc.c b/dc/dc.c
index a72644c..e03f094 100644
--- a/dc/dc.c
+++ b/dc/dc.c
@@ -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 :
+ */