1 /*
2 * `dc' desk calculator utility.
3 *
4 * Copyright (C) 1984, 1993 Free Software Foundation, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you can either send email to this
18 * program's author (see below) or write to: The Free Software Foundation,
19 * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
20 */
21
22 #include <stdio.h>
23 #include "decimal.h" /* definitions for our decimal arithmetic package */
24
25 FILE *open_file; /* input file now open */
26 int file_count; /* Number of input files not yet opened */
27 char **next_file; /* Pointer to vector of names of input files left */
28
29 struct regstack
30 {
31 decimal value; /* Saved value of register */
32 struct regstack *rest; /* Tail of list */
33 };
34
35 typedef struct regstack *regstack;
36
37 regstack freeregstacks; /* Chain of free regstack structures for fast realloc */
38
39 decimal regs[128]; /* "registers", with single-character names */
40 regstack regstacks[128]; /* For each register, a stack of previous values */
41
42 int stacktop; /* index of last used element in stack */
43 int stacksize; /* Current allocates size of stack */
44 decimal *stack; /* Pointer to computation stack */
45
46 /* A decimal number can be regarded as a string by
47 treating its contents as characters and ignoring the
48 position of its decimal point.
49 Decimal numbers are marked as strings by having an `after' field of -1
50 One use of strings is to execute them as macros.
51 */
52
53 #define STRING -1
54
55 int macrolevel; /* Current macro nesting; 0 if taking keyboard input */
56 int macrostacksize; /* Current allocated size of macrostack and macroindex */
57 decimal *macrostack; /* Pointer to macro stack array */
58 int *macroindex; /* Pointer to index-within-macro stack array */
59 /* Note that an empty macro is popped from the stack
60 only when an trying to read a character from it
61 or trying to push another macro. */
62
63 int ibase; /* Radix for numeric input. */
64 int obase; /* Radix for numeric output. */
65 int precision; /* Number of digits to keep in multiply and divide. */
66
67 char *buffer; /* Address of buffer used for reading numbers */
68 int bufsize; /* Current size of buffer (made bigger when nec) */
69
70 decimal dec_read ();
71 regstack get_regstack ();
72 int fetch ();
73 int fgetchar ();
74 char *concat ();
75 void pushsqrt ();
76 void condop ();
77 void setibase ();
78 void setobase ();
79 void setprecision ();
80 void pushmacro ();
81 decimal read_string ();
82 void pushlength ();
83 void pushscale ();
84 void unfetch ();
85 void popmacros ();
86 void popmacro ();
87 void popstack ();
88 void print_obj ();
89 void print_string ();
90 void free_regstack ();
91 void pushreg ();
92 void execute ();
93 void fputchar ();
94 void push ();
95 void incref ();
96 void decref ();
97 void binop ();
98
main(argc,argv,env)99 main (argc, argv, env)
100 int argc;
101 char **argv, **env;
102 {
103
104 ibase = 10;
105 obase = 10;
106 precision = 0;
107
108 freeregstacks = 0;
109
110 bzero (regs, sizeof regs);
111 bzero (regstacks, sizeof regstacks);
112
113 bufsize = 40;
114 buffer = (char *) xmalloc (40);
115
116 stacksize = 40;
117 stack = (decimal *) xmalloc (stacksize * sizeof (decimal));
118 stacktop = -1;
119
120 macrostacksize = 40;
121 macrostack = (decimal *) xmalloc (macrostacksize * sizeof (decimal));
122 macroindex = (int *) xmalloc (macrostacksize * sizeof (int));
123 macrolevel = 0;
124 /* Initialize for reading input files if any */
125
126 open_file = 0;
127
128 file_count = argc - 1;
129 next_file = argv + 1;
130
131
132 while (1)
133 {
134 execute ();
135 }
136 }
137
138 /* Read and execute one command from the current source of input */
139
140 void
execute()141 execute ()
142 {
143 int c = fetch ();
144
145 if (c < 0) exit (0);
146
147 {
148 switch (c)
149 {
150 case '+': /* Arithmetic operators... */
151 binop (decimal_add);
152 break;
153
154 case '-':
155 binop (decimal_sub);
156 break;
157
158 case '*':
159 binop (decimal_mul_dc); /* Like decimal_mul but hairy
160 way of deciding precision to keep */
161 break;
162
163 case '/':
164 binop (decimal_div);
165 break;
166
167 case '%':
168 binop (decimal_rem);
169 break;
170
171 case '^':
172 binop (decimal_expt);
173 break;
174
175 case '_': /* Begin a negative decimal constant */
176 {
177 decimal tem = dec_read (stdin);
178 tem->sign = !tem->sign;
179 push (tem);
180 }
181 break;
182
183 case '.':
184 case '0':
185 case '1':
186 case '2':
187 case '3':
188 case '4':
189 case '5':
190 case '6':
191 case '7':
192 case '8':
193 case '9': /* All these begin decimal constants */
194 unfetch (c);
195 push (dec_read (stdin));
196 break;
197
198 case 'A':
199 case 'B':
200 case 'C':
201 case 'D':
202 case 'E':
203 case 'F':
204 unfetch (c);
205 push (dec_read (stdin));
206 break;
207
208 case 'c': /* Clear the stack */
209 while (stacktop >= 0)
210 decref (stack[stacktop--]);
211 break;
212
213 case 'd': /* Duplicate top of stack */
214 if (stacktop < 0)
215 error ("stack empty", 0);
216 else push (stack[stacktop]);
217 break;
218
219 case 'f': /* Describe all registers and stack contents */
220 {
221 int regno;
222 int somereg = 0; /* set to 1 if we print any registers */
223 for (regno = 0; regno < 128; regno++)
224 {
225 if (regs[regno])
226 {
227 printf ("register %c: ", regno);
228 print_obj (regs[regno]);
229 somereg = 1;
230 printf ("\n");
231 }
232 }
233 if (somereg)
234 printf ("\n");
235 if (stacktop < 0)
236 printf ("stack empty\n");
237 else
238 {
239 int i;
240 printf ("stack:\n");
241 for (i = 0; i <= stacktop; i++)
242 {
243 print_obj (stack[stacktop - i]);
244 printf ("\n");
245 }
246 }
247 }
248 break;
249
250 case 'i': /* ibase <- top of stack */
251 popstack (setibase);
252 break;
253
254 case 'I': /* Push current ibase */
255 push (decimal_from_int (ibase));
256 break;
257
258 case 'k': /* like i, I but for precision instead of ibase */
259 popstack (setprecision);
260 break;
261
262 case 'K':
263 push (decimal_from_int (precision));
264 break;
265
266 case 'l': /* l<x> load register <x> onto stack */
267 {
268 char c1 = fetch ();
269 if (c1 < 0) exit (0);
270 if (!regs[c1])
271 error ("register %c empty", c1);
272 else
273 push (regs[c1]);
274 }
275 break;
276
277 case 'L': /* L<x> load register <x> to stack, pop <x>'s own stack */
278 {
279 char c1 = fetch ();
280 if (c1 < 0) exit (0);
281 if (!regstacks[c1])
282 error ("nothing pushed on register %c", c1);
283 else
284 {
285 regstack r = regstacks[c1];
286 if (!regs[c1])
287 error ("register %c empty after pop", c1);
288 else
289 push (regs[c1]);
290 regs[c1] = r->value;
291 regstacks[c1] = r->rest;
292 free_regstack (r);
293 }
294 }
295 break;
296
297 case 'o': /* o, O like i, I but for obase instead of ibase */
298 popstack (setobase);
299 break;
300
301 case 'O':
302 push (decimal_from_int (obase));
303 break;
304
305 case 'p': /* Print tos, don't pop, do print newline afterward */
306 if (stacktop < 0)
307 error ("stack empty", 0);
308 else
309 {
310 print_obj (stack[stacktop]);
311 printf ("\n");
312 }
313 break;
314
315 case 'P': /* Print tos, do pop, no newline afterward */
316 popstack (print_obj);
317 break;
318
319 case 'q': /* Exit */
320 if (macrolevel)
321 { popmacro (); popmacro (); } /* decrease recursion level by 2 */
322 else
323 exit (0); /* If not in a macro, exit the program. */
324
325 break;
326
327 case 'Q': /* Tos says how many levels to exit */
328 popstack (popmacros);
329 break;
330
331 case 's': /* s<x> -- Pop stack and set register <x> */
332 if (stacktop < 0)
333 empty ();
334 else
335 {
336 int c1 = fetch ();
337 if (c1 < 0) exit (0);
338 if (regs[c1]) decref (regs[c1]);
339 regs[c1] = stack[stacktop--];
340 }
341 break;
342
343 case 'S': /* S<x> -- pop stack and push as new value of register <x> */
344 if (stacktop < 0)
345 empty ();
346 else
347 {
348 int c1 = fetch ();
349 if (c1 < 0) exit (0);
350 pushreg (c1);
351 regs[c1] = stack[stacktop--];
352 }
353 break;
354
355 case 'v': /* tos gets square root of tos */
356 popstack (pushsqrt);
357 break;
358
359 case 'x': /* pop stack , call as macro */
360 popstack (pushmacro);
361 break;
362
363 case 'X': /* Pop stack, get # fraction digits, push that */
364 popstack (pushscale);
365 break;
366
367 case 'z': /* Compute depth of stack, push that */
368 push (decimal_from_int (stacktop + 1));
369 break;
370
371 case 'Z': /* Pop stack, get # digits, push that */
372 popstack (pushlength);
373 break;
374
375 case '<': /* Conditional: pop two numbers, compare, maybe execute register */
376 /* Note: for no obvious reason, the standard Unix `dc'
377 considers < to be true if the top of stack is less
378 than the next-to-top of stack,
379 and vice versa for >.
380 This seems backwards to me, but I am preserving compatibility. */
381 condop (1);
382 break;
383
384 case '>':
385 condop (-1);
386 break;
387
388 case '=':
389 condop (0);
390 break;
391
392 case '?': /* Read expression from terminal and execute it */
393 /* First ignore any leading newlines */
394 {
395 int c1;
396 while ((c1 = getchar ()) == '\n');
397 ungetc (c1, stdin);
398 }
399 /* Read a line from the terminal and execute it. */
400 pushmacro (read_string ('\n', fgetchar, 0));
401 break;
402
403 case '[': /* Begin string constant */
404 push (read_string (']', fetch, '['));
405 break;
406
407 case ' ':
408 case '\n':
409 break;
410
411 default:
412 error ("undefined command %c", c);
413 }
414 }
415 }
416
417 /* Functionals for performing arithmetic, etc */
418
419 /* Call the function `op', with the top of stack value as argument,
420 and then pop the stack.
421 If the stack is empty, print a message and do not call `op'. */
422
423 void
424 popstack (op)
425 void (*op) ();
426 {
427 if (stacktop < 0)
428 empty ();
429 else
430 {
431 decimal value = stack[stacktop--];
432 op (value);
433 decref (value);
434 }
435 }
436
437 /* Call the function `op' with two arguments taken from the stack top,
438 then pop those arguments and push the value returned by `op'.
439 `op' is assumed to return a decimal number.
440 If there are not two values on the stack, print a message
441 and do not call `op'. */
442
443 void
444 binop (op)
445 decimal (*op) ();
446 {
447 if (stacktop < 1)
448 error ("stack empty", 0);
449 else if (stack[stacktop]->after == STRING || stack[stacktop - 1]->after == STRING)
450 error ("operands not both numeric");
451 else
452 {
453 decimal arg2 = stack [stacktop--];
454 decimal arg1 = stack [stacktop--];
455
456 push (op (arg1, arg2, precision));
457
458 decref (arg1);
459 decref (arg2);
460 }
461 }
462
463 void
condop(cond)464 condop (cond)
465 int cond;
466 {
467 int regno = fetch ();
468 if (!regs[regno])
469 error ("register %c is empty", regno);
470 else if (stacktop < 1)
471 empty ();
472 else
473 {
474 decimal arg2 = stack[stacktop--];
475 decimal arg1 = stack[stacktop--];
476 int relation = decimal_compare (arg1, arg2);
477 decref (arg1);
478 decref (arg2);
479 if (cond == relation
480 || (cond < 0 && relation < 0)
481 || (cond > 0 && relation > 0))
482 pushmacro (regs[regno]);
483 }
484 }
485
486 /* Handle the command input source */
487
488 /* Fetch the next command character from a macro or from the terminal */
489
490 int
fetch()491 fetch()
492 {
493 int c = -1;
494
495 while (macrolevel &&
496 LENGTH (macrostack[macrolevel-1]) == macroindex[macrolevel-1])
497 popmacro();
498 if (macrolevel)
499 return macrostack[macrolevel - 1]->contents[macroindex[macrolevel-1]++];
500 while (1)
501 {
502 if (open_file)
503 {
504 c = getc (open_file);
505 if (c >= 0) break;
506 fclose (open_file);
507 open_file = 0;
508 }
509 else if (file_count)
510 {
511 open_file = fopen (*next_file++, "r");
512 file_count--;
513 if (!open_file)
514 perror_with_name (*(next_file - 1));
515 }
516 else break;
517 }
518 if (c >= 0) return c;
519 return getc (stdin);
520 }
521
522 /* Unread character c on command input stream, whatever it is */
523
524 void
unfetch(c)525 unfetch (c)
526 char c;
527 {
528 if (macrolevel)
529 macroindex[macrolevel-1]--;
530 else if (open_file)
531 ungetc (c, open_file);
532 else
533 ungetc (c, stdin);
534 }
535
536 /* Begin execution of macro m. */
537
538 void
pushmacro(m)539 pushmacro (m)
540 decimal m;
541 {
542 while (macrolevel &&
543 LENGTH (macrostack[macrolevel-1]) == macroindex[macrolevel-1])
544 popmacro();
545 if (m->after == STRING)
546 {
547 if (macrolevel == macrostacksize)
548 {
549 macrostacksize *= 2;
550 macrostack = (decimal *) xrealloc (macrostack, macrostacksize * sizeof (decimal));
551 macroindex = (int *) xrealloc (macroindex, macrostacksize * sizeof (int));
552 }
553 macroindex[macrolevel] = 0;
554 macrostack[macrolevel++] = m;
555 incref (m);
556 }
557 else
558 { /* Number supplied as a macro! */
559 push (m); /* Its effect wouyld be to push the number. */
560 }
561 }
562
563 /* Pop a specified number of levels of macro execution.
564 The number of levels is specified by a decimal number d. */
565
566 void
popmacros(d)567 popmacros (d)
568 decimal d;
569 {
570 int num_pops = decimal_to_int (d);
571 int i;
572 for (i = 0; i < num_pops; i++)
573 popmacro ();
574 }
575 /* Exit one level of macro execution. */
576
577 void
popmacro()578 popmacro ()
579 {
580 if (!macrolevel)
581 exit (0);
582 else
583 {
584 decref (macrostack[--macrolevel]);
585 }
586 }
587
588 void
push(d)589 push (d)
590 decimal d;
591 {
592 if (stacktop == stacksize - 1)
593 stack = (decimal *) xrealloc (stack, (stacksize *= 2) * sizeof (decimal));
594
595 incref (d);
596
597 stack[++stacktop] = d;
598 }
599
600 /* Reference counting and storage freeing */
601
602 void
decref(d)603 decref (d)
604 decimal d;
605 {
606 if (!--d->refcnt)
607 free (d);
608 }
609
610 void
incref(d)611 incref (d)
612 decimal d;
613 {
614 d->refcnt++;
615 }
616
empty()617 empty ()
618 {
619 error ("stack empty", 0);
620 }
621
622 regstack
get_regstack()623 get_regstack ()
624 {
625 if (freeregstacks)
626 {
627 regstack r = freeregstacks;
628 freeregstacks = r ->rest;
629 return r;
630 }
631 else
632 return (regstack) xmalloc (sizeof (struct regstack));
633 }
634
635 void
free_regstack(r)636 free_regstack (r)
637 regstack r;
638 {
639 r->rest = freeregstacks;
640 freeregstacks = r;
641 }
642
643 void
pushreg(c)644 pushreg (c)
645 char c;
646 {
647 regstack r = get_regstack ();
648
649 r->rest = regstacks[c];
650 r->value = regs[c];
651 regstacks[c] = r;
652 regs[c] = 0;
653 }
654
655 /* Input of numbers and strings */
656
657 /* Return a character read from the terminal. */
658
fgetchar()659 fgetchar ()
660 {
661 return getchar ();
662 }
663
664 void
665 fputchar (c)
666 char (c);
667 {
668 putchar (c);
669 }
670
671 /* Read text from command input source up to a close-bracket,
672 make a string out of it, and return it.
673 If STARTC is nonzero, then it and STOPC must balance when nested. */
674
675 decimal
read_string(stopc,inputfn,startc)676 read_string (stopc, inputfn, startc)
677 char stopc;
678 int (*inputfn) ();
679 int startc;
680 {
681 int c;
682 decimal result;
683 int i = 0;
684 int count = 0;
685
686 while (1)
687 {
688 c = inputfn ();
689 if (c < 0 || (c == stopc && count == 0))
690 {
691 if (count != 0)
692 error ("Unmatched `%c'", startc);
693 break;
694 }
695 if (c == stopc)
696 count--;
697 if (c == startc)
698 count++;
699 if (i + 1 >= bufsize)
700 buffer = (char *) xrealloc (buffer, bufsize *= 2);
701 buffer[i++] = c;
702 }
703 result = make_decimal (i, 0);
704 result->after = -1; /* Mark it as a string */
705 result->before++; /* but keep the length unchanged */
706 bcopy (buffer, result->contents, i);
707 return result;
708 }
709
710 /* Read a number from the current input source */
711
712 decimal
dec_read()713 dec_read ()
714 {
715 int c;
716 int i = 0;
717
718 while (1)
719 {
720 c = fetch ();
721 if (! ((c >= '0' && c <= '9')
722 || (c >= 'A' && c <= 'F')
723 || c == '.'))
724 break;
725 if (i + 1 >= bufsize)
726 buffer = (char *) xrealloc (buffer, bufsize *= 2);
727 buffer[i++] = c;
728 }
729 buffer[i++] = 0;
730 unfetch (c);
731
732 return decimal_parse (buffer, ibase);
733 }
734
735 /* Output of numbers and strings */
736
737 /* Print the contents of obj, either numerically or as a string,
738 according to what obj says it is. */
739
740 void
print_obj(obj)741 print_obj (obj)
742 decimal obj;
743 {
744 if (obj->after == STRING)
745 print_string (obj);
746 else
747 decimal_print (obj, fputchar, obase);
748 }
749
750 /* Print the contents of the decimal number `string', treated as a string. */
751
752 void
print_string(string)753 print_string (string)
754 decimal string;
755 {
756 char *p = string->contents;
757 int len = LENGTH (string);
758 int i;
759
760 for (i = 0; i < len; i++)
761 {
762 putchar (*p++);
763 }
764 }
765
766 /* Set the input radix from the value of the decimal number d, if valid. */
767
768 void
setibase(d)769 setibase (d)
770 decimal d;
771 {
772 int value = decimal_to_int (d);
773 if (value < 2 || value > 36)
774 error ("input radix must be from 2 to 36", 0);
775 else
776 ibase = value;
777 }
778
779 /* Set the output radix from the value of the decimal number d, if valid. */
780
781 void
setobase(d)782 setobase (d)
783 decimal d;
784 {
785 int value = decimal_to_int (d);
786 if (value < 2 || value > 36)
787 error ("output radix must be from 2 to 36", 0);
788 else
789 obase = value;
790 }
791
792 /* Set the precision for mul and div from the value of the decimal number d, if valid. */
793
794 void
setprecision(d)795 setprecision (d)
796 decimal d;
797 {
798 int value = decimal_to_int (d);
799 if (value < 0 || value > 30000)
800 error ("precision must be nonnegative and < 30000", 0);
801 else
802 precision = value;
803 }
804
805 /* Push the number of digits in decimal number d, as a decimal number. */
806
807 void
pushlength(d)808 pushlength (d)
809 decimal d;
810 {
811 push (decimal_from_int (LENGTH (d)));
812 }
813
814 /* Push the number of fraction digits in d. */
815
816 void
pushscale(d)817 pushscale (d)
818 decimal d;
819 {
820 push (decimal_from_int (d->after));
821 }
822
823 /* Push the square root of decimal number d. */
824
825 void
pushsqrt(d)826 pushsqrt (d)
827 decimal d;
828 {
829 push (decimal_sqrt (d, precision));
830 }
831
832 /* Print error message and exit. */
833
fatal(s1,s2)834 fatal (s1, s2)
835 char *s1, *s2;
836 {
837 error (s1, s2);
838 exit (1);
839 }
840
841 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
842
error(s1,s2)843 error (s1, s2)
844 char *s1, *s2;
845 {
846 printf ("dc: ");
847 printf (s1, s2);
848 printf ("\n");
849 }
850
decimal_error(s1,s2)851 decimal_error (s1, s2)
852 char *s1, *s2;
853 {
854 error (s1, s2);
855 }
856
perror_with_name(name)857 perror_with_name (name)
858 char *name;
859 {
860 extern int errno, sys_nerr;
861 extern char *sys_errlist[];
862 char *s;
863
864 if (errno < sys_nerr)
865 s = concat ("", sys_errlist[errno], " for %s");
866 else
867 s = "cannot open %s";
868 error (s, name);
869 }
870
871 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
872
873 char *
concat(s1,s2,s3)874 concat (s1, s2, s3)
875 char *s1, *s2, *s3;
876 {
877 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
878 char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
879
880 strcpy (result, s1);
881 strcpy (result + len1, s2);
882 strcpy (result + len1 + len2, s3);
883 *(result + len1 + len2 + len3) = 0;
884
885 return result;
886 }
887
888 /* Like malloc but get fatal error if memory is exhausted. */
889
890 int
xmalloc(size)891 xmalloc (size)
892 int size;
893 {
894 int result = malloc (size);
895 if (!result)
896 fatal ("virtual memory exhausted", 0);
897 return result;
898 }
899
900 int
xrealloc(ptr,size)901 xrealloc (ptr, size)
902 char *ptr;
903 int size;
904 {
905 int result = realloc (ptr, size);
906 if (!result)
907 fatal ("virtual memory exhausted");
908 return result;
909 }
910