📄 zio.c
字号:
/* * zio - scanf and printf routines for arbitrary precision integers * * Copyright (C) 1999-2006 David I. Bell * * Calc is open software; you can redistribute it and/or modify it under * the terms of the version 2.1 of the GNU Lesser General Public License * as published by the Free Software Foundation. * * Calc is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General * Public License for more details. * * A copy of version 2.1 of the GNU Lesser General Public License is * distributed with calc under the filename COPYING-LGPL. You should have * received a copy with calc; if not, write to Free Software Foundation, Inc. * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * @(#) $Revision: 29.8 $ * @(#) $Id: zio.c,v 29.8 2006/06/01 16:21:37 chongo Exp $ * @(#) $Source: /usr/local/src/cmd/calc/RCS/zio.c,v $ * * Under source code control: 1993/07/30 19:42:48 * File existed as early as: 1993 * * Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/ */#include <stdio.h>#include "config.h"#include "zmath.h"#include "args.h"#define OUTBUFSIZE 200 /* realloc size for output buffers */#define PUTCHAR(ch) math_chr(ch)#define PUTSTR(str) math_str(str)#define PRINTF1(fmt, a1) math_fmt(fmt, a1)#define PRINTF2(fmt, a1, a2) math_fmt(fmt, a1, a2)#define PRINTF3(fmt, a1, a2, a3) math_fmt(fmt, a1, a2, a3)#define PRINTF4(fmt, a1, a2, a3, a4) math_fmt(fmt, a1, a2, a3, a4)/* * Output state that has been saved when diversions are done. */typedef struct iostate IOSTATE;struct iostate { IOSTATE *oldiostates; /* previous saved state */ long outdigits; /* digits for output */ int outmode; /* output mode */ int outmode2; /* secondary output mode */ FILE *outfp; /* file unit for output (if any) */ char *outbuf; /* output string buffer (if any) */ size_t outbufsize; /* current size of string buffer */ size_t outbufused; /* space used in string buffer */ BOOL outputisstring; /* TRUE if output is to string buffer */};static IOSTATE *oldiostates = NULL; /* list of saved output states */static FILE *outfp = NULL; /* file unit for output */static char *outbuf = NULL; /* current diverted buffer */static BOOL outputisstring = FALSE;static size_t outbufsize;static size_t outbufused;/* * zio_init - perform needed initilization work * * On some systems, one cannot initialize a pointer to a FILE *. * This routine, called once at startup is a work-a-round for * systems with such bogons. */voidzio_init(void){ static int done = 0; /* 1 => routine already called */ if (!done) { outfp = stdout; done = 1; }}/* * Routine to output a character either to a FILE * handle or into a string. */voidmath_chr(int ch){ char *cp; if (!outputisstring) { fputc(ch, outfp); return; } if (outbufused >= outbufsize) { cp = (char *)realloc(outbuf, outbufsize + OUTBUFSIZE + 1); if (cp == NULL) { math_error("Cannot realloc output string"); /*NOTREACHED*/ } outbuf = cp; outbufsize += OUTBUFSIZE; } outbuf[outbufused++] = (char)ch;}/* * Routine to output a null-terminated string either * to a FILE handle or into a string. */voidmath_str(char *str){ char *cp; size_t len; if (!outputisstring) { fputs(str, outfp); return; } len = strlen(str); if ((outbufused + len) > outbufsize) { cp = (char *)realloc(outbuf, outbufsize + len + OUTBUFSIZE + 1); if (cp == NULL) { math_error("Cannot realloc output string"); /*NOTREACHED*/ } outbuf = cp; outbufsize += (len + OUTBUFSIZE); } memcpy(&outbuf[outbufused], str, len); outbufused += len;}/* * Output a null-terminated string either to a FILE handle or into a string, * padded with spaces as needed so as to fit within the specified width. * If width is positive, the spaces are added at the front of the string. * If width is negative, the spaces are added at the end of the string. * The complete string is always output, even if this overflows the width. * No characters within the string are handled specially. */voidmath_fill(char *str, long width){ if (width > 0) { width -= (long)strlen(str); while (width-- > 0) PUTCHAR(' '); PUTSTR(str); } else { width += (long)strlen(str); PUTSTR(str); while (width++ < 0) PUTCHAR(' '); }}/* * Routine to output a printf-style formatted string either * to a FILE handle or into a string. */voidmath_fmt(char *fmt, ...){ va_list ap; char buf[BUFSIZ+1]; va_start(ap, fmt); vsnprintf(buf, BUFSIZ, fmt, ap); va_end(ap); buf[BUFSIZ] = '\0'; math_str(buf);}/* * Flush the current output stream. */voidmath_flush(void){ if (!outputisstring) fflush(outfp);}/* * Divert further output so that it is saved into a string that will be * returned later when the diversion is completed. The current state of * output is remembered for later restoration. Diversions can be nested. * Output diversion is only intended for saving output to "stdout". */voidmath_divertio(void){ register IOSTATE *sp; sp = (IOSTATE *) malloc(sizeof(IOSTATE)); if (sp == NULL) { math_error("No memory for diverting output"); /*NOTREACHED*/ } sp->oldiostates = oldiostates; sp->outdigits = conf->outdigits; sp->outmode = conf->outmode; sp->outmode2 = conf->outmode2; sp->outfp = outfp; sp->outbuf = outbuf; sp->outbufsize = outbufsize; sp->outbufused = outbufused; sp->outputisstring = outputisstring; outbufused = 0; outbufsize = 0; outbuf = (char *) malloc(OUTBUFSIZE + 1); if (outbuf == NULL) { math_error("Cannot allocate divert string"); /*NOTREACHED*/ } outbufsize = OUTBUFSIZE; outputisstring = TRUE; oldiostates = sp;}/* * Undivert output and return the saved output as a string. This also * restores the output state to what it was before the diversion began. * The string needs freeing by the caller when it is no longer needed. */char *math_getdivertedio(void){ register IOSTATE *sp; char *cp; sp = oldiostates; if (sp == NULL) { math_error("No diverted state to restore"); /*NOTREACHED*/ } cp = outbuf; cp[outbufused] = '\0'; oldiostates = sp->oldiostates; conf->outdigits = sp->outdigits; conf->outmode = sp->outmode; conf->outmode2 = sp->outmode2; outfp = sp->outfp; outbuf = sp->outbuf; outbufsize = sp->outbufsize; outbufused = sp->outbufused; outbuf = sp->outbuf; outputisstring = sp->outputisstring; free(sp); return cp;}/* * Clear all diversions and set output back to the original destination. * This is called when resetting the global state of the program. */voidmath_cleardiversions(void){ while (oldiostates) free(math_getdivertedio());}/* * Set the output routines to output to the specified FILE stream. * This interacts with output diversion in the following manner. * STDOUT diversion action * ---- --------- ------ * yes yes set output to diversion string again. * yes no set output to stdout. * no yes set output to specified file. * no no set output to specified file. */voidmath_setfp(FILE *newfp){ outfp = newfp; outputisstring = (oldiostates && (newfp == stdout));}/* * Set the output mode for numeric output. * This also returns the previous mode. */intmath_setmode(int newmode){ int oldmode; if ((newmode <= MODE_DEFAULT) || (newmode > MODE_MAX)) { math_error("Setting illegal output mode"); /*NOTREACHED*/ } oldmode = conf->outmode; conf->outmode = newmode; return oldmode;}/* * Set the secondary output mode for numeric output. * This also returns the previous mode. */intmath_setmode2(int newmode){ int oldmode; if (newmode != MODE2_OFF && ((newmode <= MODE_DEFAULT) || (newmode > MODE_MAX))) { math_error("Setting illegal secondary output mode"); /*NOTREACHED*/ } oldmode = conf->outmode2; conf->outmode2 = newmode; return oldmode;}/* * Set the number of digits for float or exponential output. * This also returns the previous number of digits. */LENmath_setdigits(LEN newdigits){ LEN olddigits; if (newdigits < 0) { math_error("Setting illegal number of digits"); /*NOTREACHED*/ } olddigits = conf->outdigits; conf->outdigits = newdigits; return olddigits;}/* * Print an integer value as a hex number. * Width is the number of columns to print the number in, including the * sign if required. If zero, no extra output is done. If positive, * leading spaces are typed if necessary. If negative, trailing spaces are * typed if necessary. The special characters 0x appear to indicate the * number is hex. *//*ARGSUSED*/voidzprintx(ZVALUE z, long width){ register HALF *hp; /* current word to print */ int len; /* number of halfwords to type */ char *str; if (width) { math_divertio(); zprintx(z, 0L); str = math_getdivertedio(); math_fill(str, width); free(str); return; } len = z.len - 1; if (zisneg(z)) PUTCHAR('-'); if ((len == 0) && (*z.v <= (HALF) 9)) { len = '0' + (int)(*z.v); PUTCHAR(len & 0xff); return; } hp = z.v + len;#if BASEB == 32 PRINTF1("0x%lx", (PRINT) *hp--); while (--len >= 0) { PRINTF1("%08lx", (PRINT) *hp--); }#else /* BASEB == 32 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -