📄 strformat.c
字号:
#include <strformat.h>#define HAVE_DOUBLE#define HAVE_LONGLONG#ifndef LARGEST_SIGNED#ifdef HAVE_LONGLONG#define LARGEST_SIGNED long long int#else#define LARGEST_UNSIGNED long int#endif#endif#ifndef LARGEST_UNSIGNED#ifdef HAVE_LONGLONG#define LARGEST_UNSIGNED unsigned long long int#else#define LARGEST_UNSIGNED unsigned long int#endif#endif#ifndef POINTER_INT#define POINTER_INT unsigned long#endiftypedef unsigned int FormatFlags;#define MAKE_MASK(shift,size) (((1 << size) - 1) << (shift))#define JUSTIFY_SHIFT 0#define JUSTIFY_SIZE 1#define JUSTIFY_RIGHT 0x0000#define JUSTIFY_LEFT 0x0001#define JUSTIFY_MASK MAKE_MASK(JUSTIFY_SHIFT,JUSTIFY_SIZE)/* How a positive number is prefixed */#define POSITIVE_SHIFT (JUSTIFY_SHIFT + JUSTIFY_SIZE)#define POSITIVE_NONE (0x0000 << POSITIVE_SHIFT)#define POSITIVE_SPACE (0x0001 << POSITIVE_SHIFT)#define POSITIVE_PLUS (0x0003 << POSITIVE_SHIFT)#define POSITIVE_MASK MAKE_MASK(POSITIVE_SHIFT, POSITIVE_SIZE)#define POSITIVE_SIZE 2#define ALTERNATE_FORM_SHIFT (POSITIVE_SHIFT + POSITIVE_SIZE)#define ALTERNATE_FORM_SIZE 1#define ALTERNATE_FORM (0x0001 << ALTERNATE_FORM_SHIFT)#define PAD_SHIFT (ALTERNATE_FORM_SHIFT + ALTERNATE_FORM_SIZE)#define PAD_SIZE 1#define PAD_SPACE (0x0000 << PAD_SHIFT)#define PAD_ZERO (0x0001 << PAD_SHIFT)#define SIZE_SHIFT (PAD_SHIFT + PAD_SIZE)#define SIZE_SIZE 3#define SIZE_CHAR (0x0001 << SIZE_SHIFT)#define SIZE_SHORT (0x0002 << SIZE_SHIFT)#define SIZE_INT (0x0000 << SIZE_SHIFT)#define SIZE_LONG (0x0003 << SIZE_SHIFT)#define SIZE_LONGLONG (0x0004 << SIZE_SHIFT)#define SIZE_MASK MAKE_MASK(SIZE_SHIFT,SIZE_SIZE)#define CONV_SHIFT (SIZE_SHIFT + SIZE_SIZE)#define CONV_SIZE 3#define CONV_INTEGER (0x0001 << CONV_SHIFT)#define CONV_FLOAT (0x0002 << CONV_SHIFT)#define CONV_POINTER (0x0003 << CONV_SHIFT)#define CONV_STRING (0x0004 << CONV_SHIFT)#define CONV_CHAR (0x0005 << CONV_SHIFT)#define CONV_PERCENT (0x0006 << CONV_SHIFT)#define CONV_WRITTEN (0x0007 << CONV_SHIFT)#define CONV_MASK MAKE_MASK(CONV_SHIFT, CONV_SIZE)#define RADIX_SHIFT (CONV_SHIFT + CONV_SIZE)#define RADIX_SIZE 2#define RADIX_DECIMAL (0x0001 << RADIX_SHIFT)#define RADIX_OCTAL (0x0002 << RADIX_SHIFT)#define RADIX_HEX (0x0003 << RADIX_SHIFT)#define RADIX_MASK MAKE_MASK(RADIX_SHIFT,RADIX_SIZE)#define SIGNED_SHIFT (RADIX_SHIFT + RADIX_SIZE)#define SIGNED_SIZE 1#define SIGNED_NO (0x0000 << SIGNED_SHIFT)#define SIGNED_YES (0x0001 << SIGNED_SHIFT)#define SIGNED_MASK MAKE_MASK(SIGNED_SHIFT,SIGNED_SIZE)#define CAPS_SHIFT (SIGNED_SHIFT + SIGNED_SIZE)#define CAPS_SIZE 1#define CAPS_NO (0x0000 << CAPS_SHIFT)#define CAPS_YES (0x0001 << CAPS_SHIFT)#define CAPS_MASK MAKE_MASK(CAPS_SHIFT,CAPS_SIZE)#define FLOAT_SHIFT (CAPS_SHIFT + CAPS_SIZE)#define FLOAT_SIZE 2#define FLOAT_NORMAL (0x0000 << FLOAT_SHIFT)#define FLOAT_EXPONENT (0x0001 << FLOAT_SHIFT)#define FLOAT_DEPENDANT (0x0002 << FLOAT_SHIFT)#define FLOAT_HEX (0x0003 << FLOAT_SHIFT)#define FLOAT_MASK MAKE_MASK(FLOAT_SHIFT, FLOAT_SIZE)static FormatFlagsparse_flags(const char **posp){ FormatFlags flags = 0; const char *pos = *posp; while (1) { switch(*pos) { case '-': flags |= JUSTIFY_LEFT; break; case '+': flags |= POSITIVE_PLUS; break; case ' ': flags |= POSITIVE_SPACE; break; case '#': flags |= ALTERNATE_FORM; break; case '0': flags |= PAD_ZERO; break; default: *posp = pos; return flags; } pos++; } }static unsigned intparse_uint(const char **posp){ unsigned v = 0; const char *pos = *posp; char ch; while((ch = *pos) >= '0' && ch <= '9') { v = v * 10 + (ch - '0'); pos++; } *posp = pos; return v;}#define MAXCHARS_HEX ((sizeof(LARGEST_UNSIGNED) * 8) / 4 )/* Largest number of characters needed for converting an unsigned integer. */#define MAXCHARS ((sizeof(LARGEST_UNSIGNED) * 8 + 2) / 3 )static unsigned intoutput_uint_decimal(char **posp, LARGEST_UNSIGNED v){ unsigned int len; char *pos = *posp; while (v > 0) { *--pos = (v % 10) + '0'; v /= 10; } len = *posp - pos; *posp = pos; return len;}static unsigned intoutput_uint_hex(char **posp, LARGEST_UNSIGNED v, unsigned int flags){ unsigned int len; const char *hex = (flags & CAPS_YES) ?"0123456789ABCDEF":"0123456789abcdef"; char *pos = *posp; while (v > 0) { *--pos = hex[(v % 16)]; v /= 16; } len = *posp - pos; *posp = pos; return len;}static unsigned intoutput_uint_octal(char **posp, LARGEST_UNSIGNED v){ unsigned int len; char *pos = *posp; while (v > 0) { *--pos = (v % 8) + '0'; v /= 8; } len = *posp - pos; *posp = pos; return len;}static StrFormatResultfill_space(const StrFormatContext *ctxt, unsigned int len){ StrFormatResult res; static const char buffer[16] = " "; while(len > 16) { res = ctxt->write_str(ctxt->user_data, buffer, 16); if (res != STRFORMAT_OK) return res; len -= 16; } if (len == 0) return STRFORMAT_OK; return ctxt->write_str(ctxt->user_data, buffer, len);}static StrFormatResultfill_zero(const StrFormatContext *ctxt, unsigned int len){ StrFormatResult res; static const char buffer[16] = "0000000000000000"; while(len > 16) { res = ctxt->write_str(ctxt->user_data, buffer, 16); if (res != STRFORMAT_OK) return res; len -= 16; } if (len == 0) return STRFORMAT_OK; return ctxt->write_str(ctxt->user_data, buffer, len);}#define CHECKCB(res) {if ((res) != STRFORMAT_OK) {va_end(ap); return -1;}}intformat_str(const StrFormatContext *ctxt, const char *format, ...){ int ret; va_list ap; va_start(ap, format); ret = format_str_v(ctxt, format, ap); va_end(ap); return ret;}intformat_str_v(const StrFormatContext *ctxt, const char *format, va_list ap){ unsigned int written = 0; const char *pos = format; while(*pos != '\0') { FormatFlags flags; unsigned int minwidth = 0; int precision = -1; /* Negative means no precision */ char ch; const char *start = pos; while( (ch = *pos) != '\0' && ch != '%') pos++; if (pos != start) { CHECKCB(ctxt->write_str(ctxt->user_data, start, pos - start)); written += pos - start; } if (*pos == '\0') { va_end(ap); return written; } pos++; if (*pos == '\0') { va_end(ap); return written; } flags = parse_flags(&pos); /* parse width */ if (*pos >= '1' && *pos <= '9') { minwidth = parse_uint(&pos); } else if (*pos == '*') { int w = va_arg(ap,int); if (w < 0) { flags |= JUSTIFY_LEFT; minwidth = w; } else { minwidth = w; } pos ++; } /* parse precision */ if (*pos == '.') { pos++; if (*pos >= '0' && *pos <= '9') { precision = parse_uint(&pos); } else if (*pos == '*') { precision = va_arg(ap,int); } } if (*pos == 'l') { pos++; if (*pos == 'l') { flags |= SIZE_LONGLONG; pos++; } else { flags |= SIZE_LONG; } } else if (*pos == 'h') { pos++; if (*pos == 'h') { flags |= SIZE_CHAR; pos++; } else { flags |= SIZE_SHORT; } } /* parse conversion specifier */ switch(*pos) { case 'd': case 'i': flags |= CONV_INTEGER | RADIX_DECIMAL | SIGNED_YES; break; case 'u': flags |= CONV_INTEGER | RADIX_DECIMAL | SIGNED_NO; break; case 'o': flags |= CONV_INTEGER | RADIX_OCTAL | SIGNED_NO; break; case 'x': flags |= CONV_INTEGER | RADIX_HEX | SIGNED_NO; break; case 'X': flags |= CONV_INTEGER | RADIX_HEX | SIGNED_NO | CAPS_YES; break;#ifdef HAVE_DOUBLE case 'f': flags |= CONV_FLOAT | FLOAT_NORMAL; break; case 'F': flags |= CONV_FLOAT | FLOAT_NORMAL | CAPS_YES; break; case 'e': flags |= CONV_FLOAT | FLOAT_EXPONENT; break; case 'E': flags |= CONV_FLOAT | FLOAT_EXPONENT | CAPS_YES; break; case 'g': flags |= CONV_FLOAT | FLOAT_DEPENDANT; break; case 'G': flags |= CONV_FLOAT | FLOAT_DEPENDANT | CAPS_YES; break; case 'a': flags |= CONV_FLOAT | FLOAT_HEX; break; case 'A': flags |= CONV_FLOAT | FLOAT_HEX | CAPS_YES; break;#endif case 'c': flags |= CONV_CHAR; break; case 's': flags |= CONV_STRING; break; case 'p': flags |= CONV_POINTER; break; case 'n': flags |= CONV_WRITTEN; break; case '%': flags |= CONV_PERCENT; break; case '\0': va_end(ap); return written; } pos++; switch(flags & CONV_MASK) { case CONV_PERCENT: CHECKCB(ctxt->write_str(ctxt->user_data, "%", 1)); written++; break; case CONV_INTEGER: { /* unsigned integers */ char *prefix = 0; /* sign, "0x" or "0X" */ unsigned int prefix_len = 0; char buffer[MAXCHARS]; char *conv_pos = buffer + MAXCHARS; unsigned int conv_len = 0; unsigned int width = 0; unsigned int precision_fill; unsigned int field_fill; LARGEST_UNSIGNED uvalue = 0; int negative = 0; if (precision < 0) precision = 1; else flags &= ~PAD_ZERO; if (flags & SIGNED_YES) { /* signed integers */ LARGEST_SIGNED value = 0; switch(flags & SIZE_MASK) { case SIZE_CHAR: value = (signed char)va_arg(ap, int); break; case SIZE_SHORT: value = (short)va_arg(ap, int); break; case SIZE_INT: value = va_arg(ap, int); break;#ifndef HAVE_LONGLONG case SIZE_LONGLONG: /* Treat long long the same as long */#endif case SIZE_LONG: value = va_arg(ap, long); break;#ifdef HAVE_LONGLONG case SIZE_LONGLONG: value = va_arg(ap, long long); break;#endif } if (value < 0) { uvalue = -value; negative = 1; } else { uvalue = value; } } else { switch(flags & SIZE_MASK) { case SIZE_CHAR: uvalue = (unsigned char)va_arg(ap,unsigned int); break; case SIZE_SHORT: uvalue = (unsigned short)va_arg(ap,unsigned int); break; case SIZE_INT: uvalue = va_arg(ap,unsigned int); break;#ifndef HAVE_LONGLONG case SIZE_LONGLONG: /* Treat long long the same as long */#endif case SIZE_LONG: uvalue = va_arg(ap,unsigned long); break;#ifdef HAVE_LONGLONG case SIZE_LONGLONG: uvalue = va_arg(ap,unsigned long long); break;#endif } } switch(flags & (RADIX_MASK)) { case RADIX_DECIMAL: conv_len = output_uint_decimal(&conv_pos,uvalue); break; case RADIX_OCTAL: conv_len = output_uint_octal(&conv_pos,uvalue); break; case RADIX_HEX: conv_len = output_uint_hex(&conv_pos,uvalue, flags); break; } width += conv_len; precision_fill = (precision > conv_len) ? precision - conv_len : 0; if ((flags & (RADIX_MASK | ALTERNATE_FORM)) == (RADIX_OCTAL | ALTERNATE_FORM)) { if (precision_fill < 1) precision_fill = 1; } width += precision_fill; if ((flags & (RADIX_MASK | ALTERNATE_FORM)) == (RADIX_HEX | ALTERNATE_FORM) && uvalue != 0) { prefix_len = 2; if (flags & CAPS_YES) { prefix = "0X"; } else { prefix = "0x"; } } if (flags & SIGNED_YES) { if (negative) { prefix = "-"; prefix_len = 1; } else { switch(flags & POSITIVE_MASK) { case POSITIVE_SPACE: prefix = " "; prefix_len = 1; break; case POSITIVE_PLUS: prefix = "+"; prefix_len = 1; break; } } } width += prefix_len; field_fill = (minwidth > width) ? minwidth - width : 0; if ((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) { if (flags & PAD_ZERO) { precision_fill += field_fill; } else { CHECKCB(fill_space(ctxt,field_fill)); } } if (prefix_len > 0) CHECKCB(ctxt->write_str(ctxt->user_data, prefix, prefix_len)); written += prefix_len; CHECKCB(fill_zero(ctxt,precision_fill)); written += prefix_len; CHECKCB(ctxt->write_str(ctxt->user_data, conv_pos,conv_len)); written += conv_len; if ((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) { CHECKCB(fill_space(ctxt,field_fill)); } written += field_fill; } break; case CONV_STRING: { unsigned int field_fill; unsigned int len; char *str = va_arg(ap,char *); if (str) { char *pos = str; while(*pos != '\0') pos++; len = pos - str; } else { str = "(null)"; len = 6; } if (precision >= 0 && precision < len) len = precision; field_fill = (minwidth > len) ? minwidth - len : 0; if ((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) { CHECKCB(fill_space(ctxt,field_fill)); } CHECKCB(ctxt->write_str(ctxt->user_data, str,len)); written += len; if ((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) { CHECKCB(fill_space(ctxt,field_fill)); } written += field_fill; } break; case CONV_POINTER: { LARGEST_UNSIGNED uvalue = (LARGEST_UNSIGNED)(POINTER_INT)va_arg(ap,void *); char buffer[MAXCHARS_HEX + 3]; char *conv_pos = buffer + MAXCHARS_HEX+3; unsigned int conv_len; unsigned int field_fill; conv_len = output_uint_hex(&conv_pos,uvalue,flags); if (conv_len == 0) { *--conv_pos = '0'; conv_len++; } *--conv_pos = 'x'; *--conv_pos = '0'; *--conv_pos = '#'; conv_len += 3; field_fill = (minwidth > conv_len) ? minwidth - conv_len : 0; if ((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) { CHECKCB(fill_space(ctxt,field_fill)); } CHECKCB(ctxt->write_str(ctxt->user_data, conv_pos,conv_len)); written += conv_len; if ((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) { CHECKCB(fill_space(ctxt,field_fill)); } written += field_fill; } break; case CONV_CHAR: { char ch = va_arg(ap,int); unsigned int field_fill = (minwidth > 1) ? minwidth - 1 : 0; if ((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) { CHECKCB(fill_space(ctxt,field_fill)); written += field_fill; } CHECKCB(ctxt->write_str(ctxt->user_data, &ch, 1)); written++; if ((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) { CHECKCB(fill_space(ctxt,field_fill)); } written+= field_fill; } break; case CONV_WRITTEN: { int *p = va_arg(ap,int*); *p = written; } break; } } return written;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -