Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Integer vsnprintf, et. al.
- *
- * Copyright (C) 2018 MURAMATSU Atsushi <amura@tomato.sakura.ne.jp>
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- /*
- * integer vsnprintf, et. al. based on BDS C v1.6 library (PDS)
- *
- * This code provides
- * sprintf family:
- * my_vsnprintf, my_snprintf, my_vsprintf, my_sprintf,
- * and
- * fprintf family (if defined WITH_FILEIO macro):
- * my_vfprintf, my_fprintf, my_vprintf, my_printf
- *
- * Supported flags:
- * '0': zero padding
- * '-': left adgust
- * '+': always show sign
- * ' ': space presented when value is positive
- *
- * Supported modifies:
- * 'l': long
- *
- * Supported conversions:
- * 'd', 'i': decimal
- * 'u': unsigned decimal
- * 'o': octal
- * 'x': hexadecimal (lower case)
- * 'X': hexadecimal (upper case)
- * 'b': binary decimal
- * 'c': charactor
- * 's': string
- * '%' and others: non-converted
- */
- /*
- STDLIB2.C -- for BDS C v1.6 -- 1/86
- Copyright (c) 1982, 1986 by BD Software, Inc.
- The files STDLIB1.C, STDLIB2.C and STDLIB3.C contain the source
- listings for all functions present in the DEFF.CRL library object
- file. (Note: DEFF2.CRL contains the .CSM-coded portions of the
- library.)
- STDLIB2.C contains mainly formatted text I/O functions:
- printf fprintf sprintf lprintf _spr
- scanf fscanf sscanf _scn
- getline puts
- putdec
- */
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <limits.h>
- /*** PROTOTYPES ****/
- /* #ifndef MY_VSPRINTF_H */
- /* #define MY_VSPRINTF_H */
- /* #define WITH_FILEIO 1 */
- #include <stdarg.h>
- int my_vsnprintf(char *buffer, int n, const char *format, va_list va);
- int my_snprintf(char *buffer, int n, const char *format, ...);
- int my_vsprintf(char *buffer, const char *format, va_list va);
- int my_sprintf(char *buffer, const char *format, ...);
- #ifdef WITH_FILEIO
- #include <stdio.h>
- int my_vfprintf(FILE *out, const char *format, va_list va);
- int my_fprintf(FILE *out, const char *format, ...);
- int my_vprintf(const char *format, va_list va);
- int my_printf(const char *format, ...);
- #endif /* WITH_FILEIO */
- /* #endif */ /* MY_VSPRINTF_H */
- /*** END OF PROTOTYPES ****/
- typedef enum { OK, ERROR } _result_t;
- static int _spr(const char *format, va_list va,
- _result_t (*putcf)(char, void *), void *arg);
- struct bufdata {
- char *bufptr;
- char *endbufptr;
- };
- static _result_t
- _mem_writer(char c, void *arg)
- {
- struct bufdata *data = (struct bufdata *)arg;
- if (data->endbufptr && data->bufptr >= data->endbufptr)
- return ERROR;
- *(data->bufptr++) = c;
- return OK;
- }
- int
- my_vsnprintf(char *buffer, int n, const char *format, va_list va)
- {
- int s;
- struct bufdata data;
- if (n == 0) return 0;
- data.bufptr = buffer;
- data.endbufptr = buffer + n;
- _spr(format, va, &_mem_writer, &data);
- s = data.bufptr - buffer;
- _mem_writer('\0', &data);
- buffer[n-1] = '\0';
- return s;
- }
- int
- my_vsprintf(char *buffer, const char *format, va_list va)
- {
- int s;
- struct bufdata data;
- data.bufptr = buffer;
- data.endbufptr = NULL;
- _spr(format, va, &_mem_writer, &data);
- s = data.bufptr - buffer;
- _mem_writer('\0', &data);
- return s;
- }
- int
- my_snprintf(char *buffer, int n, const char *format, ...)
- {
- int s;
- va_list va;
- va_start(va, format);
- s = my_vsnprintf(buffer, n, format, va);
- va_end(va);
- return s;
- }
- int
- my_sprintf(char *buffer, const char *format, ...)
- {
- int s;
- va_list va;
- va_start(va, format);
- s = my_vsprintf(buffer, format, va);
- va_end(va);
- return s;
- }
- #ifdef WITH_FILEIO
- struct filedata {
- FILE *outfile;
- int outcount;
- };
- static _result_t
- _file_writer(char c, void *arg)
- {
- struct filedata *data = (struct filedata *)arg;
- if (fputc(c, data->outfile) == EOF)
- return ERROR;
- data->outcount++;
- return OK;
- }
- int
- my_vfprintf(FILE *out, const char *format, va_list va)
- {
- struct filedata data;
- data.outfile = out;
- data.outcount = 0;
- _spr(format, va, &_file_writer, &data);
- return data.outcount;
- }
- int
- my_fprintf(FILE *out, const char *format, ...)
- {
- int s;
- va_list va;
- va_start(va, format);
- s = my_vfprintf(out, format, va);
- va_end(va);
- return s;
- }
- int
- my_vprintf(const char *format, va_list va)
- {
- return my_vfprintf(stdout, format, va);
- }
- int
- my_printf(const char *format, ...)
- {
- int s;
- va_list va;
- va_start(va, format);
- s = my_vprintf(format, va);
- va_end(va);
- return s;
- }
- #endif /* WITH_FILEIO */
- /*
- Internal routine used by "_spr" to perform ascii-
- to-decimal conversion and update an associated pointer:
- */
- static int
- _gv2(const char **sptr)
- {
- int n;
- n = 0;
- while (isdigit(**sptr))
- n = 10*n + *(*sptr)++ - '0';
- return n;
- }
- static char
- _uspr(char **string, unsigned long n, unsigned base, int upperflag)
- {
- int length;
- if (n < base) {
- *(*string)++ = (n < 10) ? n + '0'
- : (upperflag ? (n + 'A' - 10) : (n + 'a' - 10));
- return 1;
- }
- length = _uspr(string, n / base, base, upperflag);
- _uspr(string, n % base, base, upperflag);
- return length + 1;
- }
- static int
- _spr(const char *format, va_list va, _result_t (*putcf)(char, void*), void *arg)
- {
- char c, prefill, *wptr, sign;
- long value;
- int ljflag, upperflag, longflag;
- int base = 10;
- char wbuf[128]; /* 128 is enough for all but %s */
- int length, *args, width, precision;
- while ((c = *format++)) {
- if (c == '%') {
- wptr = wbuf;
- precision = INT_MAX;
- width = ljflag = upperflag = longflag = 0;
- prefill = ' ';
- sign = '\0';
- while (1) {
- if (*format == '-')
- ljflag = 1;
- else if (*format == '0')
- prefill = '0';
- else if (*format == ' ')
- sign = ' ';
- else if (*format == '+')
- sign = '+';
- else
- break;
- format++;
- }
- if (*format == '*') {
- format++;
- width = va_arg(va, int);
- }
- else if (isdigit(*format))
- width = _gv2(&format);
- if (*format == '.') {
- format++;
- if (*format == '*') {
- format++;
- precision = va_arg(va, int);
- }
- else {
- precision = _gv2(&format);
- }
- }
- if (*format == 'l') {
- format++;
- longflag = 1;
- }
- switch (c = *format++) {
- case 'd':
- case 'i':
- {
- long value;
- if (longflag)
- value = va_arg(va, long);
- else
- value = va_arg(va, int);
- if (value < 0) {
- *wptr++ = '-';
- value = -value;
- width--;
- }
- else if (sign != '\0') {
- *wptr++ = sign;
- width--;
- }
- width -= _uspr(&wptr, value, base, 0);
- }
- goto pad;
- case 'u':
- base = 10; goto val;
- case 'b':
- base = 2; goto val;
- case 'x':
- base = 16; goto val;
- case 'X':
- base = 16; upperflag = 1; goto val;
- case 'o':
- base = 8;
- val:
- if (longflag)
- width -= _uspr(&wptr, va_arg(va, unsigned long),
- base, upperflag);
- else
- width -= _uspr(&wptr, va_arg(va, unsigned),
- base, upperflag);
- goto pad;
- case 'c':
- *wptr++ = va_arg(va, int) & 0xff;
- width--;
- goto pad;
- pad:
- *wptr = '\0';
- length = strlen(wptr = wbuf);
- pad7: /* don't modify the string at wptr */
- if (!ljflag) {
- while (width-- > 0)
- if (putcf(prefill, arg) == ERROR)
- return ERROR;
- }
- while (length--) {
- if (putcf(*wptr++, arg) == ERROR)
- return ERROR;
- }
- if (ljflag) {
- while (width-- > 0)
- if (putcf(' ', arg) == ERROR)
- return ERROR;
- }
- break;
- case 's':
- wptr = va_arg(va, char *);
- length = strlen(wptr);
- if (precision < length)
- length = precision;
- width -= length;
- goto pad7;
- case '\0':
- return OK;
- default:
- if (putcf(c, arg) == ERROR)
- return ERROR;
- }
- }
- else if (putcf(c, arg) == ERROR)
- return ERROR;
- }
- return OK;
- }
- #ifdef DEBUG
- #include <stdio.h>
- void
- test(const char *name, const char *format, ...)
- {
- char buf1[1024], buf2[1024];
- int s1, s2;
- va_list va1, va2;
- va_start(va1, format);
- va_copy(va2, va1);
- s1 = vsprintf(buf1, format, va1);
- s2 = my_vsprintf(buf2, format, va2);
- va_end(va1);
- va_end(va2);
- if (strcmp(buf1, buf2) != 0)
- printf("ERR!:: %s:%s:%s\n", name, buf1, buf2);
- if (s1 != s2)
- printf("ERR!:: %s: %d != %d\n", name, s1, s2);
- /* printf("(%d)%s\n", s1, buf1); */
- }
- int
- main()
- {
- test("test1", "testdata, %d, %10d", 10, 200);
- test("test2", "testdata, %s, %10.10s", "dfadf,", "xxxxxxxxxxxxx");
- test("test3", "testdata, %x, %10X", 10, 200);
- test("test4", "testdata, %X, %10x", 10, 200);
- test("test5", "testdata, %ld, %10ld", 1100000000L, 2000000000000L);
- test("test6", "testdata, %+d, %+10d", -10, 200);
- test("test7", "testdata, %+x, %+o", 10, 200);
- test("test8", "testdata, %03x, %04o", 10, 200);
- test("test9", "testdata, % 2d, % 3x", 10, 200);
- return 0;
- }
- #endif
Add Comment
Please, Sign In to add comment