📄 mysnprintf.c
字号:
/************************************************************** * Original: * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 * A bombproof version of doprnt (dopr) included. * Sigh. This sort of thing is always nasty do deal with. Note that * the version here does not include floating point... * * snprintf() is used instead of sprintf() as it does limit checks * for string length. This covers a nasty loophole. * * The other functions are there to prevent NULL pointers from * causing nast effects. * * More Recently: * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43 * This was ugly. It is still ugly. I opted out of floating point * numbers, but the formatter understands just about everything * from the normal C string format, at least as far as I can tell from * the Solaris 2.5 printf(3S) man page. * * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1 * Ok, added some minimal floating point support, which means this * probably requires libm on most operating systems. Don't yet * support the exponent (e,E) and sigfig (g,G). Also, fmtint() * was pretty badly broken, it just wasn't being exercised in ways * which showed it, so that's been fixed. Also, formated the code * to mutt conventions, and removed dead code left over from the * original. Also, there is now a builtin-test, just compile with: * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm * and run snprintf for results. * * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i * The PGP code was using unsigned hexadecimal formats. * Unfortunately, unsigned formats simply didn't work. * * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8 * The original code assumed that both snprintf() and vsnprintf() were * missing. Some systems only have snprintf() but not vsnprintf(), so * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. * **************************************************************/#include "config.h"#include <string.h>#include <ctype.h>#include <sys/types.h>#include <math.h>#ifdef _WIN32#include <io.h>#include <stdio.h>#include <windows.h>#else#include <unistd.h>#endif/* varargs declarations: */#if defined(HAVE_STDARG_H)# include <stdarg.h># define HAVE_STDARGS /* let's hope that works everywhere (mj) */# define VA_LOCAL_DECL va_list ap# define VA_START(f) va_start(ap, f)# define VA_SHIFT(v,t) ; /* no-op for ANSI */# define VA_END va_end(ap)#else# if defined(HAVE_VARARGS_H)# include <varargs.h># undef HAVE_STDARGS# define VA_LOCAL_DECL va_list ap# define VA_START(f) va_start(ap) /* f is ignored! */# define VA_SHIFT(v,t) v = va_arg(ap,t)# define VA_END va_end(ap)# else/*XX ** NO VARARGS ** XX*/# error no either stdarg or varargs needed# endif#endifstatic void dopr (char *buffer, size_t maxlen, const char *format, va_list args);static void fmtstr (char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, int min, int max);static void fmtint (char *buffer, size_t *currlen, size_t maxlen, long value, int base, int min, int max, int flags);static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, long double fvalue, int min, int max, int flags);static void fmtefp (char *buffer, size_t *currlen, size_t maxlen, long double fvalue, int min, int max, int flags);static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );/* * myisdigit(): signalhandlerparanoia isdigit version independend of C-Library */static int myisdigit(int c) { switch(c) { case '0': return 1; case '1': return 1; case '2': return 1; case '3': return 1; case '4': return 1; case '5': return 1; case '6': return 1; case '7': return 1; case '8': return 1; case '9': return 1; default: return 0; } }/* * mystrlen(): signalhandlerparanoia strlen version independend of C-Library */size_t mystrlen (const char *s) { int strln; for (strln = 0; s[strln]; ++strln); return strln; }/* * mystrcpy(): signalhandlerparanoia strcpy version independend of C-Library */char *mystrcpy(char *s1, const char *s2) { int strln; for (strln = 0; s2[strln]; ++strln) s1[strln]=s2[strln]; s1[strln]=0; return s1; }/* * mystrcat(): signalhandlerparanoia strcpy version independend of C-Library */char *mystrcat(char *s1, const char *s2) { int strln; int length=mystrlen(s1); for (strln = 0; s2[strln]; ++strln) s1[length+strln]=s2[strln]; s1[length+strln]=0; return s1; }/* * dopr(): poor man's version of doprintf *//* format read states */#define DP_S_DEFAULT 0#define DP_S_FLAGS 1#define DP_S_MIN 2#define DP_S_DOT 3#define DP_S_MAX 4#define DP_S_MOD 5#define DP_S_CONV 6#define DP_S_DONE 7/* format flags - Bits */#define DP_F_MINUS (1 << 0)#define DP_F_PLUS (1 << 1)#define DP_F_SPACE (1 << 2)#define DP_F_NUM (1 << 3)#define DP_F_ZERO (1 << 4)#define DP_F_UP (1 << 5)#define DP_F_UNSIGNED (1 << 6)/* Conversion Flags */#define DP_C_SHORT 1#define DP_C_LONG 2#define DP_C_LDOUBLE 3#define char_to_int(p) (p - '0')#ifndef MAX# define MAX(p,q) ((p >= q) ? p : q)#endifstatic void dopr (char *buffer, size_t maxlen, const char *format, va_list args){ char ch; long value; long double fvalue; char *strvalue; int min; int max; int state; int flags; int cflags; size_t currlen; state = DP_S_DEFAULT; currlen = flags = cflags = min = 0; max = -1; ch = *format++; while (state != DP_S_DONE) { if ((ch == '\0') || (currlen >= maxlen)) state = DP_S_DONE; switch(state) { case DP_S_DEFAULT: if (ch == '%') state = DP_S_FLAGS; else dopr_outch (buffer, &currlen, maxlen, ch); ch = *format++; break; case DP_S_FLAGS: switch (ch) { case '-': flags |= DP_F_MINUS; ch = *format++; break; case '+': flags |= DP_F_PLUS; ch = *format++; break; case ' ': flags |= DP_F_SPACE; ch = *format++; break; case '#': flags |= DP_F_NUM; ch = *format++; break; case '0': flags |= DP_F_ZERO; ch = *format++; break; default: state = DP_S_MIN; break; } break; case DP_S_MIN: if (myisdigit((unsigned char)ch)) { min = 10*min + char_to_int (ch); ch = *format++; } else if (ch == '*') { min = va_arg (args, int); ch = *format++; state = DP_S_DOT; } else state = DP_S_DOT; break; case DP_S_DOT: if (ch == '.') { state = DP_S_MAX; ch = *format++; } else state = DP_S_MOD; break; case DP_S_MAX: if (myisdigit((unsigned char)ch)) { if (max < 0) max = 0; max = 10*max + char_to_int (ch); ch = *format++; } else if (ch == '*') { max = va_arg (args, int); ch = *format++; state = DP_S_MOD; } else state = DP_S_MOD; break; case DP_S_MOD: /* Currently, we don't support Long Long, bummer */ switch (ch) { case 'h': cflags = DP_C_SHORT; ch = *format++; break; case 'l': cflags = DP_C_LONG; ch = *format++; break; case 'L': cflags = DP_C_LDOUBLE; ch = *format++; break; default: break; } state = DP_S_CONV; break; case DP_S_CONV: switch (ch) { case 'd': case 'i': if (cflags == DP_C_SHORT) value =(short int) va_arg (args, int); else if (cflags == DP_C_LONG) value = va_arg (args, long int); else value = va_arg (args, int); fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); break; case 'o': flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) value = (unsigned short int) va_arg (args, int); else if (cflags == DP_C_LONG) value = va_arg (args, unsigned long int); else value = va_arg (args, unsigned int); fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); break; case 'u': flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) value = (unsigned short int) va_arg (args, int); else if (cflags == DP_C_LONG) value = va_arg (args, unsigned long int); else value = va_arg (args, unsigned int); fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); break; case 'X': flags |= DP_F_UP; case 'x': flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) value = (unsigned short int) va_arg (args, int); else if (cflags == DP_C_LONG) value = va_arg (args, unsigned long int); else value = va_arg (args, unsigned int); fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags); break; case 'f': if (cflags == DP_C_LDOUBLE) fvalue = va_arg (args, long double); else fvalue = va_arg (args, double); /* um, floating point? */ fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); break; case 'E': flags |= DP_F_UP; case 'e': if (cflags == DP_C_LDOUBLE) fvalue = va_arg (args, long double); else fvalue = va_arg (args, double); /* um, floating point? */ fmtefp (buffer, &currlen, maxlen, fvalue, min, max, flags); break; case 'G': flags |= DP_F_UP; case 'g': if (cflags == DP_C_LDOUBLE) fvalue = va_arg (args, long double); else fvalue = va_arg (args, double); /* um, floating point? */ fmtefp (buffer, &currlen, maxlen, fvalue, min, max, flags); break; case 'c': dopr_outch (buffer, &currlen, maxlen, va_arg (args, int)); break; case 's': strvalue = va_arg (args, char *); if (max < 0) max = maxlen; /* ie, no max */ fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max); break; case 'p': strvalue = va_arg (args, void *); fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); break; case 'n': if (cflags == DP_C_SHORT) { short int *num; num = va_arg (args, short int *); *num = currlen; } else if (cflags == DP_C_LONG) { long int *num; num = va_arg (args, long int *); *num = currlen; } else { int *num; num = va_arg (args, int *); *num = currlen; } break; case '%': dopr_outch (buffer, &currlen, maxlen, ch); break; case 'w': /* not supported yet, treat as next char */ ch = *format++; break; default: /* Unknown, skip */ break; } ch = *format++; state = DP_S_DEFAULT; flags = cflags = min = 0; max = -1; break; case DP_S_DONE: break; default: /* hmm? */ break; /* some picky compilers need this */ } } if (currlen < maxlen - 1) buffer[currlen] = '\0'; else buffer[maxlen - 1] = '\0';}static void fmtstr (char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, int min, int max){ int padlen, strln; /* amount to pad */ int cnt = 0; if (value == 0) { value = "<NULL>"; } for (strln = 0; value[strln]; ++strln); /* strlen */ padlen = min - strln; if (padlen < 0) padlen = 0; if (flags & DP_F_MINUS) padlen = -padlen; /* Left Justify */ while ((padlen > 0) && (cnt < max)) { dopr_outch (buffer, currlen, maxlen, ' '); --padlen; ++cnt; } while (*value && (cnt < max)) { dopr_outch (buffer, currlen, maxlen, *value++); ++cnt; } while ((padlen < 0) && (cnt < max)) { dopr_outch (buffer, currlen, maxlen, ' '); ++padlen; ++cnt; }}/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */static void fmtint (char *buffer, size_t *currlen, size_t maxlen, long value, int base, int min, int max, int flags){ int signvalue = 0; unsigned long uvalue; char convert[20]; int place = 0; int spadlen = 0; /* amount to space pad */ int zpadlen = 0; /* amount to zero pad */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -