From af96fb92052c307818eefa4b687f964f1e3f542e Mon Sep 17 00:00:00 2001
From: Matt Weber <matthew.weber@rockwellcollins.com>
Date: Thu, 12 Sep 2019 15:04:35 -0500
Subject: [PATCH] notice read and write errors on input and output

Quoting from the bug report:
   bc (1.06-19ubuntu1) dapper; urgency=low
   * Make dc notice read and write errors on its input and output.
     I grepped for mentions of the strings `putc', `print', `getc',
     `FILE', `stdin', `stdout' and `stderr' and added calls to new
     error-checking functions unless it was clear from the
     immediately-surrounding code that the program was exiting
     nonzero, or would exit nonzero if the call failed.  I ignored
     hits in lib/getopt*, which seems to pervasively ignore write
     errors when printing usage messages, in the hope that these
     were correct.  I _think_ I got them all.  -iwj.
     -- Ian Jackson <iwj@ubuntu.com>  Tue,  4 Apr 2006 17:21:02 +0100

Upsteam:
https://sources.debian.org/patches/bc/1.07.1-2/05_notice_read_write_errors.diff/

[Reformatted to GIT for 1.0.7.1 by Matt W]
Updated by Ryan Kavanagh <rak@debian.org> for 1.0.7.1 on 26 July 2017.
Author: Ian Jackson <iwj@ubuntu.com>
Origin: other
Bug-Debian: http://bugs.debian.org/488735

Signed-off-by: Matthew Weber <matthew.weber@rockwellcollins.com>
Signed-off-by: Bernd Kuhls <bernd@kuhls.net>
[Bernd:
 Updated to incorporate changes by Matthias Klose <doko@debian.org>
 on 2024-03-13 that fix Debian bug https://bugs.debian.org/1065375]
---
 bc/execute.c | 10 +++++++++-
 bc/main.c    |  3 +++
 bc/sbc.y     |  2 ++
 bc/scan.c    |  2 ++
 bc/scan.l    |  3 +++
 bc/util.c    | 15 ++++++++++++--
 dc/dc.c      |  3 +++
 dc/eval.c    | 55 +++++++++++++++++++++++++++++++++++++++-------------
 dc/misc.c    |  1 +
 dc/numeric.c |  9 +++++++++
 dc/stack.c   | 11 ++++++++++-
 dc/string.c  |  2 ++
 h/number.h   | 11 +++++++----
 lib/number.c | 24 +++++++++++++++++++++++
 14 files changed, 129 insertions(+), 22 deletions(-)

--- a/bc/execute.c
+++ b/bc/execute.c
@@ -104,6 +104,7 @@ execute (void)
 	      }
 	    out_char ('\n');
 	  }
+	checkferror_output(stdout);
       }
 #endif
 
@@ -224,6 +225,7 @@ execute (void)
 		}
 	    }
 	fflush (stdout);
+	checkferror_output(stdout);
 	break;
 
       case 'R' : /* Return from function */
@@ -259,6 +261,7 @@ execute (void)
 	if (inst == 'W') out_char ('\n');
 	store_var (4);  /* Special variable "last". */
 	fflush (stdout);
+	checkferror_output(stdout);
 	pop ();
 	break;
 
@@ -342,6 +345,7 @@ execute (void)
       case 'w' : /* Write a string to the output. */
 	while ((ch = byte(&pc)) != '"') out_schar (ch);
 	fflush (stdout);
+	checkferror_output(stdout);
 	break;
 		   
       case 'x' : /* Exchange Top of Stack with the one under the tos. */
@@ -549,7 +553,10 @@ execute (void)
     {
       signal (SIGINT, use_quit);
       if (had_sigint)
-	printf ("\ninterrupted execution.\n");
+	{
+	  printf ("\ninterrupted execution.\n");
+	  checkferror_output(stdout);
+	}
     }
 }
 
@@ -584,6 +591,7 @@ input_char (void)
 	  out_col = 0;  /* Saw a new line */
 	}
     }
+  checkferror_input(stdin);
 
   /* Classify and preprocess the input character. */
   if (isdigit(in_ch))
--- a/bc/main.c
+++ b/bc/main.c
@@ -353,6 +353,9 @@ use_quit (int sig)
   errno = save;
 #else
   write (1, "\n(interrupt) Exiting bc.\n", 26);
+#ifdef READLINE
+  rl_initialize (); /* Clear readline buffer */
+#endif
   bc_exit(0);
 #endif
 }
--- a/bc/sbc.y
+++ b/bc/sbc.y
@@ -86,7 +86,9 @@ program			: /* empty */
 			      if (interactive && !quiet)
 				{
 				  show_bc_version ();
+				  checkferror_output(stdout);
 				  welcome ();
+				  checkferror_output(stdout);
 				}
 			    }
 			| program input_item
--- a/bc/scan.c
+++ b/bc/scan.c
@@ -791,6 +791,7 @@ bcel_input (char *buf, yy_size_t  *resul
       if (bcel_len != 0)
 	history (hist, &histev, H_ENTER, bcel_line); 
       fflush (stdout);
+      checkferror_output(stdout);
     }
 
   if (bcel_len <= max)
@@ -863,6 +864,7 @@ rl_input (char *buf, int *result, int ma
 	add_history (rl_line); 
       rl_line[rl_len-1] = '\n';
       fflush (stdout);
+      checkferror_output(stdout);
     }
 
   if (rl_len <= max)
--- a/bc/scan.l
+++ b/bc/scan.l
@@ -99,6 +99,7 @@ bcel_input (char *buf, yy_size_t  *resul
       if (bcel_len != 0)
 	history (hist, &histev, H_ENTER, bcel_line); 
       fflush (stdout);
+      checkferror_output(stdout);
     }
 
   if (bcel_len <= max)
@@ -171,6 +172,7 @@ rl_input (char *buf, int *result, int ma
 	add_history (rl_line); 
       rl_line[rl_len-1] = '\n';
       fflush (stdout);
+      checkferror_output(stdout);
     }
 
   if (rl_len <= max)
@@ -295,6 +297,7 @@ limits return(Limits);
 	    if (c == EOF)
 	      {
 		fprintf (stderr,"EOF encountered in a comment.\n");
+                checkferror_output(stderr);
 		break;
 	      }
 	  }
--- a/bc/util.c
+++ b/bc/util.c
@@ -247,9 +247,10 @@ init_gen (void)
   continue_label = 0;
   next_label  = 1;
   out_count = 2;
-  if (compile_only) 
+  if (compile_only) {
     printf ("@i");
-  else
+    checkferror_output(stdout);
+  } else
     init_load ();
   had_error = FALSE;
   did_gen = FALSE;
@@ -272,6 +273,7 @@ generate (const char *str)
 	  printf ("\n");
 	  out_count = 0;
 	}
+      checkferror_output(stdout);
     }
   else
     load_code (str);
@@ -289,6 +291,7 @@ run_code(void)
       if (compile_only)
 	{
 	  printf ("@r\n"); 
+	  checkferror_output(stdout);
 	  out_count = 0;
 	}
       else
@@ -326,6 +329,7 @@ out_char (int ch)
 	}
       putchar (ch);
     }
+  checkferror_output(stdout);
 }
 
 /* Output routines: Write a character CH to the standard output.
@@ -355,6 +359,7 @@ out_schar (int ch)
 	}
       putchar (ch);
     }
+  checkferror_output(stdout);
 }
 
 
@@ -639,6 +644,7 @@ limits(void)
 #ifdef OLD_EQ_OP
   printf ("Old assignment operatiors are valid. (=-, =+, ...)\n");
 #endif 
+  checkferror_output(stdout);
 }
 
 /* bc_malloc will check the return value so all other places do not
@@ -703,6 +709,7 @@ yyerror (str, va_alist)
   fprintf (stderr,"%s %d: ",name,line_no);
   vfprintf (stderr, str, args);
   fprintf (stderr, "\n");
+  checkferror_output(stderr);
   had_error = TRUE;
   va_end (args);
 }
@@ -743,6 +750,7 @@ ct_warn (mesg, va_alist)
       fprintf (stderr,"%s %d: Error: ",name,line_no);
       vfprintf (stderr, mesg, args);
       fprintf (stderr, "\n");
+      checkferror_output(stderr);
       had_error = TRUE;
     }
   else
@@ -755,6 +763,7 @@ ct_warn (mesg, va_alist)
 	fprintf (stderr,"%s %d: (Warning) ",name,line_no);
 	vfprintf (stderr, mesg, args);
 	fprintf (stderr, "\n");
+	checkferror_output(stderr);
       }
   va_end (args);
 }
@@ -789,6 +798,7 @@ rt_error (mesg, va_alist)
   va_end (args);
   
   fprintf (stderr, "\n");
+  checkferror_output(stderr);
   runtime_error = TRUE;
 }
 
@@ -823,6 +833,7 @@ rt_warn (const char *mesg)
   va_end (args);
 
   fprintf (stderr, "\n");
+  checkferror_output(stderr);
 }
 
 /* bc_exit: Make sure to reset the edit state. */
--- a/dc/dc.c
+++ b/dc/dc.c
@@ -45,6 +45,7 @@
 #include <getopt.h>
 #include "dc.h"
 #include "dc-proto.h"
+#include "number.h"
 
 #ifndef EXIT_SUCCESS	/* C89 <stdlib.h> */
 # define EXIT_SUCCESS	0
@@ -59,6 +60,7 @@ static void
 bug_report_info DC_DECLVOID()
 {
 	printf("Email bug reports to:  bug-dc@gnu.org .\n");
+	checkferror_output(stdout);
 }
 
 static void
@@ -69,6 +71,7 @@ show_version DC_DECLVOID()
 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);
+	checkferror_output(stdout);
 }
 
 /* your generic usage function */
@@ -85,6 +88,7 @@ Usage: %s [OPTION] [file ...]\n\
 \n\
 ", progname);
 	bug_report_info();
+	checkferror_output(f);
 }
 
 /* returns a pointer to one past the last occurance of c in s,
--- a/dc/eval.c
+++ b/dc/eval.c
@@ -41,6 +41,7 @@
 #endif
 #include "dc.h"
 #include "dc-proto.h"
+#include "number.h"
 
 typedef enum {DC_FALSE, DC_TRUE} dc_boolean;
 
@@ -97,12 +98,15 @@ static int input_pushback;
 static int
 input_fil DC_DECLVOID()
 {
+		int c;
 	if (input_pushback != EOF){
-		int c = input_pushback;
+		c = input_pushback;
 		input_pushback = EOF;
 		return c;
 	}
-	return getc(input_fil_fp);
+	c = getc(input_fil_fp);
+	checkferror_input(input_fil_fp);
+	return c;
 }
 
 /* passed as an argument to dc_getnum */
@@ -301,11 +305,13 @@ dc_func DC_DECLARG((c, peekc, negcmp))
 				tmpint = dc_num2int(datum.v.number, DC_TOSS);
 			if (2 <= tmpint  &&  tmpint <= DC_IBASE_MAX)
 				dc_ibase = tmpint;
-			else
+			else {
 				fprintf(stderr,
 						"%s: input base must be a number \
 between 2 and %d (inclusive)\n",
 						progname, DC_IBASE_MAX);
+				checkferror_output(stderr);
+			}
 		}
 		break;
 	case 'k':	/* set scale to value on top of stack */
@@ -313,11 +319,12 @@ between 2 and %d (inclusive)\n",
 			tmpint = -1;
 			if (datum.dc_type == DC_NUMBER)
 				tmpint = dc_num2int(datum.v.number, DC_TOSS);
-			if ( ! (tmpint >= 0) )
+			if ( ! (tmpint >= 0) ) {
 				fprintf(stderr,
 						"%s: scale must be a nonnegative number\n",
 						progname);
-			else
+				checkferror_output(stderr);
+			} else
 				dc_scale = tmpint;
 		}
 		break;
@@ -341,11 +348,12 @@ between 2 and %d (inclusive)\n",
 			tmpint = 0;
 			if (datum.dc_type == DC_NUMBER)
 				tmpint = dc_num2int(datum.v.number, DC_TOSS);
-			if ( ! (tmpint > 1) )
+			if ( ! (tmpint > 1) ) {
 				fprintf(stderr,
 						"%s: output base must be a number greater than 1\n",
 						progname);
-			else
+				checkferror_output(stderr);
+			} else
 				dc_obase = tmpint;
 		}
 		break;
@@ -378,6 +386,7 @@ between 2 and %d (inclusive)\n",
 				fprintf(stderr,
 						"%s: square root of nonnumeric attempted\n",
 						progname);
+				checkferror_output(stderr);
 			}else if (dc_sqrt(datum.v.number, dc_scale, &tmpnum) == DC_SUCCESS){
 				dc_free_num(&datum.v.number);
 				datum.v.number = tmpnum;
@@ -424,6 +433,7 @@ between 2 and %d (inclusive)\n",
 				dc_garbage("at top of stack", -1);
 		}
 		fflush(stdout);
+		checkferror_output(stdout);
 		break;
 	case 'Q':	/* quit out of top-of-stack nested evals;
 				 * pops value from stack;
@@ -440,6 +450,7 @@ between 2 and %d (inclusive)\n",
 			fprintf(stderr,
 					"%s: Q command requires a number >= 1\n",
 					progname);
+			checkferror_output(stderr);
 		}
 		break;
 	case 'R':	/* pop a value off of the evaluation stack,;
@@ -483,11 +494,12 @@ between 2 and %d (inclusive)\n",
 			if (datum.dc_type == DC_NUMBER)
 				tmpint = dc_num2int(datum.v.number, DC_TOSS);
 			if (dc_pop(&datum) == DC_SUCCESS){
-				if (tmpint < 0)
+				if (tmpint < 0) {
 					fprintf(stderr,
 							"%s: array index must be a nonnegative integer\n",
 							progname);
-				else
+					checkferror_output(stderr);
+				} else
 					dc_array_set(peekc, tmpint, datum);
 			}
 		}
@@ -499,18 +511,21 @@ between 2 and %d (inclusive)\n",
 			tmpint = -1;
 			if (datum.dc_type == DC_NUMBER)
 				tmpint = dc_num2int(datum.v.number, DC_TOSS);
-			if (tmpint < 0)
+			if (tmpint < 0) {
 				fprintf(stderr,
 						"%s: array index must be a nonnegative integer\n",
 						progname);
-			else
+				checkferror_output(stderr);
+			} else
 				dc_push(dc_array_get(peekc, tmpint));
 		}
 		return DC_EATONE;
 
 	default:	/* What did that user mean? */
 		fprintf(stderr, "%s: ", progname);
+		checkferror_output(stderr);
 		dc_show_id(stdout, c, " unimplemented\n");
+		checkferror_output(stdout);
 		break;
 	}
 	return DC_OKAY;
@@ -538,6 +553,7 @@ evalstr DC_DECLARG((string))
 		fprintf(stderr,
 				"%s: eval called with non-string argument\n",
 				progname);
+		checkferror_output(stderr);
 		return DC_OKAY;
 	}
 	interrupt_seen = 0;
@@ -635,6 +651,7 @@ evalstr DC_DECLARG((string))
 				return DC_FAIL;
 			}
 			fprintf(stderr, "%s: unexpected EOS\n", progname);
+			checkferror_output(stderr);
 			return DC_OKAY;
 		}
 	}
@@ -692,6 +709,7 @@ dc_evalfile DC_DECLARG((fp))
 	stdin_lookahead = EOF;
 	for (c=getc(fp); c!=EOF; c=peekc){
 		peekc = getc(fp);
+		checkferror_input(stdin);
 		/*
 		 * The following if() is the only place where ``stdin_lookahead''
 		 * might be set to other than EOF:
@@ -717,24 +735,30 @@ dc_evalfile DC_DECLARG((fp))
 		signal(SIGINT, sigint_handler);
 		switch (dc_func(c, peekc, negcmp)){
 		case DC_OKAY:
-			if (stdin_lookahead != peekc  &&  fp == stdin)
+			if (stdin_lookahead != peekc  &&  fp == stdin) {
 				peekc = getc(fp);
+				checkferror_input(stdin);
+			}
 			break;
 		case DC_EATONE:
 			peekc = getc(fp);
+			checkferror_input(fp);
 			break;
 		case DC_EVALREG:
 			/*commands which send us here shall guarantee that peekc!=EOF*/
 			c = peekc;
 			peekc = getc(fp);
+			checkferror_input(fp);
 			stdin_lookahead = peekc;
 			if (dc_register_get(c, &datum) != DC_SUCCESS)
 				break;
 			dc_push(datum);
 			/*@fallthrough@*/
 		case DC_EVALTOS:
-			if (stdin_lookahead != peekc  &&  fp == stdin)
+			if (stdin_lookahead != peekc  &&  fp == stdin) {
 				peekc = getc(fp);
+				checkferror_input(stdin);
+			}
 			if (dc_pop(&datum) == DC_SUCCESS){
 				if (datum.dc_type == DC_NUMBER){
 					dc_push(datum);
@@ -744,6 +768,7 @@ dc_evalfile DC_DECLARG((fp))
 							goto reset_and_exit_quit;
 						fprintf(stderr, "%s: Q command argument exceeded \
 string execution depth\n", progname);
+						checkferror_output(stderr);
 					}
 				}else{
 					dc_garbage("at top of stack", -1);
@@ -756,8 +781,11 @@ string execution depth\n", progname);
 			fprintf(stderr,
 					"%s: Q command argument exceeded string execution depth\n",
 					progname);
-			if (stdin_lookahead != peekc  &&  fp == stdin)
+			checkferror_output(stderr);
+			if (stdin_lookahead != peekc  &&  fp == stdin) {
 				peekc = getc(fp);
+				checkferror_input(stdin);
+			}
 			break;
 
 		case DC_INT:
--- a/dc/misc.c
+++ b/dc/misc.c
@@ -47,6 +47,7 @@
 #include <getopt.h>
 #include "dc.h"
 #include "dc-proto.h"
+#include "number.h"
 
 #ifndef EXIT_FAILURE	/* C89 <stdlib.h> */
 # define EXIT_FAILURE	1
@@ -89,6 +90,7 @@ dc_show_id DC_DECLARG((fp, id, suffix))
 		fprintf(fp, "'%c' (%#o)%s", (unsigned int) id, id, suffix);
 	else
 		fprintf(fp, "%#o%s", (unsigned int) id, suffix);
+	checkferror_output(fp);
 }
 
 
--- a/dc/numeric.c
+++ b/dc/numeric.c
@@ -133,6 +133,7 @@ dc_div DC_DECLARG((a, b, kscale, result)
 	bc_init_num(CastNumPtr(result));
 	if (bc_divide(CastNum(a), CastNum(b), CastNumPtr(result), kscale)){
 		fprintf(stderr, "%s: divide by zero\n", progname);
+		checkferror_output(stderr);
 		return DC_DOMAIN_ERROR;
 	}
 	return DC_SUCCESS;
@@ -155,6 +156,7 @@ dc_divrem DC_DECLARG((a, b, kscale, quot
 	if (bc_divmod(CastNum(a), CastNum(b),
 						CastNumPtr(quotient), CastNumPtr(remainder), kscale)){
 		fprintf(stderr, "%s: divide by zero\n", progname);
+		checkferror_output(stderr);
 		return DC_DOMAIN_ERROR;
 	}
 	return DC_SUCCESS;
@@ -173,6 +175,7 @@ dc_rem DC_DECLARG((a, b, kscale, result)
 	bc_init_num(CastNumPtr(result));
 	if (bc_modulo(CastNum(a), CastNum(b), CastNumPtr(result), kscale)){
 		fprintf(stderr, "%s: remainder by zero\n", progname);
+		checkferror_output(stderr);
 		return DC_DOMAIN_ERROR;
 	}
 	return DC_SUCCESS;
@@ -225,6 +228,7 @@ dc_sqrt DC_DECLARG((value, kscale, resul
 	tmp = bc_copy_num(CastNum(value));
 	if (!bc_sqrt(&tmp, kscale)){
 		fprintf(stderr, "%s: square root of negative number\n", progname);
+		checkferror_output(stderr);
 		bc_free_num(&tmp);
 		return DC_DOMAIN_ERROR;
 	}
@@ -470,6 +474,7 @@ dc_dump_num DC_DECLARG((dcvalue, discard
 
 	for (cur=top_of_stack; cur; cur=next) {
 		putchar(cur->digit);
+		checkferror_output(stdout);
 		next = cur->link;
 		free(cur);
 	}
@@ -587,6 +592,8 @@ out_char (ch)
 			out_col = 1;
 		}
 		putchar(ch);
+                checkferror_output(stdout);
+		checkferror_output(stderr);
 	}
 }
 
@@ -626,6 +633,7 @@ rt_error (mesg, va_alist)
 	vfprintf (stderr, mesg, args);
 	va_end (args);
 	fprintf (stderr, "\n");
+	checkferror_output(stderr);
 }
 
 
@@ -659,6 +667,7 @@ rt_warn (mesg, va_alist)
 	vfprintf (stderr, mesg, args);
 	va_end (args);
 	fprintf (stderr, "\n");
+	checkferror_output(stderr);
 }
 
 
--- a/dc/stack.c
+++ b/dc/stack.c
@@ -33,9 +33,13 @@
 #include "dc.h"
 #include "dc-proto.h"
 #include "dc-regdef.h"
+#include "number.h"
 
 /* an oft-used error message: */
-#define Empty_Stack	fprintf(stderr, "%s: stack empty\n", progname)
+#define Empty_Stack do{					\
+    fprintf(stderr, "%s: stack empty\n", progname);	\
+    checkferror_output(stderr);				\
+  }while(0)
 
 
 /* simple linked-list implementation suffices: */
@@ -91,6 +95,7 @@ dc_binop DC_DECLARG((op, kscale))
 	if (dc_stack->value.dc_type!=DC_NUMBER
 			|| dc_stack->link->value.dc_type!=DC_NUMBER){
 		fprintf(stderr, "%s: non-numeric value\n", progname);
+		checkferror_output(stderr);
 		return;
 	}
 	(void)dc_pop(&b);
@@ -131,6 +136,7 @@ dc_binop2 DC_DECLARG((op, kscale))
 	if (dc_stack->value.dc_type!=DC_NUMBER
 			|| dc_stack->link->value.dc_type!=DC_NUMBER){
 		fprintf(stderr, "%s: non-numeric value\n", progname);
+		checkferror_output(stderr);
 		return;
 	}
 	(void)dc_pop(&b);
@@ -169,6 +175,7 @@ dc_cmpop DC_DECLVOID()
 	if (dc_stack->value.dc_type!=DC_NUMBER
 			|| dc_stack->link->value.dc_type!=DC_NUMBER){
 		fprintf(stderr, "%s: non-numeric value\n", progname);
+		checkferror_output(stderr);
 		return 0;
 	}
 	(void)dc_pop(&b);
@@ -206,6 +213,7 @@ dc_triop DC_DECLARG((op, kscale))
 			|| dc_stack->link->value.dc_type!=DC_NUMBER
 			|| dc_stack->link->link->value.dc_type!=DC_NUMBER){
 		fprintf(stderr, "%s: non-numeric value\n", progname);
+		checkferror_output(stderr);
 		return;
 	}
 	(void)dc_pop(&c);
@@ -327,6 +335,7 @@ dc_register_get DC_DECLARG((regid, resul
 		*result = dc_int2data(0);
 	}else if (r->value.dc_type==DC_UNINITIALIZED){
 		fprintf(stderr, "%s: BUG: register ", progname);
+		checkferror_output(stderr);
 		dc_show_id(stderr, regid, " exists but is uninitialized?\n");
 		return DC_FAIL;
 	}else{
@@ -402,6 +411,7 @@ dc_register_pop DC_DECLARG((stackid, res
 	r = dc_register[stackid];
 	if (r==NULL || r->value.dc_type==DC_UNINITIALIZED){
 		fprintf(stderr, "%s: stack register ", progname);
+		checkferror_output(stderr);
 		dc_show_id(stderr, stackid, " is empty\n");
 		return DC_FAIL;
 	}
--- a/dc/string.c
+++ b/dc/string.c
@@ -45,6 +45,7 @@
 #endif
 #include "dc.h"
 #include "dc-proto.h"
+#include "number.h"
 
 /* here is the completion of the dc_string type: */
 struct dc_string {
@@ -94,6 +95,7 @@ dc_out_str DC_DECLARG((value, discard_fl
 	dc_discard discard_flag DC_DECLEND
 {
 	fwrite(value->s_ptr, value->s_len, sizeof *value->s_ptr, stdout);
+        checkferror_output(stdout);
 	if (discard_flag == DC_TOSS)
 		dc_free_str(&value);
 }
@@ -169,6 +171,7 @@ dc_readstring DC_DECLARG((fp, ldelim, rd
 		}
 		*p++ = c;
 	}
+	checkferror_input(fp);
 	return dc_makestring(line_buf, (size_t)(p-line_buf));
 }
 
--- a/h/number.h
+++ b/h/number.h
@@ -23,10 +23,10 @@
     You may contact the author by:
        e-mail:  philnelson@acm.org
       us-mail:  Philip A. Nelson
-                Computer Science Department, 9062
-                Western Washington University
-                Bellingham, WA 98226-9062
-       
+		Computer Science Department, 9062
+		Western Washington University
+		Bellingham, WA 98226-9062
+
 *************************************************************************/
 
 #ifndef _NUMBER_H_
@@ -140,4 +140,7 @@ void bc_out_num (bc_num num, int o_base,
 			     int leading_zero);
 
 void bc_out_long (long val, int size, int space, void (*out_char)(int));
+
+void checkferror_input (FILE*);
+void checkferror_output (FILE*);
 #endif
--- a/lib/number.c
+++ b/lib/number.c
@@ -1713,6 +1713,7 @@ static void
 out_char (int c)
 {
   putchar(c);
+  checkferror_output(stdout);
 }
 
 
@@ -1721,6 +1722,7 @@ pn (bc_num num)
 {
   bc_out_num (num, 10, out_char, 0);
   out_char ('\n');
+  checkferror_output(stdout);
 }
 
 
@@ -1732,6 +1734,28 @@ pv (char *name, unsigned char *num, int
   printf ("%s=", name);
   for (i=0; i<len; i++) printf ("%c",BCD_CHAR(num[i]));
   printf ("\n");
+  checkferror_output(stdout);
 }
 
 #endif
+
+/* check ferror() status and if so die */
+void
+checkferror_input (fp)
+	FILE *fp;
+{
+	if (ferror(fp)) {
+		perror("dc: could not read input file");
+		exit(EXIT_FAILURE);
+	}
+}
+
+void
+checkferror_output (fp)
+	FILE *fp;
+{
+	if (ferror(fp)) {
+		perror("dc: could not write output file");
+		exit(EXIT_FAILURE);
+	}
+}
