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

📄 format.c

📁 刻录光盘的程序
💻 C
字号:
/* @(#)format.c	1.29 98/03/31 Copyright 1985 J. Schilling *//* *	format *	common code for printf fprintf & sprintf * *	allows recursive printf with "%r", used in: *	error, comerr, comerrno, errmsg, errmsgno and the like * *	Copyright (c) 1985 J. Schilling *//* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING.  If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */#include <mconfig.h>#include <vadefs.h>#include <strdefs.h>#include <stdxlib.h>#ifndef	HAVE_STDLIB_Hextern	char	*gcvt __PR((double, int, char *));#endif#include <standard.h>/* * Some CPU's (e.g. PDP-11) cannot do logical shifts. * They use rotate instead. Masking the low bits before, * makes rotate work too. */#define	allmask(t)	((unsigned t)~((unsigned t)0))#define	lowmask(t, x)	((unsigned t)~((unsigned t)((1 << (x))-1) ))#define	rshiftmask(t, s)((allmask(t) & lowmask(t, s)) >> (s))#define	CHARMASK	makemask(char)#define	SHORTMASK	makemask(short)#define	INTMASK		makemask(int)#define	LONGMASK	makemask(long)#ifdef	DIVLBYSextern	long	divlbys();extern	long	modlbys();#else#define	divlbys(val, base)	((val)/(base))#define	modlbys(val, base)	((val)%(base))#endif/* *	We use macros here to avoid the need to link to the international *	character routines. *	We don't need internationalization for our purpose. */#define	is_dig(c)	(((c) >= '0') && ((c) <= '9'))#define	is_cap(c)	((c) >= 'A' && (c) <= 'Z')#define	to_cap(c)	(is_cap(c) ? c : c - 'a' + 'A')#define	cap_ty(c)	(is_cap(c) ? 'L' : 'I')typedef unsigned int	Uint;typedef unsigned short	Ushort;typedef unsigned long	Ulong;#ifdef	HAVE_LONGLONGtypedef unsigned long long	Ullong;#endiftypedef struct f_args {	void	(*outf) __PR((char, long)); /* Func from format(fun, arg) */	long	farg;			    /* Arg from format (fun, arg) */	int	minusflag;	int	flags;	int	fldwidth;	int	signific;	int	lzero;	char	*buf;	char	*bufp;	char	fillc;	char	*prefix;	int	prefixlen;} f_args;#define	MINUSFLG	1	/* '-' flag */#define	PLUSFLG		2	/* '+' flag */#define	SPACEFLG	4	/* ' ' flag */#define	HASHFLG		8	/* '#' flag */LOCAL	void	prnum  __PR((Ulong, unsigned, f_args *));LOCAL	void	prdnum __PR((Ulong, f_args *));LOCAL	void	pronum __PR((Ulong, f_args *));LOCAL	void	prxnum __PR((Ulong, f_args *));LOCAL	void	prXnum __PR((Ulong, f_args *));LOCAL	int	prbuf  __PR((const char *, f_args *));LOCAL	int	prc    __PR((char, f_args *));LOCAL	int	prstring __PR((const char *, f_args *));#ifdef	PROTOTYPESEXPORT int format(	void (*fun)(char, long),			long farg,			const char *fmt,			va_list args)#elseEXPORT int format(fun, farg, fmt, args)	register void	(*fun)();	register long	farg;	register char	*fmt;	va_list		args;#endif{	char buf[512];	const char *sfmt;	register int unsflag;	register long val;	register char type;	register char mode;	register char c;	int count;	int i;	short sh;	const char *str;	double dval;	Ulong res;	char *rfmt;	f_args	fa;	fa.outf = fun;	fa.farg = farg;	count = 0;	/*	 * Main loop over the format string.	 * Increment and check for end of string is made here.	 */	for(; *fmt != '\0'; fmt++) {		c = *fmt;		while (c != '%') {			if (c == '\0')				return (count);			(*fun)(c, farg);			c = *(++fmt);			count++;		}		/*		 * We reached a '%' sign.		 */		buf[0] = '\0';		fa.buf = fa.bufp = buf;		fa.minusflag = 0;		fa.flags = 0;		fa.fldwidth = 0;		fa.signific = -1;		fa.lzero = 0;		fa.fillc = ' ';		fa.prefixlen = 0;		sfmt = fmt;		unsflag = FALSE;	newflag:		switch (*(++fmt)) {		case '+':			fa.flags |= PLUSFLG;			goto newflag;		case '-':			fa.minusflag++;			goto newflag;		case ' ':			/*			 * If the space and the + flag are present,			 * the space flag will be ignored.			 */			fa.flags |= SPACEFLG;			goto newflag;		case '#':			fa.flags |= HASHFLG;			goto newflag;		case '0':			/*			 * '0' is a flag.			 */			fa.fillc = '0';			goto newflag;		}		if (*fmt == '*') {			fmt++;			fa.fldwidth = va_arg(args, int);			/*			 * A negative fieldwith is a minus flag with a			 * positive fieldwidth.			 */			if (fa.fldwidth < 0) {				fa.fldwidth = -fa.fldwidth;/*				fa.minusflag ^= 1;*/				fa.minusflag = 1;			}		} else while (c = *fmt, is_dig(c)) {			fa.fldwidth *= 10;			fa.fldwidth += c - '0';			fmt++;		}		if (*fmt == '.') {			fmt++;			fa.signific = 0;			if (*fmt == '*') {				fmt++;				fa.signific = va_arg(args, int);				if (fa.signific < 0)					fa.signific = 0;			} else while (c = *fmt, is_dig(c)) {				fa.signific *= 10;				fa.signific += c - '0';				fmt++;			}		}		if (strchr("UCSIL", *fmt)) {			/*			 * Enhancements to K&R and ANSI:			 *			 * got a type specifyer			 */			if (*fmt == 'U') {				fmt++;				unsflag = TRUE;			}			if (!strchr("CSILZODX", *fmt)) {				/*				 * Got only 'U'nsigned specifyer,				 * use default type and mode.				 */				type = 'I';				mode = 'D';				fmt--;			} else if (!strchr("CSIL", *fmt)) {				/*				 * no type, use default				 */				type = 'I';				mode = *fmt;			} else {				/*				 * got CSIL				 */				type = *fmt++;				if (!strchr("ZODX", mode = *fmt)) {					fmt--;					mode = 'D';/* default mode */				}			}		} else switch(*fmt) {		case 'h':			type = 'S';		/* convert to type */			goto getmode;		case 'l':			type = 'L';		/* convert to type */		getmode:			if (!strchr("udioxX", *(++fmt))) {				fmt--;				mode = 'D';			} else {				mode = *fmt;				if (mode != 'x')					mode = to_cap(mode);				if (mode == 'U')					unsflag = TRUE;				else if (mode == 'I')	/*XXX */					mode = 'D';			}			break;		case 'x':			mode = 'x';			goto havemode;		case 'u':			unsflag = TRUE;		case 'o': case 'O':		case 'd': case 'D':		case 'i': case 'I':		case 'p':		case 'X':		case 'z': case 'Z':			mode = to_cap(*fmt);		havemode:			type = cap_ty(*fmt);			if (mode == 'I')	/*XXX kann entfallen*/				mode = 'D';	/*wenn besseres uflg*/			break;		case '%':			count += prc('%', &fa);			continue;		case ' ':			count += prbuf("", &fa);			continue;		case 'c':			c = va_arg(args, int);			count += prc(c, &fa);			continue;		case 's':			str = va_arg(args, char *);			count += prstring(str, &fa);			continue;		case 'b':			str = va_arg(args, char *);			fa.signific = va_arg(args, int);			count += prstring(str, &fa);			continue;#ifndef	NO_FLOATINGPOINT		case 'e':			if (fa.signific == -1)				fa.signific = 6;			dval = va_arg(args, double);			ftoes(buf, dval, 0, fa.signific);			count += prbuf(buf, &fa);			continue;		case 'f':			if (fa.signific == -1)				fa.signific = 6;			dval = va_arg(args, double);			ftofs(buf, dval, 0, fa.signific);			count += prbuf(buf, &fa);			continue;		case 'g':			if (fa.signific == -1)				fa.signific = 6;			if (fa.signific == 0)				fa.signific = 1;			dval = va_arg(args, double);			gcvt(dval, fa.signific, buf);			count += prbuf(buf, &fa);			continue;#else#	ifdef	USE_FLOATINGARGS		case 'e':		case 'f':		case 'g':			dval = va_arg(args, double);			continue;#	endif#endif		case 'r':			/* recursive printf */		case 'R':			/* recursive printf */			rfmt  = va_arg(args, char *);			/*			 * I don't know any portable way to get an arbitrary			 * C object from a var arg list so I use a			 * system-specific routine __va_arg_list() that knows			 * if 'va_list' is an array. You will not be able to			 * assign the value of __va_arg_list() but it works			 * to be used as an argument of a function.			 * It is a requirement for recursive printf to be able			 * to use this function argument. If your system			 * defines va_list to be an array you need to know this			 * via autoconf or another mechanism.			 * It would be nice to have something like			 * __va_arg_list() in stdarg.h			 */			count += format(fun, farg, rfmt, __va_arg_list(args));			continue;		case 'n':			{				int	*ip = va_arg(args, int *);				*ip = count;			}			continue;		default:			/* Unknown '%' format */			sfmt++;			/* Dont't print '%'   */			count += fmt - sfmt;			while (sfmt < fmt)				(*fun)(*(sfmt++), farg);			if (*fmt == '\0') {				fmt--;				continue;			} else {				(*fun)(*fmt, farg);				count++;				continue;			}		}		/*		 * print numbers:		 * first prepare type 'C'har, 'S'hort, 'I'nt, or 'L'ong		 */		switch(type) {		case 'C':			c = va_arg(args, int);			val = c;		/* extend sign here */			if (unsflag || mode != 'D')#ifdef	DO_MASK				val &= CHARMASK;#else				val = (unsigned char)val;#endif			break;		case 'S':			sh = va_arg(args, int);			val = sh;		/* extend sign here */			if (unsflag || mode != 'D')#ifdef	DO_MASK				val &= SHORTMASK;#else				val = (unsigned short)val;#endif			break;		case 'I':		default:			i = va_arg(args, int);			val = i;		/* extend sign here */			if (unsflag || mode != 'D')#ifdef	DO_MASK				val &= INTMASK;#else				val = (unsigned int)val;#endif			break;		case 'P':		case 'L':			val = va_arg(args, long);			break;		}		/*		 * Final print out, take care of mode:		 * mode is one of: 'O'ctal, 'D'ecimal, or he'X'		 * oder 'Z'weierdarstellung.		 */		fa.bufp = &buf[sizeof(buf)-1];		*--fa.bufp = '\0';		if (val == 0 && mode != 'D') {		printzero:			/*			 * Printing '0' with fieldwidth 0 results in no chars.			 */			fa.lzero = -1;			if (fa.signific >= 0)				fa.fillc = ' ';			count += prstring("0", &fa);			continue;		} else switch(mode) {		case 'D':			if (!unsflag && val < 0) {				fa.prefix = "-";				fa.prefixlen = 1;				val = -val;			} else if (fa.flags & PLUSFLG) {				fa.prefix = "+";				fa.prefixlen = 1;			} else if (fa.flags & SPACEFLG) {				fa.prefix = " ";				fa.prefixlen = 1;			}			if (val == 0)				goto printzero;		case 'U':			/* output a long unsigned decimal number */			prdnum(val, &fa);			break;		case 'O':			/* output a long octal number */			if (fa.flags & HASHFLG) {				fa.prefix = "0";				fa.prefixlen = 1;			}			pronum(val & 07, &fa);			if ((res = (val>>3) & rshiftmask(long, 3)) != 0)				pronum(res, &fa);			break;		case 'p':		case 'x':			/* output a hex long */			if (fa.flags & HASHFLG) {				fa.prefix = "0x";				fa.prefixlen = 2;			}			prxnum(val & 0xF, &fa);			if ((res = (val>>4) & rshiftmask(long, 4)) != 0)				prxnum(res, &fa);			break;		case 'P':		case 'X':			/* output a hex long */			if (fa.flags & HASHFLG) {				fa.prefix = "0X";				fa.prefixlen = 2;			}			prXnum(val & 0xF, &fa);			if ((res = (val>>4) & rshiftmask(long, 4)) != 0)				prXnum(res, &fa);			break;		case 'Z':			/* output a binary long */			prnum(val & 0x1, 2, &fa);			if ((res = (val>>1) & rshiftmask(long, 1)) != 0)				prnum(res, 2, &fa);		}		fa.lzero = -1;		/*		 * If a precision (fielwidth) is specified		 * on diouXx conversions, the '0' flag is ignored.		 */		if (fa.signific >= 0)			fa.fillc = ' ';		count += prbuf(fa.bufp, &fa);	}	return (count);}/* * Routines to print (not negative) numbers in an arbitrary base */LOCAL	unsigned char	dtab[]  = "0123456789abcdef";LOCAL	unsigned char	udtab[] = "0123456789ABCDEF";LOCAL void prnum(val, base, fa)	register Ulong val;	register unsigned base;	f_args *fa;{	register char *p = fa->bufp;	do {		*--p = dtab[modlbys(val, base)];		val = divlbys(val, base);	} while (val > 0);	fa->bufp = p;}LOCAL void prdnum(val, fa)	register Ulong val;	f_args *fa;{	register char *p = fa->bufp;	do {		*--p = dtab[modlbys(val, (unsigned)10)];		val = divlbys(val, (unsigned)10);	} while (val > 0);	fa->bufp = p;}/* * We may need to use division here too (PDP-11, non two's complement ...) */LOCAL void pronum(val, fa)	register Ulong val;	f_args *fa;{	register char *p = fa->bufp;	do {		*--p = dtab[val & 7];		val >>= 3;	} while (val > 0);	fa->bufp = p;}LOCAL void prxnum(val, fa)	register Ulong val;	f_args *fa;{	register char *p = fa->bufp;	do {		*--p = dtab[val & 15];		val >>= 4;	} while (val > 0);	fa->bufp = p;}LOCAL void prXnum(val, fa)	register Ulong val;	f_args *fa;{	register char *p = fa->bufp;	do {		*--p = udtab[val & 15];		val >>= 4;	} while (val > 0);	fa->bufp = p;}/* * Final buffer print out routine. */LOCAL int prbuf(s, fa)	register const char *s;	f_args *fa;{	register int diff;	register int rfillc;	register long arg			= fa->farg;	register void (*fun) __PR((char, long))	= fa->outf;	register int count;	register int lzero = 0;	count = strlen(s);	if (fa->lzero < 0 && count < fa->signific)		lzero = fa->signific - count;	diff = fa->fldwidth - lzero - count - fa->prefixlen;	count += lzero;	if (diff > 0)		count += diff;	if (fa->prefixlen && fa->fillc != ' ') {		while (*fa->prefix != '\0')			(*fun)(*fa->prefix++, arg);	}	if (!fa->minusflag) {		rfillc = fa->fillc;		while (--diff >= 0)			(*fun)(rfillc, arg);	}	if (fa->prefixlen && fa->fillc == ' ') {		while (*fa->prefix != '\0')			(*fun)(*fa->prefix++, arg);	}	if (lzero > 0) {		rfillc = '0';		while (--lzero >= 0)			(*fun)(rfillc, arg);	}	while (*s != '\0')		(*fun)(*s++, arg);	if (fa->minusflag) {		rfillc = ' ';		while (--diff >= 0)			(*fun)(rfillc, arg);	}	return (count);}/* * Print out one char, allowing prc('\0') * Similar to prbuf() */#ifdef	PROTOTYPESLOCAL int prc(char c, f_args *fa)#elseLOCAL int prc(c, fa)	char	c;	f_args *fa;#endif{	register int diff;	register int rfillc;	register long arg			= fa->farg;	register void (*fun) __PR((char, long))	= fa->outf;	register int count;	count = 1;	diff = fa->fldwidth - 1;	if (diff > 0)		count += diff;	if (!fa->minusflag) {		rfillc = fa->fillc;		while (--diff >= 0)			(*fun)(rfillc, arg);	}	(*fun)(c, arg);	if (fa->minusflag) {		rfillc = ' ';		while (--diff >= 0)			(*fun)(rfillc, arg);	}	return (count);}/* * String output routine. * If fa->signific is >= 0, it uses only fa->signific chars. * If fa->signific is 0, print no characters. */LOCAL int prstring(s, fa)	register const char	*s;	f_args *fa;{	register char	*bp;	register int	signific;	if (s == NULL)		return (prbuf("(NULL POINTER)", fa));	if (fa->signific < 0)		return (prbuf(s, fa));	bp = fa->buf;	signific = fa->signific;	while (--signific >= 0 && *s != '\0')		*bp++ = *s++;	*bp = '\0';	return (prbuf(fa->buf, fa));}

⌨️ 快捷键说明

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