分享
 
 
 

printf() function implementation!

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

/*****************************************************************************

Stripped-down printf()

Chris Giese <geezer@execpc.com> http://www.execpc.com/~geezer

Release date: Dec 12, 2003

This code is public domain (no copyright).

You can do whatever you want with it.

Revised Dec 12, 2003

- fixed vsprintf() and sprintf() in test code

Revised Jan 28, 2002

- changes to make characters 0x80-0xFF display properly

Revised 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

# (???) no

width: (field width) DONE

prec: (precision) no

conv: 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 DONE

mod: 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 0

#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 *) or

other 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 16

typedef int (*fnptr_t)(unsigned c, void **helper);

/*****************************************************************************

name: do_printf

action: minimal subfunction for ?printf, calls function

'fn' with arg 'ptr' for each character to be output

returns: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, short);

else

num = va_arg(args, unsigned short);

}

/* 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 ASCII

OK, 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 char);

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(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 1 /* 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;

}

/*****************************************************************************

PRINTF

You must write your own putchar()

*****************************************************************************/

int 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;

}

/*****************************************************************************

*****************************************************************************/

int 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

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有