modified: diffout.py
[GalaxyCodeBases.git] / c_cpp / etc / calc / zio.c
blobceb39f249aa127a7615d672a866300e0a10842cf
1 /*
2 * zio - scanf and printf routines for arbitrary precision integers
4 * Copyright (C) 1999-2007 David I. Bell
6 * Calc is open software; you can redistribute it and/or modify it under
7 * the terms of the version 2.1 of the GNU Lesser General Public License
8 * as published by the Free Software Foundation.
10 * Calc is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
13 * Public License for more details.
15 * A copy of version 2.1 of the GNU Lesser General Public License is
16 * distributed with calc under the filename COPYING-LGPL. You should have
17 * received a copy with calc; if not, write to Free Software Foundation, Inc.
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * @(#) $Revision: 30.2 $
21 * @(#) $Id: zio.c,v 30.2 2013/08/11 08:41:38 chongo Exp $
22 * @(#) $Source: /usr/local/src/bin/calc/RCS/zio.c,v $
24 * Under source code control: 1993/07/30 19:42:48
25 * File existed as early as: 1993
27 * Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
31 #include <stdio.h>
32 #include "config.h"
33 #include "zmath.h"
34 #include "args.h"
37 #define OUTBUFSIZE 200 /* realloc size for output buffers */
39 #define PUTCHAR(ch) math_chr(ch)
40 #define PUTSTR(str) math_str(str)
41 #define PRINTF1(fmt, a1) math_fmt(fmt, a1)
42 #define PRINTF2(fmt, a1, a2) math_fmt(fmt, a1, a2)
43 #define PRINTF3(fmt, a1, a2, a3) math_fmt(fmt, a1, a2, a3)
44 #define PRINTF4(fmt, a1, a2, a3, a4) math_fmt(fmt, a1, a2, a3, a4)
48 * Output state that has been saved when diversions are done.
50 typedef struct iostate IOSTATE;
51 struct iostate {
52 IOSTATE *oldiostates; /* previous saved state */
53 long outdigits; /* digits for output */
54 int outmode; /* output mode */
55 int outmode2; /* secondary output mode */
56 FILE *outfp; /* file unit for output (if any) */
57 char *outbuf; /* output string buffer (if any) */
58 size_t outbufsize; /* current size of string buffer */
59 size_t outbufused; /* space used in string buffer */
60 BOOL outputisstring; /* TRUE if output is to string buffer */
64 STATIC IOSTATE *oldiostates = NULL; /* list of saved output states */
65 STATIC FILE *outfp = NULL; /* file unit for output */
66 STATIC char *outbuf = NULL; /* current diverted buffer */
67 STATIC BOOL outputisstring = FALSE;
68 STATIC size_t outbufsize;
69 STATIC size_t outbufused;
73 * zio_init - perform needed initilization work
75 * On some systems, one cannot initialize a pointer to a FILE *.
76 * This routine, called once at startup is a work-a-round for
77 * systems with such bogons.
79 void
80 zio_init(void)
82 STATIC int done = 0; /* 1 => routine already called */
84 if (!done) {
85 outfp = stdout;
86 done = 1;
92 * Routine to output a character either to a FILE
93 * handle or into a string.
95 void
96 math_chr(int ch)
98 char *cp;
100 if (!outputisstring) {
101 fputc(ch, outfp);
102 return;
104 if (outbufused >= outbufsize) {
105 cp = (char *)realloc(outbuf, outbufsize + OUTBUFSIZE + 1);
106 if (cp == NULL) {
107 math_error("Cannot realloc output string");
108 /*NOTREACHED*/
110 outbuf = cp;
111 outbufsize += OUTBUFSIZE;
113 outbuf[outbufused++] = (char)ch;
118 * Routine to output a null-terminated string either
119 * to a FILE handle or into a string.
121 void
122 math_str(char *str)
124 char *cp;
125 size_t len;
127 if (!outputisstring) {
128 fputs(str, outfp);
129 return;
131 len = strlen(str);
132 if ((outbufused + len) > outbufsize) {
133 cp = (char *)realloc(outbuf, outbufsize + len + OUTBUFSIZE + 1);
134 if (cp == NULL) {
135 math_error("Cannot realloc output string");
136 /*NOTREACHED*/
138 outbuf = cp;
139 outbufsize += (len + OUTBUFSIZE);
141 memcpy(&outbuf[outbufused], str, len);
142 outbufused += len;
147 * Output a null-terminated string either to a FILE handle or into a string,
148 * padded with spaces as needed so as to fit within the specified width.
149 * If width is positive, the spaces are added at the front of the string.
150 * If width is negative, the spaces are added at the end of the string.
151 * The complete string is always output, even if this overflows the width.
152 * No characters within the string are handled specially.
154 void
155 math_fill(char *str, long width)
157 if (width > 0) {
158 width -= (long)strlen(str);
159 while (width-- > 0)
160 PUTCHAR(' ');
161 PUTSTR(str);
162 } else {
163 width += (long)strlen(str);
164 PUTSTR(str);
165 while (width++ < 0)
166 PUTCHAR(' ');
172 * Routine to output a printf-style formatted string either
173 * to a FILE handle or into a string.
175 void
176 math_fmt(char *fmt, ...)
178 va_list ap;
179 char buf[BUFSIZ+1];
181 va_start(ap, fmt);
182 vsnprintf(buf, BUFSIZ, fmt, ap);
183 va_end(ap);
184 buf[BUFSIZ] = '\0';
185 math_str(buf);
190 * Flush the current output stream.
192 void
193 math_flush(void)
195 if (!outputisstring)
196 fflush(outfp);
201 * Divert further output so that it is saved into a string that will be
202 * returned later when the diversion is completed. The current state of
203 * output is remembered for later restoration. Diversions can be nested.
204 * Output diversion is only intended for saving output to "stdout".
206 void
207 math_divertio(void)
209 register IOSTATE *sp;
211 sp = (IOSTATE *) malloc(sizeof(IOSTATE));
212 if (sp == NULL) {
213 math_error("No memory for diverting output");
214 /*NOTREACHED*/
216 sp->oldiostates = oldiostates;
217 sp->outdigits = conf->outdigits;
218 sp->outmode = conf->outmode;
219 sp->outmode2 = conf->outmode2;
220 sp->outfp = outfp;
221 sp->outbuf = outbuf;
222 sp->outbufsize = outbufsize;
223 sp->outbufused = outbufused;
224 sp->outputisstring = outputisstring;
226 outbufused = 0;
227 outbufsize = 0;
228 outbuf = (char *) malloc(OUTBUFSIZE + 1);
229 if (outbuf == NULL) {
230 math_error("Cannot allocate divert string");
231 /*NOTREACHED*/
233 outbufsize = OUTBUFSIZE;
234 outputisstring = TRUE;
235 oldiostates = sp;
240 * Undivert output and return the saved output as a string. This also
241 * restores the output state to what it was before the diversion began.
242 * The string needs freeing by the caller when it is no longer needed.
244 char *
245 math_getdivertedio(void)
247 register IOSTATE *sp;
248 char *cp;
250 sp = oldiostates;
251 if (sp == NULL) {
252 math_error("No diverted state to restore");
253 /*NOTREACHED*/
255 cp = outbuf;
256 cp[outbufused] = '\0';
257 oldiostates = sp->oldiostates;
258 conf->outdigits = sp->outdigits;
259 conf->outmode = sp->outmode;
260 conf->outmode2 = sp->outmode2;
261 outfp = sp->outfp;
262 outbuf = sp->outbuf;
263 outbufsize = sp->outbufsize;
264 outbufused = sp->outbufused;
265 outbuf = sp->outbuf;
266 outputisstring = sp->outputisstring;
267 free(sp);
268 return cp;
273 * Clear all diversions and set output back to the original destination.
274 * This is called when resetting the global state of the program.
276 void
277 math_cleardiversions(void)
279 while (oldiostates)
280 free(math_getdivertedio());
285 * Set the output routines to output to the specified FILE stream.
286 * This interacts with output diversion in the following manner.
287 * STDOUT diversion action
288 * ---- --------- ------
289 * yes yes set output to diversion string again.
290 * yes no set output to stdout.
291 * no yes set output to specified file.
292 * no no set output to specified file.
294 void
295 math_setfp(FILE *newfp)
297 outfp = newfp;
298 outputisstring = (oldiostates && (newfp == stdout));
303 * Set the output mode for numeric output.
304 * This also returns the previous mode.
307 math_setmode(int newmode)
309 int oldmode;
311 if ((newmode <= MODE_DEFAULT) || (newmode > MODE_MAX)) {
312 math_error("Setting illegal output mode");
313 /*NOTREACHED*/
315 oldmode = conf->outmode;
316 conf->outmode = newmode;
317 return oldmode;
322 * Set the secondary output mode for numeric output.
323 * This also returns the previous mode.
326 math_setmode2(int newmode)
328 int oldmode;
330 if (newmode != MODE2_OFF && ((newmode <= MODE_DEFAULT) ||
331 (newmode > MODE_MAX))) {
332 math_error("Setting illegal secondary output mode");
333 /*NOTREACHED*/
335 oldmode = conf->outmode2;
336 conf->outmode2 = newmode;
337 return oldmode;
342 * Set the number of digits for float or exponential output.
343 * This also returns the previous number of digits.
346 math_setdigits(LEN newdigits)
348 LEN olddigits;
350 if (newdigits < 0) {
351 math_error("Setting illegal number of digits");
352 /*NOTREACHED*/
354 olddigits = conf->outdigits;
355 conf->outdigits = newdigits;
356 return olddigits;
361 * Print an integer value as a hex number.
362 * Width is the number of columns to print the number in, including the
363 * sign if required. If zero, no extra output is done. If positive,
364 * leading spaces are typed if necessary. If negative, trailing spaces are
365 * typed if necessary. The special characters 0x appear to indicate the
366 * number is hex.
368 /*ARGSUSED*/
369 void
370 zprintx(ZVALUE z, long width)
372 register HALF *hp; /* current word to print */
373 int len; /* number of halfwords to type */
374 char *str;
376 if (width) {
377 math_divertio();
378 zprintx(z, 0L);
379 str = math_getdivertedio();
380 math_fill(str, width);
381 free(str);
382 return;
384 len = z.len - 1;
385 if (zisneg(z))
386 PUTCHAR('-');
387 if ((len == 0) && (*z.v <= (HALF) 9)) {
388 len = '0' + (int)(*z.v);
389 PUTCHAR(len & 0xff);
390 return;
392 hp = z.v + len;
393 #if BASEB == 32
394 PRINTF1("0x%lx", (PRINT) *hp--);
395 while (--len >= 0) {
396 PRINTF1("%08lx", (PRINT) *hp--);
398 #else /* BASEB == 32 */
399 PRINTF1("0x%lx", (FULL) *hp--);
400 while (--len >= 0) {
401 PRINTF1("%04lx", (FULL) *hp--);
403 #endif /* BASEB == 32 */
408 * Print an integer value as a binary number.
409 * The special characters 0b appear to indicate the number is binary.
411 /*ARGSUSED*/
412 void
413 zprintb(ZVALUE z, long width)
415 register HALF *hp; /* current word to print */
416 int len; /* number of halfwords to type */
417 HALF val; /* current value */
418 HALF mask; /* current mask */
419 int didprint; /* nonzero if printed some digits */
420 int ch; /* current char */
421 char *str;
423 if (width) {
424 math_divertio();
425 zprintb(z, 0L);
426 str = math_getdivertedio();
427 math_fill(str, width);
428 free(str);
429 return;
431 len = z.len - 1;
432 if (zisneg(z))
433 PUTCHAR('-');
434 if ((len == 0) && (*z.v <= (FULL) 1)) {
435 len = '0' + (int)(*z.v);
436 PUTCHAR(len & 0xff);
437 return;
439 hp = z.v + len;
440 didprint = 0;
441 PUTSTR("0b");
442 while (len-- >= 0) {
443 val = ((len >= 0) ? *hp-- : *hp);
444 mask = ((HALF)1 << (BASEB - 1));
445 while (mask) {
446 ch = '0' + ((mask & val) != 0);
447 if (didprint || (ch != '0')) {
448 PUTCHAR(ch & 0xff);
449 didprint = 1;
451 mask >>= 1;
458 * Print an integer value as an octal number.
459 * The number begins with a leading 0 to indicate that it is octal.
461 /*ARGSUSED*/
462 void
463 zprinto(ZVALUE z, long width)
465 register HALF *hp; /* current word to print */
466 int len; /* number of halfwords to type */
467 #if BASEB == 32 /* Yes, the larger base needs a smaller type! */
468 HALF num1='0'; /* numbers to type */
469 HALF num2=(HALF)0; /* numbers to type */
470 HALF num3; /* numbers to type */
471 HALF num4; /* numbers to type */
472 #else
473 FULL num1='0'; /* numbers to type */
474 FULL num2=(FULL)0; /* numbers to type */
475 #endif
476 int rem; /* remainder number of halfwords */
477 char *str;
479 if (width) {
480 math_divertio();
481 zprinto(z, 0L);
482 str = math_getdivertedio();
483 math_fill(str, width);
484 free(str);
485 return;
487 if (zisneg(z))
488 PUTCHAR('-');
489 len = z.len;
490 if ((len == 1) && (*z.v <= (FULL) 7)) {
491 num1 = '0' + (int)(*z.v);
492 PUTCHAR((int)(num1 & 0xff));
493 return;
495 hp = z.v + len - 1;
496 rem = len % 3;
497 #if BASEB == 32
498 switch (rem) { /* handle odd amounts first */
499 case 0:
500 num1 = ((hp[0]) >> 8);
501 num2 = (((hp[0] & 0xff) << 16) + (hp[-1] >> 16));
502 num3 = (((hp[-1] & 0xffff) << 8) + (hp[-2] >> 24));
503 num4 = (hp[-2] & 0xffffff);
504 if (num1) {
505 PRINTF4("0%lo%08lo%08lo%08lo",
506 (PRINT) num1, (PRINT) num2,
507 (PRINT) num3, (PRINT) num4);
508 } else {
509 PRINTF3("0%lo%08lo%08lo",
510 (PRINT) num2, (PRINT) num3, (PRINT) num4);
512 rem = 3;
513 break;
514 case 1:
515 PRINTF1("0%lo", (PRINT) hp[0]);
516 break;
517 case 2:
518 num1 = ((hp[0]) >> 16);
519 num2 = (((hp[0] & 0xffff) << 8) + (hp[-1] >> 24));
520 num3 = (hp[-1] & 0xffffff);
521 if (num1) {
522 PRINTF3("0%lo%08lo%08lo",
523 (PRINT) num1, (PRINT) num2, (PRINT) num3);
524 } else {
525 PRINTF2("0%lo%08lo", (PRINT) num2, (PRINT) num3);
527 break;
529 len -= rem;
530 if (len > 0) {
531 hp -= rem;
532 while (len > 0) { /* finish in groups of 3 words */
533 PRINTF4("%08lo%08lo%08lo%08lo",
534 (PRINT) ((hp[0]) >> 8),
535 (PRINT) (((hp[0] & 0xff) << 16) + (hp[-1] >> 16)),
536 (PRINT) (((hp[-1] & 0xffff) << 8) + (hp[-2] >> 24)),
537 (PRINT) (hp[-2] & 0xffffff));
538 hp -= 3;
539 len -= 3;
542 #else
543 switch (rem) { /* handle odd amounts first */
544 case 0:
545 num1 = ((((FULL) hp[0]) << 8) + (((FULL) hp[-1]) >> 8));
546 num2 = ((((FULL) (hp[-1] & 0xff)) << 16) + ((FULL) hp[-2]));
547 rem = 3;
548 break;
549 case 1:
550 num1 = 0;
551 num2 = (FULL) hp[0];
552 break;
553 case 2:
554 num1 = (((FULL) hp[0]) >> 8);
555 num2 = ((((FULL) (hp[0] & 0xff)) << 16) + ((FULL) hp[-1]));
556 break;
558 if (num1) {
559 PRINTF2("0%lo%08lo", num1, num2);
560 } else {
561 PRINTF1("0%lo", num2);
563 len -= rem;
564 if (len > 0) {
565 hp -= rem;
566 while (len > 0) { /* finish in groups of 3 halfwords */
567 PRINTF2("%08lo%08lo",
568 ((((FULL) hp[0]) << 8) + (((FULL) hp[-1]) >> 8)),
569 ((((FULL) (hp[-1] & 0xff))<<16) + ((FULL) hp[-2])));
570 hp -= 3;
571 len -= 3;
574 #endif
579 * Print a decimal integer to the terminal.
580 * This works by dividing the number by 10^2^N for some N, and
581 * then doing this recursively on the quotient and remainder.
582 * Decimals supplies number of decimal places to print, with a decimal
583 * point at the right location, with zero meaning no decimal point.
584 * Width is the number of columns to print the number in, including the
585 * decimal point and sign if required. If zero, no extra output is done.
586 * If positive, leading spaces are typed if necessary. If negative, trailing
587 * spaces are typed if necessary. As examples of the effects of these values,
588 * (345,0,0) = "345", (345,2,0) = "3.45", (345,5,8) = " .00345".
590 * given:
591 * z number to be printed
592 * decimals number of decimal places
593 * width number of columns to print in
595 void
596 zprintval(ZVALUE z, long decimals, long width)
598 int depth; /* maximum depth */
599 int n; /* current index into array */
600 long i; /* number to print */
601 long leadspaces; /* number of leading spaces to print */
602 long putpoint; /* digits until print decimal point */
603 long digits; /* number of digits of raw number */
604 BOOL output; /* TRUE if have output something */
605 BOOL neg; /* TRUE if negative */
606 ZVALUE quo, rem; /* quotient and remainder */
607 ZVALUE leftnums[32]; /* left parts of the number */
608 ZVALUE rightnums[32]; /* right parts of the number */
610 if (decimals < 0)
611 decimals = 0;
612 if (width < 0)
613 width = 0;
614 neg = (z.sign != 0);
616 leadspaces = width - neg - (decimals > 0);
617 z.sign = 0;
619 * Find the 2^N power of ten which is greater than or equal
620 * to the number, calculating it the first time if necessary.
622 _tenpowers_[0] = _ten_;
623 depth = 0;
624 while ((_tenpowers_[depth].len < z.len) ||
625 (zrel(_tenpowers_[depth], z) <= 0)) {
626 depth++;
627 if (_tenpowers_[depth].len == 0) {
628 if (depth <= TEN_MAX) {
629 zsquare(_tenpowers_[depth-1],
630 &_tenpowers_[depth]);
631 } else {
632 math_error("cannot compute 10^2^(TEN_MAX+1)");
633 /*NOTREACHED*/
638 * Divide by smaller 2^N powers of ten until the parts are small
639 * enough to output. This algorithm walks through a binary tree
640 * where each node is a piece of the number to print, and such that
641 * we visit left nodes first. We do the needed recursion in line.
643 digits = 1;
644 output = FALSE;
645 n = 0;
646 putpoint = 0;
647 rightnums[0].len = 0;
648 leftnums[0] = z;
649 for (;;) {
650 while (n < depth) {
651 i = depth - n - 1;
652 zdiv(leftnums[n], _tenpowers_[i], &quo, &rem, 0);
653 if (!ziszero(quo))
654 digits += (1L << i);
655 n++;
656 leftnums[n] = quo;
657 rightnums[n] = rem;
659 i = (long)(leftnums[n].v[0]);
660 if (output || i || (n == 0)) {
661 if (!output) {
662 output = TRUE;
663 if (decimals < digits)
664 leadspaces -= digits;
665 else
666 leadspaces -= decimals+conf->leadzero;
667 while (--leadspaces >= 0)
668 PUTCHAR(' ');
669 if (neg)
670 PUTCHAR('-');
671 if (decimals) {
672 putpoint = (digits - decimals);
673 if (putpoint <= 0) {
674 if (conf->leadzero)
675 PUTCHAR('0');
676 PUTCHAR('.');
677 while (++putpoint <= 0)
678 PUTCHAR('0');
679 putpoint = 0;
683 i += '0';
684 PUTCHAR((int)(i & 0xff));
685 if (--putpoint == 0)
686 PUTCHAR('.');
688 while (rightnums[n].len == 0) {
689 if (n <= 0)
690 return;
691 if (leftnums[n].len)
692 zfree(leftnums[n]);
693 n--;
695 zfree(leftnums[n]);
696 leftnums[n] = rightnums[n];
697 rightnums[n].len = 0;
703 * Read an integer value in decimal, hex, octal, or binary.
704 * Hex numbers are indicated by a leading "0x", binary with a leading "0b",
705 * and octal by a leading "0". Periods are skipped over, but any other
706 * extraneous character stops the scan.
708 void
709 str2z(char *s, ZVALUE *res)
711 ZVALUE z, ztmp, digit;
712 HALF digval;
713 BOOL minus;
714 long shift;
716 minus = FALSE;
717 shift = 0;
718 if (*s == '+')
719 s++;
720 else if (*s == '-') {
721 minus = TRUE;
722 s++;
724 if (*s == '0') { /* possibly hex, octal, or binary */
725 s++;
726 if ((*s >= '0') && (*s <= '7')) {
727 shift = 3;
728 } else if ((*s == 'x') || (*s == 'X')) {
729 shift = 4;
730 s++;
731 } else if ((*s == 'b') || (*s == 'B')) {
732 shift = 1;
733 s++;
736 digit.v = &digval;
737 digit.len = 1;
738 digit.sign = 0;
739 z = _zero_;
740 while (*s) {
741 digval = *s++;
742 if ((digval >= '0') && (digval <= '9'))
743 digval -= '0';
744 else if ((digval >= 'a') && (digval <= 'f') && shift)
745 digval -= ('a' - 10);
746 else if ((digval >= 'A') && (digval <= 'F') && shift)
747 digval -= ('A' - 10);
748 else if (digval == '.')
749 continue;
750 else
751 break;
752 if (shift)
753 zshift(z, shift, &ztmp);
754 else
755 zmuli(z, 10L, &ztmp);
756 zfree(z);
757 zadd(ztmp, digit, &z);
758 zfree(ztmp);
760 ztrim(&z);
761 if (minus && !ziszero(z))
762 z.sign = 1;
763 *res = z;
767 void
768 fitzprint(ZVALUE z, long digits, long show)
770 ZVALUE ztmp1, ztmp2;
771 long i;
773 if (digits <= show) {
774 zprintval(z, 0, 0);
775 return;
777 show /= 2;
778 ztenpow(digits - show, &ztmp1);
779 (void) zquo(z, ztmp1, &ztmp2, 1);
780 zprintval(ztmp2, 0, 0);
781 zfree(ztmp1);
782 zfree(ztmp2);
783 printf("...");
784 ztenpow(show, &ztmp1);
785 (void) zmod(z, ztmp1, &ztmp2, 0);
786 i = zdigits(ztmp2);
787 while (i++ < show)
788 printf("0");
789 zprintval(ztmp2, 0, 0);
790 zfree(ztmp1);
791 zfree(ztmp2);
794 /* END CODE */