⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sbufvform.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1990 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley.  The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */#if defined(LIBC_SCCS) && !defined(lint)static char sccsid[] = "%W% (Berkeley) %G%";#endif /* LIBC_SCCS and not lint *//* * Actual printf innards. * * This code is large and complicated... */#include <sys/types.h>#include "ioprivate.h"#include <string.h>#include <stdarg.h>/* * Define FLOATING_POINT to get floating point. */#ifndef	NO_FLOATING_POINT#define	FLOATING_POINT#endif/* end of configuration stuff *//* * Helper class and function for `fprintf to unbuffered': creates a * temporary buffer.  We only work on write-only files; this avoids * worries about ungetc buffers and so forth. */class help_streambuf : public backupbuf {  public:    char *buffer;    int buf_size;    streambuf *sb;    help_streambuf(streambuf *sbuf, char *buf, int n) {	sb = sbuf; buffer = buf; buf_size = n;	setp(buffer, buffer+buf_size); }    ~help_streambuf();    virtual int overflow(int c = EOF);};int help_streambuf::overflow(int c){    int used = pptr() - pbase();    if (used) {	sb->sputn(pbase(), used);	pbump(-used);    }    if (c == EOF || buf_size == 0)	return sb->overflow(c);    return sputc(c);}help_streambuf::~help_streambuf(){    int used = pptr() - pbase();    if (used) {	sb->sputn(pbase(), used);	pbump(-used);    }}int help_vform(streambuf *sb, char const *fmt0, va_list ap){    char buf[_G_BUFSIZ];    help_streambuf helper(sb, buf, _G_BUFSIZ);    return helper.vform(fmt0, ap);}#ifdef FLOATING_POINT#include "floatio.h"#define	BUF		(MAXEXP+MAXFRACT+1)	/* + decimal point */#define	DEFPREC		6extern "C" double modf(double, double*);#else /* no FLOATING_POINT */#define	BUF		40#endif /* FLOATING_POINT *//* * Macros for converting digits to letters and vice versa */#define	to_digit(c)	((c) - '0')#define is_digit(c)	((unsigned)to_digit(c) <= 9)#define	to_char(n)	((n) + '0')/* * Flags used during conversion. */#define	LONGINT		0x01		/* long integer */#define	LONGDBL		0x02		/* long double; unimplemented */#define	SHORTINT	0x04		/* short integer */#define	ALT		0x08		/* alternate form */#define	LADJUST		0x10		/* left adjustment */#define	ZEROPAD		0x20		/* zero (as opposed to blank) pad */#define	HEXPREFIX	0x40		/* add 0x or 0X prefix */int streambuf::vform(char const *fmt0, _G_va_list ap){	register const char *fmt; /* format string */	register int ch;	/* character from fmt */	register int n;		/* handy integer (short term usage) */	register char *cp;	/* handy char pointer (short term usage) */	const char *fmark;	/* for remembering a place in fmt */	register int flags;	/* flags as above */	int ret;		/* return value accumulator */	int width;		/* width from format (%8d), or 0 */	int prec;		/* precision from format (%.3d), or -1 */	char sign;		/* sign prefix (' ', '+', '-', or \0) */#ifdef FLOATING_POINT	int softsign;		/* temporary negative sign for floats */	double _double;		/* double precision arguments %[eEfgG] */#ifndef USE_DTOA	int fpprec;		/* `extra' floating precision in [eEfgG] */#endif#endif	unsigned long _ulong;	/* integer arguments %[diouxX] */	enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */	int dpad;		/* extra 0 padding needed for integers */	int fieldsz;		/* field size expanded by sign, dpad etc */	// The initialization of 'size' is to suppress a warning that	// 'size' might be used unitialized.  It seems gcc can't	// quite grok this spaghetti code ...	int size = 0;		/* size of converted field or string */	char buf[BUF];		/* space for %c, %[diouxX], %[eEfgG] */	char ox[2];		/* space for 0x hex-prefix */	/*	 * Choose PADSIZE to trade efficiency vs size.  If larger	 * printf fields occur frequently, increase PADSIZE (and make	 * the initialisers below longer).	 */#define	PADSIZE	16		/* pad chunk size */	static char const blanks[PADSIZE] =	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};	static char const zeroes[PADSIZE] =	 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};	/*	 * BEWARE, these `goto error' on error, and PAD uses `n'.	 */#define	PRINT(ptr, len) \  do { if (sputn(ptr, len) != len) goto error; } while (0)#if 1#define PAD_SP(howmany) if (padn(' ', howmany) < 0) goto error;#define PAD_0(howmany) if (padn('0', howmany) < 0) goto error;#else#define	PAD(howmany, with) { \	if ((n = (howmany)) > 0) { \		while (n > PADSIZE) { \			PRINT(with, PADSIZE); \			n -= PADSIZE; \		} \		PRINT(with, n); \	} \}#define PAD_SP(howmany) PAD(howmany, blanks)#define PAD_0(howmany) PAD(howmany, zeroes)#endif	/*	 * To extend shorts properly, we need both signed and unsigned	 * argument extraction methods.	 */#define	SARG() \	(flags&LONGINT ? va_arg(ap, long) : \	    flags&SHORTINT ? (long)(short)va_arg(ap, int) : \	    (long)va_arg(ap, int))#define	UARG() \	(flags&LONGINT ? va_arg(ap, unsigned long) : \	    flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \	    (unsigned long)va_arg(ap, unsigned int))	/* optimise cerr (and other unbuffered Unix files) */	if (unbuffered())	    return help_vform(this, fmt0, ap);	fmt = fmt0;	ret = 0;	/*	 * Scan the format for conversions (`%' character).	 */	for (;;) {		for (fmark = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)			/* void */;		if ((n = fmt - fmark) != 0) {			PRINT(fmark, n);			ret += n;		}		if (ch == '\0')			goto done;		fmt++;		/* skip over '%' */		flags = 0;		dprec = 0;#if defined(FLOATING_POINT) && !defined (USE_DTOA)		fpprec = 0;#endif		width = 0;		prec = -1;		sign = '\0';rflag:		ch = *fmt++;reswitch:	switch (ch) {		case ' ':			/*			 * ``If the space and + flags both appear, the space			 * flag will be ignored.''			 *	-- ANSI X3J11			 */			if (!sign)				sign = ' ';			goto rflag;		case '#':			flags |= ALT;			goto rflag;		case '*':			/*			 * ``A negative field width argument is taken as a			 * - flag followed by a positive field width.''			 *	-- ANSI X3J11			 * They don't exclude field widths read from args.			 */			if ((width = va_arg(ap, int)) >= 0)				goto rflag;			width = -width;			/* FALLTHROUGH */		case '-':			flags |= LADJUST;			flags &= ~ZEROPAD; /* '-' disables '0' */			goto rflag;		case '+':			sign = '+';			goto rflag;		case '.':			if ((ch = *fmt++) == '*') {				n = va_arg(ap, int);				prec = n < 0 ? -1 : n;				goto rflag;			}			n = 0;			while (is_digit(ch)) {				n = 10 * n + to_digit(ch);				ch = *fmt++;			}			prec = n < 0 ? -1 : n;			goto reswitch;		case '0':			/*			 * ``Note that 0 is taken as a flag, not as the			 * beginning of a field width.''			 *	-- ANSI X3J11			 */			if (!(flags & LADJUST))			    flags |= ZEROPAD; /* '-' disables '0' */			goto rflag;		case '1': case '2': case '3': case '4':		case '5': case '6': case '7': case '8': case '9':			n = 0;			do {				n = 10 * n + to_digit(ch);				ch = *fmt++;			} while (is_digit(ch));			width = n;			goto reswitch;#ifdef FLOATING_POINT		case 'L':			flags |= LONGDBL;			goto rflag;#endif		case 'h':			flags |= SHORTINT;			goto rflag;		case 'l':			flags |= LONGINT;			goto rflag;		case 'c':			*(cp = buf) = va_arg(ap, int);			size = 1;			sign = '\0';			break;		case 'D':			flags |= LONGINT;			/*FALLTHROUGH*/		case 'd':		case 'i':			_ulong = SARG();			if ((long)_ulong < 0) {				_ulong = -_ulong;				sign = '-';			}			base = DEC;			goto number;#ifdef FLOATING_POINT		case 'e':		case 'E':		case 'f':		case 'F':		case 'g':		case 'G':			_double = va_arg(ap, double);#ifdef USE_DTOA			{			    ios::fmtflags fmt_flags = 0;			    int fill = ' ';			    if (flags & ALT)				fmt_flags |= ios::showpoint;			    if (flags & LADJUST)				fmt_flags |= ios::left;			    else if (flags & ZEROPAD)				fmt_flags |= ios::internal, fill = '0';			    n = __outfloat(_double, this, ch, width,					   prec < 0 ? DEFPREC : prec,					   fmt_flags, sign, fill);			    if (n < 0)				goto error;			    ret += n;			}			// CHECK ERROR!			continue;#else			/*			 * don't do unrealistic precision; just pad it with			 * zeroes later, so buffer size stays rational.			 */			if (prec > MAXFRACT) {				if ((ch != 'g' && ch != 'G') || (flags&ALT))					fpprec = prec - MAXFRACT;				prec = MAXFRACT;			} else if (prec == -1)				prec = DEFPREC;			// __cvt_double may have to round up before the			// "start" of its buffer, i.e.			// ``intf("%.2f", (double)9.999);'';			// if the first character is still NUL, it did.			// softsign avoids negative 0 if _double < 0 but			// no significant digits will be shown.			cp = buf;			*cp = '\0';			size = __cvt_double(_double, prec, flags, &softsign,					    ch, cp, buf + sizeof(buf));			if (softsign)				sign = '-';			if (*cp == '\0')				cp++;			break;#endif#endif /* FLOATING_POINT */		case 'n':			if (flags & LONGINT)				*va_arg(ap, long *) = ret;			else if (flags & SHORTINT)				*va_arg(ap, short *) = ret;			else				*va_arg(ap, int *) = ret;			continue;	/* no output */		case 'O':			flags |= LONGINT;			/*FALLTHROUGH*/		case 'o':			_ulong = UARG();			base = OCT;			goto nosign;		case 'p':			/*			 * ``The argument shall be a pointer to void.  The			 * value of the pointer is converted to a sequence			 * of printable characters, in an implementation-			 * defined manner.''			 *	-- ANSI X3J11			 */			/* NOSTRICT */			_ulong = (unsigned long)va_arg(ap, void *);			base = HEX;			flags |= HEXPREFIX;			ch = 'x';			goto nosign;		case 's':			if ((cp = va_arg(ap, char *)) == NULL)				cp = "(null)";			if (prec >= 0) {				/*				 * can't use strlen; can only look for the				 * NUL in the first `prec' characters, and				 * strlen() will go further.				 */				char *p = (char*)memchr(cp, 0, prec);				if (p != NULL) {					size = p - cp;					if (size > prec)						size = prec;				} else					size = prec;			} else				size = strlen(cp);			sign = '\0';			break;		case 'U':			flags |= LONGINT;			/*FALLTHROUGH*/		case 'u':			_ulong = UARG();			base = DEC;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -