1From af96fb92052c307818eefa4b687f964f1e3f542e Mon Sep 17 00:00:00 2001
2From: Matt Weber <matthew.weber@rockwellcollins.com>
3Date: Thu, 12 Sep 2019 15:04:35 -0500
4Subject: [PATCH] notice read and write errors on input and output
5
6Quoting from the bug report:
7   bc (1.06-19ubuntu1) dapper; urgency=low
8   * Make dc notice read and write errors on its input and output.
9     I grepped for mentions of the strings `putc', `print', `getc',
10     `FILE', `stdin', `stdout' and `stderr' and added calls to new
11     error-checking functions unless it was clear from the
12     immediately-surrounding code that the program was exiting
13     nonzero, or would exit nonzero if the call failed.  I ignored
14     hits in lib/getopt*, which seems to pervasively ignore write
15     errors when printing usage messages, in the hope that these
16     were correct.  I _think_ I got them all.  -iwj.
17     -- Ian Jackson <iwj@ubuntu.com>  Tue,  4 Apr 2006 17:21:02 +0100
18
19Upsteam:
20https://sources.debian.org/patches/bc/1.07.1-2/05_notice_read_write_errors.diff/
21
22[Reformatted to GIT for 1.0.7.1 by Matt W]
23Updated by Ryan Kavanagh <rak@debian.org> for 1.0.7.1 on 26 July 2017.
24Author: Ian Jackson <iwj@ubuntu.com>
25Origin: other
26Bug-Debian: http://bugs.debian.org/488735
27
28Signed-off-by: Matthew Weber <matthew.weber@rockwellcollins.com>
29Signed-off-by: Bernd Kuhls <bernd@kuhls.net>
30[Bernd:
31 Updated to incorporate changes by Matthias Klose <doko@debian.org>
32 on 2024-03-13 that fix Debian bug https://bugs.debian.org/1065375]
33---
34 bc/execute.c | 10 +++++++++-
35 bc/main.c    |  3 +++
36 bc/sbc.y     |  2 ++
37 bc/scan.c    |  2 ++
38 bc/scan.l    |  3 +++
39 bc/util.c    | 15 ++++++++++++--
40 dc/dc.c      |  3 +++
41 dc/eval.c    | 55 +++++++++++++++++++++++++++++++++++++++-------------
42 dc/misc.c    |  1 +
43 dc/numeric.c |  9 +++++++++
44 dc/stack.c   | 11 ++++++++++-
45 dc/string.c  |  2 ++
46 h/number.h   | 11 +++++++----
47 lib/number.c | 24 +++++++++++++++++++++++
48 14 files changed, 129 insertions(+), 22 deletions(-)
49
50diff --git a/bc/execute.c b/bc/execute.c
51index 256e4b7..50eac49 100644
52--- a/bc/execute.c
53+++ b/bc/execute.c
54@@ -104,6 +104,7 @@ execute (void)
55 	      }
56 	    out_char ('\n');
57 	  }
58+	checkferror_output(stdout);
59       }
60 #endif
61
62@@ -224,6 +225,7 @@ execute (void)
63 		}
64 	    }
65 	fflush (stdout);
66+	checkferror_output(stdout);
67 	break;
68
69       case 'R' : /* Return from function */
70@@ -259,6 +261,7 @@ execute (void)
71 	if (inst == 'W') out_char ('\n');
72 	store_var (4);  /* Special variable "last". */
73 	fflush (stdout);
74+	checkferror_output(stdout);
75 	pop ();
76 	break;
77
78@@ -342,6 +345,7 @@ execute (void)
79       case 'w' : /* Write a string to the output. */
80 	while ((ch = byte(&pc)) != '"') out_schar (ch);
81 	fflush (stdout);
82+	checkferror_output(stdout);
83 	break;
84
85       case 'x' : /* Exchange Top of Stack with the one under the tos. */
86@@ -549,7 +553,10 @@ execute (void)
87     {
88       signal (SIGINT, use_quit);
89       if (had_sigint)
90-	printf ("\ninterrupted execution.\n");
91+	{
92+	  printf ("\ninterrupted execution.\n");
93+	  checkferror_output(stdout);
94+	}
95     }
96 }
97
98@@ -584,6 +591,7 @@ input_char (void)
99 	  out_col = 0;  /* Saw a new line */
100 	}
101     }
102+  checkferror_input(stdin);
103
104   /* Classify and preprocess the input character. */
105   if (isdigit(in_ch))
106diff --git a/bc/main.c b/bc/main.c
107index 012075c..c96207b 100644
108--- a/bc/main.c
109+++ b/bc/main.c
110@@ -353,6 +353,9 @@ use_quit (int sig)
111   errno = save;
112 #else
113   write (1, "\n(interrupt) Exiting bc.\n", 26);
114+#ifdef READLINE
115+  rl_initialize (); /* Clear readline buffer */
116+#endif
117   bc_exit(0);
118 #endif
119 }
120diff --git a/bc/sbc.y b/bc/sbc.y
121index 586686b..921ab1e 100644
122--- a/bc/sbc.y
123+++ b/bc/sbc.y
124@@ -86,7 +86,9 @@ program			: /* empty */
125 			      if (interactive && !quiet)
126 				{
127 				  show_bc_version ();
128+				  checkferror_output(stdout);
129 				  welcome ();
130+				  checkferror_output(stdout);
131 				}
132 			    }
133 			| program input_item
134diff --git a/bc/scan.c b/bc/scan.c
135index b237f55..8dee4e9 100644
136--- a/bc/scan.c
137+++ b/bc/scan.c
138@@ -791,6 +791,7 @@ bcel_input (char *buf, yy_size_t  *result, int max)
139       if (bcel_len != 0)
140 	history (hist, &histev, H_ENTER, bcel_line);
141       fflush (stdout);
142+      checkferror_output(stdout);
143     }
144
145   if (bcel_len <= max)
146@@ -863,6 +864,7 @@ rl_input (char *buf, int *result, int max)
147 	add_history (rl_line);
148       rl_line[rl_len-1] = '\n';
149       fflush (stdout);
150+      checkferror_output(stdout);
151     }
152
153   if (rl_len <= max)
154diff --git a/bc/scan.l b/bc/scan.l
155index eb2e2dd..79186bb 100644
156--- a/bc/scan.l
157+++ b/bc/scan.l
158@@ -99,6 +99,7 @@ bcel_input (char *buf, yy_size_t  *result, int max)
159       if (bcel_len != 0)
160 	history (hist, &histev, H_ENTER, bcel_line);
161       fflush (stdout);
162+      checkferror_output(stdout);
163     }
164
165   if (bcel_len <= max)
166@@ -171,6 +172,7 @@ rl_input (char *buf, int *result, int max)
167 	add_history (rl_line);
168       rl_line[rl_len-1] = '\n';
169       fflush (stdout);
170+      checkferror_output(stdout);
171     }
172
173   if (rl_len <= max)
174@@ -295,6 +297,7 @@ limits return(Limits);
175 	    if (c == EOF)
176 	      {
177 		fprintf (stderr,"EOF encountered in a comment.\n");
178+                checkferror_output(stderr);
179 		break;
180 	      }
181 	  }
182diff --git a/bc/util.c b/bc/util.c
183index 8eba093..cacd796 100644
184--- a/bc/util.c
185+++ b/bc/util.c
186@@ -247,9 +247,10 @@ init_gen (void)
187   continue_label = 0;
188   next_label  = 1;
189   out_count = 2;
190-  if (compile_only)
191+  if (compile_only) {
192     printf ("@i");
193-  else
194+    checkferror_output(stdout);
195+  } else
196     init_load ();
197   had_error = FALSE;
198   did_gen = FALSE;
199@@ -272,6 +273,7 @@ generate (const char *str)
200 	  printf ("\n");
201 	  out_count = 0;
202 	}
203+      checkferror_output(stdout);
204     }
205   else
206     load_code (str);
207@@ -289,6 +291,7 @@ run_code(void)
208       if (compile_only)
209 	{
210 	  printf ("@r\n");
211+	  checkferror_output(stdout);
212 	  out_count = 0;
213 	}
214       else
215@@ -326,6 +329,7 @@ out_char (int ch)
216 	}
217       putchar (ch);
218     }
219+  checkferror_output(stdout);
220 }
221
222 /* Output routines: Write a character CH to the standard output.
223@@ -355,6 +359,7 @@ out_schar (int ch)
224 	}
225       putchar (ch);
226     }
227+  checkferror_output(stdout);
228 }
229
230
231@@ -639,6 +644,7 @@ limits(void)
232 #ifdef OLD_EQ_OP
233   printf ("Old assignment operatiors are valid. (=-, =+, ...)\n");
234 #endif
235+  checkferror_output(stdout);
236 }
237
238 /* bc_malloc will check the return value so all other places do not
239@@ -703,6 +709,7 @@ yyerror (str, va_alist)
240   fprintf (stderr,"%s %d: ",name,line_no);
241   vfprintf (stderr, str, args);
242   fprintf (stderr, "\n");
243+  checkferror_output(stderr);
244   had_error = TRUE;
245   va_end (args);
246 }
247@@ -743,6 +750,7 @@ ct_warn (mesg, va_alist)
248       fprintf (stderr,"%s %d: Error: ",name,line_no);
249       vfprintf (stderr, mesg, args);
250       fprintf (stderr, "\n");
251+      checkferror_output(stderr);
252       had_error = TRUE;
253     }
254   else
255@@ -755,6 +763,7 @@ ct_warn (mesg, va_alist)
256 	fprintf (stderr,"%s %d: (Warning) ",name,line_no);
257 	vfprintf (stderr, mesg, args);
258 	fprintf (stderr, "\n");
259+	checkferror_output(stderr);
260       }
261   va_end (args);
262 }
263@@ -789,6 +798,7 @@ rt_error (mesg, va_alist)
264   va_end (args);
265
266   fprintf (stderr, "\n");
267+  checkferror_output(stderr);
268   runtime_error = TRUE;
269 }
270
271@@ -823,6 +833,7 @@ rt_warn (const char *mesg)
272   va_end (args);
273
274   fprintf (stderr, "\n");
275+  checkferror_output(stderr);
276 }
277
278 /* bc_exit: Make sure to reset the edit state. */
279diff --git a/dc/dc.c b/dc/dc.c
280index 6a2bb26..ccdb1c2 100644
281--- a/dc/dc.c
282+++ b/dc/dc.c
283@@ -45,6 +45,7 @@
284 #include <getopt.h>
285 #include "dc.h"
286 #include "dc-proto.h"
287+#include "number.h"
288
289 #ifndef EXIT_SUCCESS	/* C89 <stdlib.h> */
290 # define EXIT_SUCCESS	0
291@@ -59,6 +59,7 @@ static void
292 bug_report_info DC_DECLVOID()
293 {
294 	printf("Email bug reports to:  bug-dc@gnu.org .\n");
295+	checkferror_output(stdout);
296 }
297
298 static void
299@@ -69,6 +70,7 @@ show_version DC_DECLVOID()
300 This is free software; see the source for copying conditions.  There is NO\n\
301 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,\n\
302 to the extent permitted by law.\n", DC_COPYRIGHT);
303+	checkferror_output(stdout);
304 }
305
306 /* your generic usage function */
307@@ -85,6 +87,7 @@ Usage: %s [OPTION] [file ...]\n\
308 \n\
309 ", progname);
310 	bug_report_info();
311+	checkferror_output(f);
312 }
313
314 /* returns a pointer to one past the last occurance of c in s,
315diff --git a/dc/eval.c b/dc/eval.c
316index 05a3d9e..6c54e61 100644
317--- a/dc/eval.c
318+++ b/dc/eval.c
319@@ -41,6 +41,7 @@
320 #endif
321 #include "dc.h"
322 #include "dc-proto.h"
323+#include "number.h"
324
325 typedef enum {DC_FALSE, DC_TRUE} dc_boolean;
326
327@@ -97,12 +97,15 @@ static int input_pushback;
328 static int
329 input_fil DC_DECLVOID()
330 {
331+		int c;
332 	if (input_pushback != EOF){
333-		int c = input_pushback;
334+		c = input_pushback;
335 		input_pushback = EOF;
336 		return c;
337 	}
338-	return getc(input_fil_fp);
339+	c = getc(input_fil_fp);
340+	checkferror_input(input_fil_fp);
341+	return c;
342 }
343
344 /* passed as an argument to dc_getnum */
345@@ -301,11 +304,13 @@ dc_func DC_DECLARG((c, peekc, negcmp))
346 				tmpint = dc_num2int(datum.v.number, DC_TOSS);
347 			if (2 <= tmpint  &&  tmpint <= DC_IBASE_MAX)
348 				dc_ibase = tmpint;
349-			else
350+			else {
351 				fprintf(stderr,
352 						"%s: input base must be a number \
353 between 2 and %d (inclusive)\n",
354 						progname, DC_IBASE_MAX);
355+				checkferror_output(stderr);
356+			}
357 		}
358 		break;
359 	case 'k':	/* set scale to value on top of stack */
360@@ -313,11 +318,12 @@ between 2 and %d (inclusive)\n",
361 			tmpint = -1;
362 			if (datum.dc_type == DC_NUMBER)
363 				tmpint = dc_num2int(datum.v.number, DC_TOSS);
364-			if ( ! (tmpint >= 0) )
365+			if ( ! (tmpint >= 0) ) {
366 				fprintf(stderr,
367 						"%s: scale must be a nonnegative number\n",
368 						progname);
369-			else
370+				checkferror_output(stderr);
371+			} else
372 				dc_scale = tmpint;
373 		}
374 		break;
375@@ -341,11 +347,12 @@ between 2 and %d (inclusive)\n",
376 			tmpint = 0;
377 			if (datum.dc_type == DC_NUMBER)
378 				tmpint = dc_num2int(datum.v.number, DC_TOSS);
379-			if ( ! (tmpint > 1) )
380+			if ( ! (tmpint > 1) ) {
381 				fprintf(stderr,
382 						"%s: output base must be a number greater than 1\n",
383 						progname);
384-			else
385+				checkferror_output(stderr);
386+			} else
387 				dc_obase = tmpint;
388 		}
389 		break;
390@@ -378,6 +385,7 @@ between 2 and %d (inclusive)\n",
391 				fprintf(stderr,
392 						"%s: square root of nonnumeric attempted\n",
393 						progname);
394+				checkferror_output(stderr);
395 			}else if (dc_sqrt(datum.v.number, dc_scale, &tmpnum) == DC_SUCCESS){
396 				dc_free_num(&datum.v.number);
397 				datum.v.number = tmpnum;
398@@ -424,6 +432,7 @@ between 2 and %d (inclusive)\n",
399 				dc_garbage("at top of stack", -1);
400 		}
401 		fflush(stdout);
402+		checkferror_output(stdout);
403 		break;
404 	case 'Q':	/* quit out of top-of-stack nested evals;
405 				 * pops value from stack;
406@@ -440,6 +449,7 @@ between 2 and %d (inclusive)\n",
407 			fprintf(stderr,
408 					"%s: Q command requires a number >= 1\n",
409 					progname);
410+			checkferror_output(stderr);
411 		}
412 		break;
413 	case 'R':	/* pop a value off of the evaluation stack,;
414@@ -483,11 +493,12 @@ between 2 and %d (inclusive)\n",
415 			if (datum.dc_type == DC_NUMBER)
416 				tmpint = dc_num2int(datum.v.number, DC_TOSS);
417 			if (dc_pop(&datum) == DC_SUCCESS){
418-				if (tmpint < 0)
419+				if (tmpint < 0) {
420 					fprintf(stderr,
421 							"%s: array index must be a nonnegative integer\n",
422 							progname);
423-				else
424+					checkferror_output(stderr);
425+				} else
426 					dc_array_set(peekc, tmpint, datum);
427 			}
428 		}
429@@ -499,18 +510,21 @@ between 2 and %d (inclusive)\n",
430 			tmpint = -1;
431 			if (datum.dc_type == DC_NUMBER)
432 				tmpint = dc_num2int(datum.v.number, DC_TOSS);
433-			if (tmpint < 0)
434+			if (tmpint < 0) {
435 				fprintf(stderr,
436 						"%s: array index must be a nonnegative integer\n",
437 						progname);
438-			else
439+				checkferror_output(stderr);
440+			} else
441 				dc_push(dc_array_get(peekc, tmpint));
442 		}
443 		return DC_EATONE;
444
445 	default:	/* What did that user mean? */
446 		fprintf(stderr, "%s: ", progname);
447+		checkferror_output(stderr);
448 		dc_show_id(stdout, c, " unimplemented\n");
449+		checkferror_output(stdout);
450 		break;
451 	}
452 	return DC_OKAY;
453@@ -538,6 +552,7 @@ evalstr DC_DECLARG((string))
454 		fprintf(stderr,
455 				"%s: eval called with non-string argument\n",
456 				progname);
457+		checkferror_output(stderr);
458 		return DC_OKAY;
459 	}
460 	interrupt_seen = 0;
461@@ -635,6 +650,7 @@ evalstr DC_DECLARG((string))
462 				return DC_FAIL;
463 			}
464 			fprintf(stderr, "%s: unexpected EOS\n", progname);
465+			checkferror_output(stderr);
466 			return DC_OKAY;
467 		}
468 	}
469@@ -692,6 +708,7 @@ dc_evalfile DC_DECLARG((fp))
470 	stdin_lookahead = EOF;
471 	for (c=getc(fp); c!=EOF; c=peekc){
472 		peekc = getc(fp);
473+		checkferror_input(stdin);
474 		/*
475 		 * The following if() is the only place where ``stdin_lookahead''
476 		 * might be set to other than EOF:
477@@ -717,24 +734,30 @@ dc_evalfile DC_DECLARG((fp))
478 		signal(SIGINT, sigint_handler);
479 		switch (dc_func(c, peekc, negcmp)){
480 		case DC_OKAY:
481-			if (stdin_lookahead != peekc  &&  fp == stdin)
482+			if (stdin_lookahead != peekc  &&  fp == stdin) {
483 				peekc = getc(fp);
484+				checkferror_input(stdin);
485+			}
486 			break;
487 		case DC_EATONE:
488 			peekc = getc(fp);
489+			checkferror_input(fp);
490 			break;
491 		case DC_EVALREG:
492 			/*commands which send us here shall guarantee that peekc!=EOF*/
493 			c = peekc;
494 			peekc = getc(fp);
495+			checkferror_input(fp);
496 			stdin_lookahead = peekc;
497 			if (dc_register_get(c, &datum) != DC_SUCCESS)
498 				break;
499 			dc_push(datum);
500 			/*@fallthrough@*/
501 		case DC_EVALTOS:
502-			if (stdin_lookahead != peekc  &&  fp == stdin)
503+			if (stdin_lookahead != peekc  &&  fp == stdin) {
504 				peekc = getc(fp);
505+				checkferror_input(stdin);
506+			}
507 			if (dc_pop(&datum) == DC_SUCCESS){
508 				if (datum.dc_type == DC_NUMBER){
509 					dc_push(datum);
510@@ -744,6 +767,7 @@ dc_evalfile DC_DECLARG((fp))
511 							goto reset_and_exit_quit;
512 						fprintf(stderr, "%s: Q command argument exceeded \
513 string execution depth\n", progname);
514+						checkferror_output(stderr);
515 					}
516 				}else{
517 					dc_garbage("at top of stack", -1);
518@@ -756,8 +780,11 @@ string execution depth\n", progname);
519 			fprintf(stderr,
520 					"%s: Q command argument exceeded string execution depth\n",
521 					progname);
522-			if (stdin_lookahead != peekc  &&  fp == stdin)
523+			checkferror_output(stderr);
524+			if (stdin_lookahead != peekc  &&  fp == stdin) {
525 				peekc = getc(fp);
526+				checkferror_input(stdin);
527+			}
528 			break;
529
530 		case DC_INT:
531diff --git a/dc/misc.c b/dc/misc.c
532index cd23602..cd910b8 100644
533--- a/dc/misc.c
534+++ b/dc/misc.c
535@@ -47,6 +47,7 @@
536 #include <getopt.h>
537 #include "dc.h"
538 #include "dc-proto.h"
539+#include "number.h"
540
541 #ifndef EXIT_FAILURE	/* C89 <stdlib.h> */
542 # define EXIT_FAILURE	1
543@@ -89,6 +89,7 @@ dc_show_id DC_DECLARG((fp, id, suffix))
544 		fprintf(fp, "'%c' (%#o)%s", (unsigned int) id, id, suffix);
545 	else
546 		fprintf(fp, "%#o%s", (unsigned int) id, suffix);
547+	checkferror_output(fp);
548 }
549
550
551diff --git a/dc/numeric.c b/dc/numeric.c
552index 37759de..60cfb85 100644
553--- a/dc/numeric.c
554+++ b/dc/numeric.c
555@@ -133,6 +133,7 @@ dc_div DC_DECLARG((a, b, kscale, result))
556 	bc_init_num(CastNumPtr(result));
557 	if (bc_divide(CastNum(a), CastNum(b), CastNumPtr(result), kscale)){
558 		fprintf(stderr, "%s: divide by zero\n", progname);
559+		checkferror_output(stderr);
560 		return DC_DOMAIN_ERROR;
561 	}
562 	return DC_SUCCESS;
563@@ -155,6 +156,7 @@ dc_divrem DC_DECLARG((a, b, kscale, quotient, remainder))
564 	if (bc_divmod(CastNum(a), CastNum(b),
565 						CastNumPtr(quotient), CastNumPtr(remainder), kscale)){
566 		fprintf(stderr, "%s: divide by zero\n", progname);
567+		checkferror_output(stderr);
568 		return DC_DOMAIN_ERROR;
569 	}
570 	return DC_SUCCESS;
571@@ -173,6 +175,7 @@ dc_rem DC_DECLARG((a, b, kscale, result))
572 	bc_init_num(CastNumPtr(result));
573 	if (bc_modulo(CastNum(a), CastNum(b), CastNumPtr(result), kscale)){
574 		fprintf(stderr, "%s: remainder by zero\n", progname);
575+		checkferror_output(stderr);
576 		return DC_DOMAIN_ERROR;
577 	}
578 	return DC_SUCCESS;
579@@ -225,6 +228,7 @@ dc_sqrt DC_DECLARG((value, kscale, result))
580 	tmp = bc_copy_num(CastNum(value));
581 	if (!bc_sqrt(&tmp, kscale)){
582 		fprintf(stderr, "%s: square root of negative number\n", progname);
583+		checkferror_output(stderr);
584 		bc_free_num(&tmp);
585 		return DC_DOMAIN_ERROR;
586 	}
587@@ -470,6 +474,7 @@ dc_dump_num DC_DECLARG((dcvalue, discard_p))
588
589 	for (cur=top_of_stack; cur; cur=next) {
590 		putchar(cur->digit);
591+		checkferror_output(stdout);
592 		next = cur->link;
593 		free(cur);
594 	}
595@@ -587,6 +592,8 @@ out_char (ch)
596 			out_col = 1;
597 		}
598 		putchar(ch);
599+                checkferror_output(stdout);
600+		checkferror_output(stderr);
601 	}
602 }
603
604@@ -626,6 +633,7 @@ rt_error (mesg, va_alist)
605 	vfprintf (stderr, mesg, args);
606 	va_end (args);
607 	fprintf (stderr, "\n");
608+	checkferror_output(stderr);
609 }
610
611
612@@ -659,6 +667,7 @@ rt_warn (mesg, va_alist)
613 	vfprintf (stderr, mesg, args);
614 	va_end (args);
615 	fprintf (stderr, "\n");
616+	checkferror_output(stderr);
617 }
618
619
620diff --git a/dc/stack.c b/dc/stack.c
621index 49422df..174411d 100644
622--- a/dc/stack.c
623+++ b/dc/stack.c
624@@ -33,9 +33,13 @@
625 #include "dc.h"
626 #include "dc-proto.h"
627 #include "dc-regdef.h"
628+#include "number.h"
629
630 /* an oft-used error message: */
631-#define Empty_Stack	fprintf(stderr, "%s: stack empty\n", progname)
632+#define Empty_Stack do{					\
633+    fprintf(stderr, "%s: stack empty\n", progname);	\
634+    checkferror_output(stderr);				\
635+  }while(0)
636
637
638 /* simple linked-list implementation suffices: */
639@@ -91,6 +94,7 @@ dc_binop DC_DECLARG((op, kscale))
640 	if (dc_stack->value.dc_type!=DC_NUMBER
641 			|| dc_stack->link->value.dc_type!=DC_NUMBER){
642 		fprintf(stderr, "%s: non-numeric value\n", progname);
643+		checkferror_output(stderr);
644 		return;
645 	}
646 	(void)dc_pop(&b);
647@@ -131,6 +135,7 @@ dc_binop2 DC_DECLARG((op, kscale))
648 	if (dc_stack->value.dc_type!=DC_NUMBER
649 			|| dc_stack->link->value.dc_type!=DC_NUMBER){
650 		fprintf(stderr, "%s: non-numeric value\n", progname);
651+		checkferror_output(stderr);
652 		return;
653 	}
654 	(void)dc_pop(&b);
655@@ -169,6 +174,7 @@ dc_cmpop DC_DECLVOID()
656 	if (dc_stack->value.dc_type!=DC_NUMBER
657 			|| dc_stack->link->value.dc_type!=DC_NUMBER){
658 		fprintf(stderr, "%s: non-numeric value\n", progname);
659+		checkferror_output(stderr);
660 		return 0;
661 	}
662 	(void)dc_pop(&b);
663@@ -206,6 +212,7 @@ dc_triop DC_DECLARG((op, kscale))
664 			|| dc_stack->link->value.dc_type!=DC_NUMBER
665 			|| dc_stack->link->link->value.dc_type!=DC_NUMBER){
666 		fprintf(stderr, "%s: non-numeric value\n", progname);
667+		checkferror_output(stderr);
668 		return;
669 	}
670 	(void)dc_pop(&c);
671@@ -327,6 +334,7 @@ dc_register_get DC_DECLARG((regid, result))
672 		*result = dc_int2data(0);
673 	}else if (r->value.dc_type==DC_UNINITIALIZED){
674 		fprintf(stderr, "%s: BUG: register ", progname);
675+		checkferror_output(stderr);
676 		dc_show_id(stderr, regid, " exists but is uninitialized?\n");
677 		return DC_FAIL;
678 	}else{
679@@ -402,6 +410,7 @@ dc_register_pop DC_DECLARG((stackid, result))
680 	r = dc_register[stackid];
681 	if (r==NULL || r->value.dc_type==DC_UNINITIALIZED){
682 		fprintf(stderr, "%s: stack register ", progname);
683+		checkferror_output(stderr);
684 		dc_show_id(stderr, stackid, " is empty\n");
685 		return DC_FAIL;
686 	}
687diff --git a/dc/string.c b/dc/string.c
688index dee9169..389d899 100644
689--- a/dc/string.c
690+++ b/dc/string.c
691@@ -45,6 +45,7 @@
692 #endif
693 #include "dc.h"
694 #include "dc-proto.h"
695+#include "number.h"
696
697 /* here is the completion of the dc_string type: */
698 struct dc_string {
699@@ -94,6 +94,7 @@ dc_out_str DC_DECLARG((value, discard_flag))
700 	dc_discard discard_flag DC_DECLEND
701 {
702 	fwrite(value->s_ptr, value->s_len, sizeof *value->s_ptr, stdout);
703+        checkferror_output(stdout);
704 	if (discard_flag == DC_TOSS)
705 		dc_free_str(&value);
706 }
707@@ -169,6 +170,7 @@ dc_readstring DC_DECLARG((fp, ldelim, rdelim))
708 		}
709 		*p++ = c;
710 	}
711+	checkferror_input(fp);
712 	return dc_makestring(line_buf, (size_t)(p-line_buf));
713 }
714
715diff --git a/h/number.h b/h/number.h
716index abf6332..1983ab4 100644
717--- a/h/number.h
718+++ b/h/number.h
719@@ -23,10 +23,10 @@
720     You may contact the author by:
721        e-mail:  philnelson@acm.org
722       us-mail:  Philip A. Nelson
723-                Computer Science Department, 9062
724-                Western Washington University
725-                Bellingham, WA 98226-9062
726-
727+		Computer Science Department, 9062
728+		Western Washington University
729+		Bellingham, WA 98226-9062
730+
731 *************************************************************************/
732
733 #ifndef _NUMBER_H_
734@@ -140,4 +140,7 @@ void bc_out_num (bc_num num, int o_base, void (* out_char)(int),
735 			     int leading_zero);
736
737 void bc_out_long (long val, int size, int space, void (*out_char)(int));
738+
739+void checkferror_input (FILE*);
740+void checkferror_output (FILE*);
741 #endif
742diff --git a/lib/number.c b/lib/number.c
743index f394e92..80b33e3 100644
744--- a/lib/number.c
745+++ b/lib/number.c
746@@ -1713,6 +1713,7 @@ static void
747 out_char (int c)
748 {
749   putchar(c);
750+  checkferror_output(stdout);
751 }
752
753
754@@ -1721,6 +1722,7 @@ pn (bc_num num)
755 {
756   bc_out_num (num, 10, out_char, 0);
757   out_char ('\n');
758+  checkferror_output(stdout);
759 }
760
761
762@@ -1732,6 +1734,28 @@ pv (char *name, unsigned char *num, int len)
763   printf ("%s=", name);
764   for (i=0; i<len; i++) printf ("%c",BCD_CHAR(num[i]));
765   printf ("\n");
766+  checkferror_output(stdout);
767 }
768
769 #endif
770+
771+/* check ferror() status and if so die */
772+void
773+checkferror_input (fp)
774+	FILE *fp;
775+{
776+	if (ferror(fp)) {
777+		perror("dc: could not read input file");
778+		exit(EXIT_FAILURE);
779+	}
780+}
781+
782+void
783+checkferror_output (fp)
784+	FILE *fp;
785+{
786+	if (ferror(fp)) {
787+		perror("dc: could not write output file");
788+		exit(EXIT_FAILURE);
789+	}
790+}
791--
7922.17.1
793
794