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

📄 printf.c

📁 在ARM上实现Printf,可以输出任何格式的变量
💻 C
字号:
#include "type.h"
#include <string.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif

#include "uart.h"


//#define LIGHTPRINTF

void PRINT(const char * ptr, unsigned int len) {
	for(;len;len--) 
	{
		UART0_Sendbyte(*ptr++);
	}
}
  
void PRINTP(const char * ptr, unsigned int len) {
	for(;len;len--)
	{ 
		UART0_Sendstr(*ptr++);
	 }
}

void PAD_SP(signed char howmany) {
	for(;howmany>0;howmany--)
	{
		UART0_Sendstr(' ');
	}
}

void PAD_0(signed char howmany) {
	for(;howmany>0;howmany--)
	{
		UART0_Sendstr('0');
	}
}

#define	BUF		40

/*
 * Macros for converting digits to letters and vice versa
 */
#define	to_digit(c)	((c) - '0')
#define  is_digit(c)	((c)<='9' && (c)>='0')
#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 */

void _printf_P (char const *fmt0, ...)      /* Works with string from FLASH */
  {
 	va_list ap;
	register const char *fmt; /* format string */
	register char 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 unsigned char flags;	/* flags as above */
	signed char width;		/* width from format (%8d), or 0 */
	signed char prec;		/* precision from format (%.3d), or -1 */
	char sign;				/* sign prefix (' ', '+', '-', or \0) */
	unsigned long _ulong=0;	/* integer arguments %[diouxX] */
#define OCT 8
#define DEC 10
#define HEX 16
	unsigned char base;		/* base for [diouxX] conversion */
	signed char dprec;		/* a copy of prec if [diouxX], 0 otherwise */
	signed char dpad;			/* extra 0 padding needed for integers */
	signed char 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 ... */
	signed char size = 0;		/* size of converted field or string */
	char buf[BUF];		/* space for %c, %[diouxX], %[eEfgG] */
	char ox[2];			/* space for 0x hex-prefix */

	va_start(ap, fmt0);
	
	fmt = fmt0;

	/*
	 * Scan the format for conversions (`%' character).
	 */
	for (;;) {
		for (fmark = fmt; (ch = (*fmt)) != '\0' && ch != '%'; fmt++)
			/* void */;
		if ((n = fmt - fmark) != 0) {
			PRINTP(fmark, n);
		}
		if (ch == '\0')
			goto done;
		fmt++;		/* skip over '%' */

		flags = 0;
		dprec = 0;
		width = 0;
		prec = -1;
		sign = '\0';

rflag:		ch = (*fmt++);
reswitch:
#ifdef LIGHTPRINTF
	if (ch=='o' || ch=='u' || (ch|0x20)=='x') {
#else
	if (ch=='u' || (ch|0x20)=='x') {
#endif
		if (flags&LONGINT) {
		 	_ulong=va_arg(ap, unsigned long);
		} else {
			register unsigned int _d;
			_d=va_arg(ap, unsigned int);
			_ulong = flags&SHORTINT ? (unsigned long)(unsigned short)_d : (unsigned long)_d;
		}
	}
 	
#ifndef LIGHTPRINTF
		if(ch==' ') {
			/*
			 * ``If the space and + flags both appear, the space
			 * flag will be ignored.''
			 *	-- ANSI X3J11
			 */
			if (!sign)
				sign = ' ';
			goto rflag;
		} else if (ch=='#') {
			flags |= ALT;
			goto rflag;
		} else if (ch=='*'||ch=='-') {
			if (ch=='*') {
				/*
				 * ``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;
			}
			flags |= LADJUST;
			flags &= ~ZEROPAD; /* '-' disables '0' */
			goto rflag;
		} else if (ch=='+') {
			sign = '+';
			goto rflag;
		} else if (ch=='.') {
			if ((ch = (*fmt++)) == '*') {
				n = va_arg(ap, int);
				prec = n < 0 ? -1 : n;
				goto rflag;
			}
			n = 0;
			while (is_digit(ch)) {
				n = n*10 + to_digit(ch);
				ch = (*fmt++);
			}
			prec = n < 0 ? -1 : n;
			goto reswitch;
		} else
#endif /* LIGHTPRINTF */
		if (ch=='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;
		} else if (ch>='1' && ch<='9') {
			n = 0;
			do {
				n = 10 * n + to_digit(ch);
				ch = *fmt++;
			} while (is_digit(ch));
			width = n;
			goto reswitch;
		} else if (ch=='h') {
			flags |= SHORTINT;
			goto rflag;
		} else if (ch=='l') {
			flags |= LONGINT;
			goto rflag;
		} else if (ch=='c') {
			*(cp = buf) = va_arg(ap, int);
			size = 1;
			sign = '\0';
		} else if (ch=='D'||ch=='d'||ch=='i') {
			if(ch=='D')
				flags |= LONGINT;
			if (flags&LONGINT) {
			 	_ulong=va_arg(ap, long);
			} else {
				register int _d;
				_d=va_arg(ap, int);
				_ulong = flags&SHORTINT ? (long)(short)_d : (long)_d;
			}
    			
			if ((long)_ulong < 0) {
				_ulong = -_ulong;
				sign = '-';
			}
			base = DEC;
			goto number;
		} else
/*		
		if (ch=='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 
		} else
*/
#ifndef LIGHTPRINTF			
		if (ch=='O'||ch=='o') {
			if (ch=='O')
				flags |= LONGINT;
			base = OCT;
			goto nosign;
		} else if (ch=='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 int)va_arg(ap, void *);
			base = HEX;
			flags |= HEXPREFIX;
			ch = 'x';
			goto nosign;
		} else if (ch=='s') {  // print a string from RAM
			if ((cp = va_arg(ap, char *)) == NULL) {
				cp=buf;
				cp[0] = '(';
				cp[1] = 'n';
				cp[2] = 'u';
				cp[4] = cp[3] = 'l';
				cp[5] = ')';
				cp[6] = '\0';
			}
			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';
		} else
#endif /* LIGHTPRINTF */			
		if(ch=='U'||ch=='u') {
			if (ch=='U')
				flags |= LONGINT;
			base = DEC;
			goto nosign;
		} else if (ch=='X'||ch=='x') {
			base = HEX;
			/* leading 0x/X only if non-zero */
			if (flags & ALT && _ulong != 0)
				flags |= HEXPREFIX;

			/* unsigned conversions */
nosign:			sign = '\0';
			/*
			 * ``... diouXx conversions ... if a precision is
			 * specified, the 0 flag will be ignored.''
			 *	-- ANSI X3J11
			 */
number:	if ((dprec = prec) >= 0)
				flags &= ~ZEROPAD;

			/*
			 * ``The result of converting a zero value with an
			 * explicit precision of zero is no characters.''
			 *	-- ANSI X3J11
			 */
			cp = buf + BUF;
			if (_ulong != 0 || prec != 0) {
				register unsigned char _d,notlastdigit;
				do {
					notlastdigit=(_ulong>=base);
					_d = _ulong % base;

					if (_d<10) {
						_d+='0';
					} else {
						_d+='a'-10;
						if (ch=='X') _d&=~0x20;
					}
					*--cp=_d;
					_ulong /= base;
				} while (notlastdigit);
#ifndef LIGHTPRINTF
				// handle octal leading 0 
				if (base==OCT && flags & ALT && *cp != '0')
					*--cp = '0';
#endif
			}

			size = buf + BUF - cp;
	} else {  //default
		/* "%?" prints ?, unless ? is NUL */
			if (ch == '\0')
				goto done;
			/* pretend it was %c with argument ch */
			cp = buf;
			*cp = ch;
			size = 1;
			sign = '\0';
		}

		/*
		 * All reasonable formats wind up here.  At this point,
		 * `cp' points to a string which (if not flags&LADJUST)
		 * should be padded out to `width' places.  If
		 * flags&ZEROPAD, it should first be prefixed by any
		 * sign or other prefix; otherwise, it should be blank
		 * padded before the prefix is emitted.  After any
		 * left-hand padding and prefixing, emit zeroes
		 * required by a decimal [diouxX] precision, then print
		 * the string proper, then emit zeroes required by any
		 * leftover floating precision; finally, if LADJUST,
		 * pad with blanks.
		 */

		/*
		 * compute actual size, so we know how much to pad.
		 */
		fieldsz = size;

		dpad = dprec - size;
		if (dpad < 0)
		    dpad = 0;

		if (sign)
			fieldsz++;
		else if (flags & HEXPREFIX)
			fieldsz += 2;
		fieldsz += dpad;

		/* right-adjusting blank padding */
		if ((flags & (LADJUST|ZEROPAD)) == 0)
			PAD_SP(width - fieldsz);

		/* prefix */
		if (sign) {
			PRINT(&sign, 1);
		} else if (flags & HEXPREFIX) {
			ox[0] = '0';
			ox[1] = ch;
			PRINT(ox, 2);
		}

		/* right-adjusting zero padding */
		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
			PAD_0(width - fieldsz);

		/* leading zeroes from decimal precision */
		PAD_0(dpad);

		/* the string or number proper */
		PRINT(cp, size);

		/* left-adjusting padding (always blank) */
		if (flags & LADJUST)
			PAD_SP(width - fieldsz);
	}
done:
	va_end(ap);
}   
/* end*/

⌨️ 快捷键说明

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