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