📄 printf.c
字号:
/* Author: Daniel Malik (daniel.malik@motorola.com) */
/* Revision history:
1.0 First code released (15/02/2001)
1.1 Bug in fractional support: fmtpars.justification_options == zero_fill; changed to: fmtpars.justification_options = zero_fill;
Changed fractional handling, 0xe000 is -.25 not -.75 as I thought
1.2 Optimized number printout (now uses unsigned division and unsigned parameters), hex printout correction (22/02/2001)
1.3 global variable changed to static (19/03/2001)
*/
#include "stdio.h"
/* options */
#define support_fractional /* fractional (16bit), conversion character "r", precision (when >3) specifies maximum number of characters (no rounding is done, string is cut) */
#define BUFFER_SIZE 15 /* buffer size for number conversion */
#define isdigit(c) ((c>='0')&&(c<='9'))
enum justification_options {
left_justification,
right_justification,
zero_fill
};
enum sign_options {
only_minus,
sign_always,
space_holder
};
enum argument_options {
normal_argument,
long_argument
};
typedef struct {
int justification_options;
int sign_options;
int alternate_form;
int argument_options;
int conversion_char;
int field_width;
int precision;
} print_format;
char *parseformat(char *format,print_format *f,va_list *arg) {
int flag_found;
char c=*format;
(*f).justification_options = right_justification;
(*f).sign_options = only_minus;
(*f).alternate_form = 0;
(*f).argument_options = normal_argument;
(*f).field_width = 0;
(*f).precision = -1; /* -1 means not specified */
if (c == '\0') return(0);
if (c == '%') {
(*f).conversion_char = '%';
return(++format);
}
do {
flag_found = 1;
switch (c) {
case '-': (*f).justification_options = left_justification; break;
case '+': (*f).sign_options = sign_always; break;
case ' ': if ((*f).sign_options != sign_always) (*f).sign_options = space_holder; break;
case '#': (*f).alternate_form = 1; break;
case '0': if ((*f).justification_options != left_justification) (*f).justification_options = zero_fill; break;
default: flag_found = 0;
}
if (flag_found) c=*++format; else break;
} while (flag_found);
if (c == '*') {
if (((*f).field_width = va_arg(*arg, int)) < 0) {
(*f).justification_options = left_justification;
(*f).field_width = -(*f).field_width;
}
c = *++format;
}
else while (isdigit(c)) {
(*f).field_width = ((*f).field_width * 10) + (c - '0');
c = *++format;
}
if (c == '.') {
(*f).precision = 0;
if ((c = *++format) == '*') {
if (((*f).precision = va_arg(*arg, int)) < 0) (*f).precision = 0;
c = *++format;
}
else while (isdigit(c)) {
(*f).precision = ((*f).precision * 10) + (c - '0');
c = *++format;
}
}
if (c=='l') {
(*f).argument_options = long_argument;
c = *++format;
}
(*f).conversion_char = c;
switch (c) {
case 'd':
case 'i':
case 'u':
case 'o':
case 'x':
case 'X':
if ((*f).precision<0) (*f).precision = 1;
else if ((*f).justification_options == zero_fill) (*f).justification_options = right_justification;
break;
case 'f':
case 'F':
if ((*f).precision<0) (*f).precision = 6;
break;
case 'g':
case 'G':
case 'e':
case 'E':
if ((*f).precision<0) (*f).precision = 6;
if (!(*f).precision) (*f).precision = 1;
break;
case 'p':
(*f).conversion_char = 'x';
(*f).alternate_form = 1;
(*f).precision = 4;
break;
case '\0':
return(0);
}
return(++format);
}
/* returns pointer to first character of output string */
char *long2str (unsigned long int n, char *buffer, print_format *f) {
int base,minus=0,digit,count=0;
buffer+=BUFFER_SIZE; /*maximum length of long number plus sign */
switch ((*f).conversion_char) {
case 'd':
#ifdef support_fractional
case 'r':
#endif
case 'i':
if (n & 0x80000000) {
n=~n+1;
minus=1;
}
case 'u':
base = 10;
break;
case 'o':
base = 8;
break;
case 'x':
case 'X':
base = 16;
}
do {
digit=n%base;
n/=base;
if (digit<10) digit+='0'; else {
digit+='a'-10;
if ((*f).conversion_char=='X') digit+='A'-'a';
}
*(--buffer)=digit;
count++;
} while (n);
if (base == 8 && (*f).alternate_form && *(++buffer) != '0') {
*--buffer = '0';
count++;
}
if ((*f).justification_options == zero_fill) {
(*f).precision = (*f).field_width;
if (minus || (*f).sign_options != only_minus) (*f).precision--;
if (base == 16 && (*f).alternate_form) (*f).precision-=2;
}
if ((count<BUFFER_SIZE)&&(count<(*f).precision)) {
*--buffer='0';
count++;
}
if (base == 16 && (*f).alternate_form) {
*--buffer = (*f).conversion_char;
*--buffer = '0';
}
if (minus) *--buffer = '-';
else if ((*f).sign_options == sign_always) *--buffer = '+';
else if ((*f).sign_options == space_holder) *--buffer = ' ';
return(buffer);
}
void justify_and_print_string(void (*output_func)(char), char *buffer, print_format *f) {
int buf_lng;
char *bptr=buffer;
while(*(bptr++));
buf_lng=bptr-buffer-1;
if ((*f).justification_options != left_justification) {
int i;
char fill_char = ((*f).justification_options == zero_fill) ? '0' : ' ';
if (((*buffer == '+') || (*buffer == '-')) && (fill_char == '0')) {
output_func(*(buffer++));
buf_lng--;
}
i=buf_lng;
while (i<(*f).field_width) {
output_func(fill_char);
i++;
}
}
while(*buffer) output_func(*(buffer++));
if ((*f).justification_options == left_justification) {
while (buf_lng < (*f).field_width) {
output_func(' ');
buf_lng++;
}
}
}
#ifdef support_fractional
unsigned long fractable[15]={500000000,250000000,125000000,62500000,31250000,
15625000,7812500,3906250,1953125,976563,488281,
244141,122070,61035,30518};
long int frac2long (unsigned long int number) {
int i;
long int result=0;
for (i=14;i>=0;i--) {
if (number&1) result+=fractable[i];
number>>=1;
}
if (number&1) return(result-(long)1000000000);
return(result);
}
#endif
void pformatter (void (*output_func)(char), char *format, va_list arg) {
print_format fmtpars;
char *fmt1;
while ((*format)!='\0') {
while (((*format)!='%')&&((*format)!='\0')) {
output_func(*(format++));
}
fmt1=format;
if ((*(format))!='\0') if (format = parseformat(format+1,&fmtpars,&arg)) {
switch (fmtpars.conversion_char)
{
case 'c': output_func(va_arg(arg, char)); break;
case '%': output_func('%'); break;
case 's': justify_and_print_string(output_func,va_arg(arg,char *),&fmtpars); break;
#ifdef support_fractional
case 'r': {
char buffer[BUFFER_SIZE+1+2];
char *bptr;
unsigned long int number;
int i,j;
buffer[BUFFER_SIZE+2]='\0';
if (fmtpars.argument_options == long_argument) number = va_arg(arg, unsigned long);
else number = va_arg(arg, unsigned int);
number=frac2long(number);
j=fmtpars.precision;
i=fmtpars.field_width;
fmtpars.field_width=10;
fmtpars.justification_options = zero_fill;
bptr=long2str((unsigned long int)number,buffer+2,&fmtpars);
if (!isdigit(*bptr)) {
*(bptr-2)=*bptr;
*(bptr-1)='0';
*(bptr)='.';
bptr-=2;
} else {
*(bptr-1)='0';
*(bptr)='.';
bptr--;
}
fmtpars.field_width=i;
if ((j<12)&&(j>3)) *(bptr+j)='\0'; /* shorten the string if precision > 3 */
justify_and_print_string(output_func,bptr,&fmtpars);
} break;
#endif
case 'd':
case 'o':
case 'u':
case 'x':
case 'X':
case 'i': {
char buffer[BUFFER_SIZE+1];
char *bptr;
long int number;
buffer[BUFFER_SIZE]='\0';
if (fmtpars.argument_options == long_argument) number = va_arg(arg, long);
else if (fmtpars.conversion_char=='d') number = va_arg(arg, int);
else number = va_arg(arg, unsigned int);
bptr=long2str((unsigned long int)number,buffer,&fmtpars);
justify_and_print_string(output_func,bptr,&fmtpars);
} break;
default: while(fmt1<format) output_func(*(fmt1++)); /* print unknown conversion strings */
}
}
}
}
void printf(char *format, ...) {
pformatter(&stdio_putchar, format, va_start(format));
}
static char *dest_ptr;
void output_to_string(char character) {
*(dest_ptr++)=character;
}
void sprintf(char *dest, char *format, ...) {
char *old_dest_ptr=dest_ptr; /* save old pointer to make sprintf reentrant */
dest_ptr=dest;
pformatter(&output_to_string, format, va_start(format));
*dest_ptr='\0';
dest_ptr=old_dest_ptr;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -