printf.c
来自「WinAoE is an open source GPLv3 driver fo」· C语言 代码 · 共 407 行
C
407 行
/*****************************************************************************Stripped-down printf()Chris Giese <geezer@execpc.com> http://www.execpc.com/~geezerRelease date: Dec 12, 2003This code is public domain (no copyright).You can do whatever you want with it.Revised Dec 12, 2003- fixed vsprintf() and sprintf() in test codeRevised Jan 28, 2002- changes to make characters 0x80-0xFF display properlyRevised June 10, 2001- changes to make vsprintf() terminate string with '\0'Revised May 12, 2000- math in DO_NUM is now unsigned, as it should be- %0 flag (pad left with zeroes) now works- actually did some TESTING, maybe fixed some other bugs%[flag][width][.prec][mod][conv]flag: - left justify, pad right w/ blanks DONE 0 pad left w/ 0 for numerics DONE + always print sign, + or - no ' ' (blank) no # (???) nowidth: (field width) DONEprec: (precision) noconv: d,i decimal int DONE u decimal unsigned DONE o octal DONE x,X hex DONE f,e,g,E,G float no c char DONE s string DONE p ptr DONEmod: N near ptr DONE F far ptr no h short (16-bit) int DONE l long (32-bit) int DONE L long long (64-bit) int no*****************************************************************************///#include <string.h> /* strlen() *///#include <stdio.h> /* stdout, putchar(), fputs() (but not printf() :) */#if 1#include <stdarg.h> /* va_list, va_start(), va_arg(), va_end() */#else/* home-brew STDARG.H, also public-domain: *//* Assume: width of stack == width of int. Don't use sizeof(char *) orother pointer because sizeof(char *)==4 for LARGE-model 16-bit code.Assume: width is a power of 2 */#define STACK_WIDTH sizeof(int)/* Round up object width so it's an even multiple of STACK_WIDTH.Using & for division here, so STACK_WIDTH must be a power of 2. */#define TYPE_WIDTH(TYPE) \ ((sizeof(TYPE) + STACK_WIDTH - 1) & ~(STACK_WIDTH - 1))/* point the va_list pointer to LASTARG,then advance beyond it to the first variable arg */#define va_start(PTR, LASTARG) \ PTR = (va_list)((char *)&(LASTARG) + TYPE_WIDTH(LASTARG))#define va_end(PTR) /* nothing *//* Increment the va_list pointer, then return(evaluate to, actually) the previous value of the pointer.WHEEE! At last; a valid use for the C comma operator! */#define va_arg(PTR, TYPE) ( \ (char *)(PTR) += TYPE_WIDTH(TYPE) \ , \ *((TYPE *)((char *)(PTR) - TYPE_WIDTH(TYPE))) \ )/* Every other compiler/libc seems to be using 'void *', so...(I _was_ using 'unsigned char *') */typedef void *va_list;#endif/* flags used in processing format string */#define PR_LJ 0x01 /* left justify */#define PR_CA 0x02 /* use A-F instead of a-f for hex */#define PR_SG 0x04 /* signed numeric conversion (%d vs. %u) */#define PR_32 0x08 /* long (32-bit) numeric conversion */#define PR_16 0x10 /* short (16-bit) numeric conversion */#define PR_WS 0x20 /* PR_SG set and num was < 0 */#define PR_LZ 0x40 /* pad left with '0' instead of ' ' */#define PR_FP 0x80 /* pointers are far *//* largest number handled is 2^32-1, lowest radix handled is 8.2^32-1 in base 8 has 11 digits (add 5 for trailing NUL and for slop) */#define PR_BUFLEN 16typedef int (*fnptr_t)(unsigned c, void **helper);/*****************************************************************************name: do_printfaction: minimal subfunction for ?printf, calls function 'fn' with arg 'ptr' for each character to be outputreturns:total number of characters output*****************************************************************************/int do_printf(const char *fmt, va_list args, fnptr_t fn, void *ptr){ unsigned flags, actual_wd, count, given_wd; unsigned char *where, buf[PR_BUFLEN]; unsigned char state, radix; long num; state = flags = count = given_wd = 0;/* begin scanning format specifier list */ for(; *fmt; fmt++) { switch(state) {/* STATE 0: AWAITING % */ case 0: if(*fmt != '%') /* not %... */ { fn(*fmt, &ptr); /* ...just echo it */ count++; break; }/* found %, get next char and advance state to check if next char is a flag */ state++; fmt++; /* FALL THROUGH *//* STATE 1: AWAITING FLAGS (%-0) */ case 1: if(*fmt == '%') /* %% */ { fn(*fmt, &ptr); count++; state = flags = given_wd = 0; break; } if(*fmt == '-') { if(flags & PR_LJ)/* %-- is illegal */ state = flags = given_wd = 0; else flags |= PR_LJ; break; }/* not a flag char: advance state to check if it's field width */ state++;/* check now for '%0...' */ if(*fmt == '0') { flags |= PR_LZ; fmt++; } /* FALL THROUGH *//* STATE 2: AWAITING (NUMERIC) FIELD WIDTH */ case 2: if(*fmt >= '0' && *fmt <= '9') { given_wd = 10 * given_wd + (*fmt - '0'); break; }/* not field width: advance state to check if it's a modifier */ state++; /* FALL THROUGH *//* STATE 3: AWAITING MODIFIER CHARS (FNlh) */ case 3: if(*fmt == 'F') { flags |= PR_FP; break; } if(*fmt == 'N') break; if(*fmt == 'l') { flags |= PR_32; break; } if(*fmt == 'h') { flags |= PR_16; break; }/* not modifier: advance state to check if it's a conversion char */ state++; /* FALL THROUGH *//* STATE 4: AWAITING CONVERSION CHARS (Xxpndiuocs) */ case 4: where = buf + PR_BUFLEN - 1; *where = '\0'; switch(*fmt) { case 'X': flags |= PR_CA; /* FALL THROUGH *//* xxx - far pointers (%Fp, %Fn) not yet supported */ case 'x': case 'p': case 'n': radix = 16; goto DO_NUM; case 'd': case 'i': flags |= PR_SG; /* FALL THROUGH */ case 'u': radix = 10; goto DO_NUM; case 'o': radix = 8;/* load the value to be printed. l=long=32 bits: */DO_NUM: if(flags & PR_32) num = va_arg(args, unsigned long);/* h=short=16 bits (signed or unsigned) */ else if(flags & PR_16) { if(flags & PR_SG) num = va_arg(args, int); else num = va_arg(args, unsigned int); }/* no h nor l: sizeof(int) bits (signed or unsigned) */ else { if(flags & PR_SG) num = va_arg(args, int); else num = va_arg(args, unsigned int); }/* take care of sign */ if(flags & PR_SG) { if(num < 0) { flags |= PR_WS; num = -num; } }/* convert binary to octal/decimal/hex ASCIIOK, I found my mistake. The math here is _always_ unsigned */ do { unsigned long temp; temp = (unsigned long)num % radix; where--; if(temp < 10) *where = temp + '0'; else if(flags & PR_CA) *where = temp - 10 + 'A'; else *where = temp - 10 + 'a'; num = (unsigned long)num / radix; } while(num != 0); goto EMIT; case 'c':/* disallow pad-left-with-zeroes for %c */ flags &= ~PR_LZ; where--; *where = (unsigned char)va_arg(args, unsigned int); actual_wd = 1; goto EMIT2; case 's':/* disallow pad-left-with-zeroes for %s */ flags &= ~PR_LZ; where = va_arg(args, unsigned char *);EMIT: actual_wd = strlen((char *)where); if(flags & PR_WS) actual_wd++;/* if we pad left with ZEROES, do the sign now */ if((flags & (PR_WS | PR_LZ)) == (PR_WS | PR_LZ)) { fn('-', &ptr); count++; }/* pad on left with spaces or zeroes (for right justify) */EMIT2: if((flags & PR_LJ) == 0) { while(given_wd > actual_wd) { fn(flags & PR_LZ ? '0' : ' ', &ptr); count++; given_wd--; } }/* if we pad left with SPACES, do the sign now */ if((flags & (PR_WS | PR_LZ)) == PR_WS) { fn('-', &ptr); count++; }/* emit string/char/converted number */ while(*where != '\0') { fn(*where++, &ptr); count++; }/* pad on right with spaces (for left justify) */ if(given_wd < actual_wd) given_wd = 0; else given_wd -= actual_wd; for(; given_wd; given_wd--) { fn(' ', &ptr); count++; } break; default: break; } default: state = flags = given_wd = 0; break; } } return count;}#if 0 /* testing *//*****************************************************************************SPRINTF*****************************************************************************/static int vsprintf_help(unsigned c, void **ptr){ char *dst; dst = *ptr; *dst++ = (char)c; *ptr = dst; return 0 ;}/**********************************************************************************************************************************************************/int vsprintf(char *buf, const char *fmt, va_list args){ int rv; rv = do_printf(fmt, args, vsprintf_help, (void *)buf); buf[rv] = '\0'; return rv;}/**********************************************************************************************************************************************************/int sprintf(char *buf, const char *fmt, ...){ va_list args; int rv; va_start(args, fmt); rv = vsprintf(buf, fmt, args); va_end(args); return rv;}/*****************************************************************************PRINTFYou must write your own putchar()*****************************************************************************/#endifint vprintf_help(unsigned c, void **ptr){ putchar(c); return 0 ;}/**********************************************************************************************************************************************************/int vprintf(const char *fmt, va_list args){ return do_printf(fmt, args, vprintf_help, NULL);}/**********************************************************************************************************************************************************/int printf(const char *fmt, ...){ va_list args; int rv; va_start(args, fmt); rv = vprintf(fmt, args); va_end(args); return rv;}/**********************************************************************************************************************************************************/#if 0int main(void){ char buf[64]; sprintf(buf, "%u score and %i years ago...\n", 4, -7); fputs(buf, stdout); /* puts() adds newline */ sprintf(buf, "-1L == 0x%lX == octal %lo\n", -1L, -1L); fputs(buf, stdout); /* puts() adds newline */ printf("<%-08s> and <%08s> justified strings\n", "left", "right"); return 0;}#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?