117d15b25SDag-Erling Smørgrav /* snprintf - compatibility implementation of snprintf, vsnprintf
217d15b25SDag-Erling Smørgrav *
317d15b25SDag-Erling Smørgrav * Copyright (c) 2013, NLnet Labs. All rights reserved.
417d15b25SDag-Erling Smørgrav *
517d15b25SDag-Erling Smørgrav * This software is open source.
617d15b25SDag-Erling Smørgrav *
717d15b25SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without
817d15b25SDag-Erling Smørgrav * modification, are permitted provided that the following conditions
917d15b25SDag-Erling Smørgrav * are met:
1017d15b25SDag-Erling Smørgrav *
1117d15b25SDag-Erling Smørgrav * Redistributions of source code must retain the above copyright notice,
1217d15b25SDag-Erling Smørgrav * this list of conditions and the following disclaimer.
1317d15b25SDag-Erling Smørgrav *
1417d15b25SDag-Erling Smørgrav * Redistributions in binary form must reproduce the above copyright notice,
1517d15b25SDag-Erling Smørgrav * this list of conditions and the following disclaimer in the documentation
1617d15b25SDag-Erling Smørgrav * and/or other materials provided with the distribution.
1717d15b25SDag-Erling Smørgrav *
1817d15b25SDag-Erling Smørgrav * Neither the name of the NLNET LABS nor the names of its contributors may
1917d15b25SDag-Erling Smørgrav * be used to endorse or promote products derived from this software without
2017d15b25SDag-Erling Smørgrav * specific prior written permission.
2117d15b25SDag-Erling Smørgrav *
2217d15b25SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23*986ba33cSDag-Erling Smørgrav * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24*986ba33cSDag-Erling Smørgrav * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25*986ba33cSDag-Erling Smørgrav * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26*986ba33cSDag-Erling Smørgrav * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27*986ba33cSDag-Erling Smørgrav * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
28*986ba33cSDag-Erling Smørgrav * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29*986ba33cSDag-Erling Smørgrav * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30*986ba33cSDag-Erling Smørgrav * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31*986ba33cSDag-Erling Smørgrav * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32*986ba33cSDag-Erling Smørgrav * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3317d15b25SDag-Erling Smørgrav */
3417d15b25SDag-Erling Smørgrav
357b5038d7SDag-Erling Smørgrav #include <ldns/config.h>
3617d15b25SDag-Erling Smørgrav #include <stdio.h>
377b5038d7SDag-Erling Smørgrav #include <ctype.h>
3817d15b25SDag-Erling Smørgrav #include <string.h>
397b5038d7SDag-Erling Smørgrav #include <stdarg.h>
4017d15b25SDag-Erling Smørgrav #include <stdlib.h>
4117d15b25SDag-Erling Smørgrav #include <errno.h>
4217d15b25SDag-Erling Smørgrav #ifdef HAVE_STDINT_H
4317d15b25SDag-Erling Smørgrav #include <stdint.h>
447b5038d7SDag-Erling Smørgrav #endif
457b5038d7SDag-Erling Smørgrav
4617d15b25SDag-Erling Smørgrav /* for test */
4717d15b25SDag-Erling Smørgrav /* #define SNPRINTF_TEST 1 */
4817d15b25SDag-Erling Smørgrav #ifdef SNPRINTF_TEST
4917d15b25SDag-Erling Smørgrav #define snprintf my_snprintf
5017d15b25SDag-Erling Smørgrav #define vsnprintf my_vsnprintf
517b5038d7SDag-Erling Smørgrav #endif /* SNPRINTF_TEST */
527b5038d7SDag-Erling Smørgrav
5317d15b25SDag-Erling Smørgrav int snprintf(char* str, size_t size, const char* format, ...);
5417d15b25SDag-Erling Smørgrav int vsnprintf(char* str, size_t size, const char* format, va_list arg);
5517d15b25SDag-Erling Smørgrav
5617d15b25SDag-Erling Smørgrav /**
5717d15b25SDag-Erling Smørgrav * Very portable snprintf implementation, limited in functionality,
5817d15b25SDag-Erling Smørgrav * esp. for %[capital] %[nonportable] and so on. Reduced float functionality,
5917d15b25SDag-Erling Smørgrav * mostly in formatting and range (e+-16), for %f and %g.
6017d15b25SDag-Erling Smørgrav *
6117d15b25SDag-Erling Smørgrav * %s, %d, %u, %i, %x, %c, %n and %% are fully supported.
6217d15b25SDag-Erling Smørgrav * This includes width, precision, flags 0- +, and *(arg for wid,prec).
6317d15b25SDag-Erling Smørgrav * %f, %g, %m, %p have reduced support, support for wid,prec,flags,*, but
6417d15b25SDag-Erling Smørgrav * less floating point range, no %e formatting for %g.
6517d15b25SDag-Erling Smørgrav */
snprintf(char * str,size_t size,const char * format,...)6617d15b25SDag-Erling Smørgrav int snprintf(char* str, size_t size, const char* format, ...)
6717d15b25SDag-Erling Smørgrav {
6817d15b25SDag-Erling Smørgrav int r;
6917d15b25SDag-Erling Smørgrav va_list args;
7017d15b25SDag-Erling Smørgrav va_start(args, format);
7117d15b25SDag-Erling Smørgrav r = vsnprintf(str, size, format, args);
7217d15b25SDag-Erling Smørgrav va_end(args);
7317d15b25SDag-Erling Smørgrav return r;
7417d15b25SDag-Erling Smørgrav }
7517d15b25SDag-Erling Smørgrav
7617d15b25SDag-Erling Smørgrav /** add padding to string */
7717d15b25SDag-Erling Smørgrav static void
print_pad(char ** at,size_t * left,int * ret,char p,int num)7817d15b25SDag-Erling Smørgrav print_pad(char** at, size_t* left, int* ret, char p, int num)
7917d15b25SDag-Erling Smørgrav {
8017d15b25SDag-Erling Smørgrav while(num--) {
8117d15b25SDag-Erling Smørgrav if(*left > 1) {
8217d15b25SDag-Erling Smørgrav *(*at)++ = p;
8317d15b25SDag-Erling Smørgrav (*left)--;
8417d15b25SDag-Erling Smørgrav }
8517d15b25SDag-Erling Smørgrav (*ret)++;
8617d15b25SDag-Erling Smørgrav }
8717d15b25SDag-Erling Smørgrav }
8817d15b25SDag-Erling Smørgrav
8917d15b25SDag-Erling Smørgrav /** get negative symbol, 0 if none */
9017d15b25SDag-Erling Smørgrav static char
get_negsign(int negative,int plus,int space)9117d15b25SDag-Erling Smørgrav get_negsign(int negative, int plus, int space)
9217d15b25SDag-Erling Smørgrav {
9317d15b25SDag-Erling Smørgrav if(negative)
9417d15b25SDag-Erling Smørgrav return '-';
9517d15b25SDag-Erling Smørgrav if(plus)
9617d15b25SDag-Erling Smørgrav return '+';
9717d15b25SDag-Erling Smørgrav if(space)
9817d15b25SDag-Erling Smørgrav return ' ';
9917d15b25SDag-Erling Smørgrav return 0;
10017d15b25SDag-Erling Smørgrav }
10117d15b25SDag-Erling Smørgrav
10217d15b25SDag-Erling Smørgrav #define PRINT_DEC_BUFSZ 32 /* 20 is enough for 64 bit decimals */
10317d15b25SDag-Erling Smørgrav /** print decimal into buffer, returns length */
10417d15b25SDag-Erling Smørgrav static int
print_dec(char * buf,int max,unsigned int value)10517d15b25SDag-Erling Smørgrav print_dec(char* buf, int max, unsigned int value)
10617d15b25SDag-Erling Smørgrav {
10717d15b25SDag-Erling Smørgrav int i = 0;
10817d15b25SDag-Erling Smørgrav if(value == 0) {
10917d15b25SDag-Erling Smørgrav if(max > 0) {
11017d15b25SDag-Erling Smørgrav buf[0] = '0';
11117d15b25SDag-Erling Smørgrav i = 1;
11217d15b25SDag-Erling Smørgrav }
11317d15b25SDag-Erling Smørgrav } else while(value && i < max) {
11417d15b25SDag-Erling Smørgrav buf[i++] = '0' + value % 10;
11517d15b25SDag-Erling Smørgrav value /= 10;
11617d15b25SDag-Erling Smørgrav }
11717d15b25SDag-Erling Smørgrav return i;
11817d15b25SDag-Erling Smørgrav }
11917d15b25SDag-Erling Smørgrav
12017d15b25SDag-Erling Smørgrav /** print long decimal into buffer, returns length */
12117d15b25SDag-Erling Smørgrav static int
print_dec_l(char * buf,int max,unsigned long value)12217d15b25SDag-Erling Smørgrav print_dec_l(char* buf, int max, unsigned long value)
12317d15b25SDag-Erling Smørgrav {
12417d15b25SDag-Erling Smørgrav int i = 0;
12517d15b25SDag-Erling Smørgrav if(value == 0) {
12617d15b25SDag-Erling Smørgrav if(max > 0) {
12717d15b25SDag-Erling Smørgrav buf[0] = '0';
12817d15b25SDag-Erling Smørgrav i = 1;
12917d15b25SDag-Erling Smørgrav }
13017d15b25SDag-Erling Smørgrav } else while(value && i < max) {
13117d15b25SDag-Erling Smørgrav buf[i++] = '0' + value % 10;
13217d15b25SDag-Erling Smørgrav value /= 10;
13317d15b25SDag-Erling Smørgrav }
13417d15b25SDag-Erling Smørgrav return i;
13517d15b25SDag-Erling Smørgrav }
13617d15b25SDag-Erling Smørgrav
13717d15b25SDag-Erling Smørgrav /** print long decimal into buffer, returns length */
13817d15b25SDag-Erling Smørgrav static int
print_dec_ll(char * buf,int max,unsigned long long value)13917d15b25SDag-Erling Smørgrav print_dec_ll(char* buf, int max, unsigned long long value)
14017d15b25SDag-Erling Smørgrav {
14117d15b25SDag-Erling Smørgrav int i = 0;
14217d15b25SDag-Erling Smørgrav if(value == 0) {
14317d15b25SDag-Erling Smørgrav if(max > 0) {
14417d15b25SDag-Erling Smørgrav buf[0] = '0';
14517d15b25SDag-Erling Smørgrav i = 1;
14617d15b25SDag-Erling Smørgrav }
14717d15b25SDag-Erling Smørgrav } else while(value && i < max) {
14817d15b25SDag-Erling Smørgrav buf[i++] = '0' + value % 10;
14917d15b25SDag-Erling Smørgrav value /= 10;
15017d15b25SDag-Erling Smørgrav }
15117d15b25SDag-Erling Smørgrav return i;
15217d15b25SDag-Erling Smørgrav }
15317d15b25SDag-Erling Smørgrav
15417d15b25SDag-Erling Smørgrav /** print hex into buffer, returns length */
15517d15b25SDag-Erling Smørgrav static int
print_hex(char * buf,int max,unsigned int value)15617d15b25SDag-Erling Smørgrav print_hex(char* buf, int max, unsigned int value)
15717d15b25SDag-Erling Smørgrav {
15817d15b25SDag-Erling Smørgrav const char* h = "0123456789abcdef";
15917d15b25SDag-Erling Smørgrav int i = 0;
16017d15b25SDag-Erling Smørgrav if(value == 0) {
16117d15b25SDag-Erling Smørgrav if(max > 0) {
16217d15b25SDag-Erling Smørgrav buf[0] = '0';
16317d15b25SDag-Erling Smørgrav i = 1;
16417d15b25SDag-Erling Smørgrav }
16517d15b25SDag-Erling Smørgrav } else while(value && i < max) {
16617d15b25SDag-Erling Smørgrav buf[i++] = h[value & 0x0f];
16717d15b25SDag-Erling Smørgrav value >>= 4;
16817d15b25SDag-Erling Smørgrav }
16917d15b25SDag-Erling Smørgrav return i;
17017d15b25SDag-Erling Smørgrav }
17117d15b25SDag-Erling Smørgrav
17217d15b25SDag-Erling Smørgrav /** print long hex into buffer, returns length */
17317d15b25SDag-Erling Smørgrav static int
print_hex_l(char * buf,int max,unsigned long value)17417d15b25SDag-Erling Smørgrav print_hex_l(char* buf, int max, unsigned long value)
17517d15b25SDag-Erling Smørgrav {
17617d15b25SDag-Erling Smørgrav const char* h = "0123456789abcdef";
17717d15b25SDag-Erling Smørgrav int i = 0;
17817d15b25SDag-Erling Smørgrav if(value == 0) {
17917d15b25SDag-Erling Smørgrav if(max > 0) {
18017d15b25SDag-Erling Smørgrav buf[0] = '0';
18117d15b25SDag-Erling Smørgrav i = 1;
18217d15b25SDag-Erling Smørgrav }
18317d15b25SDag-Erling Smørgrav } else while(value && i < max) {
18417d15b25SDag-Erling Smørgrav buf[i++] = h[value & 0x0f];
18517d15b25SDag-Erling Smørgrav value >>= 4;
18617d15b25SDag-Erling Smørgrav }
18717d15b25SDag-Erling Smørgrav return i;
18817d15b25SDag-Erling Smørgrav }
18917d15b25SDag-Erling Smørgrav
19017d15b25SDag-Erling Smørgrav /** print long long hex into buffer, returns length */
19117d15b25SDag-Erling Smørgrav static int
print_hex_ll(char * buf,int max,unsigned long long value)19217d15b25SDag-Erling Smørgrav print_hex_ll(char* buf, int max, unsigned long long value)
19317d15b25SDag-Erling Smørgrav {
19417d15b25SDag-Erling Smørgrav const char* h = "0123456789abcdef";
19517d15b25SDag-Erling Smørgrav int i = 0;
19617d15b25SDag-Erling Smørgrav if(value == 0) {
19717d15b25SDag-Erling Smørgrav if(max > 0) {
19817d15b25SDag-Erling Smørgrav buf[0] = '0';
19917d15b25SDag-Erling Smørgrav i = 1;
20017d15b25SDag-Erling Smørgrav }
20117d15b25SDag-Erling Smørgrav } else while(value && i < max) {
20217d15b25SDag-Erling Smørgrav buf[i++] = h[value & 0x0f];
20317d15b25SDag-Erling Smørgrav value >>= 4;
20417d15b25SDag-Erling Smørgrav }
20517d15b25SDag-Erling Smørgrav return i;
20617d15b25SDag-Erling Smørgrav }
20717d15b25SDag-Erling Smørgrav
20817d15b25SDag-Erling Smørgrav /** copy string into result, reversed */
20917d15b25SDag-Erling Smørgrav static void
spool_str_rev(char ** at,size_t * left,int * ret,const char * buf,int len)21017d15b25SDag-Erling Smørgrav spool_str_rev(char** at, size_t* left, int* ret, const char* buf, int len)
21117d15b25SDag-Erling Smørgrav {
21217d15b25SDag-Erling Smørgrav int i = len;
21317d15b25SDag-Erling Smørgrav while(i) {
21417d15b25SDag-Erling Smørgrav if(*left > 1) {
21517d15b25SDag-Erling Smørgrav *(*at)++ = buf[--i];
21617d15b25SDag-Erling Smørgrav (*left)--;
21717d15b25SDag-Erling Smørgrav } else --i;
21817d15b25SDag-Erling Smørgrav (*ret)++;
21917d15b25SDag-Erling Smørgrav }
22017d15b25SDag-Erling Smørgrav }
22117d15b25SDag-Erling Smørgrav
22217d15b25SDag-Erling Smørgrav /** copy string into result */
22317d15b25SDag-Erling Smørgrav static void
spool_str(char ** at,size_t * left,int * ret,const char * buf,int len)22417d15b25SDag-Erling Smørgrav spool_str(char** at, size_t* left, int* ret, const char* buf, int len)
22517d15b25SDag-Erling Smørgrav {
22617d15b25SDag-Erling Smørgrav int i;
22717d15b25SDag-Erling Smørgrav for(i=0; i<len; i++) {
22817d15b25SDag-Erling Smørgrav if(*left > 1) {
22917d15b25SDag-Erling Smørgrav *(*at)++ = buf[i];
23017d15b25SDag-Erling Smørgrav (*left)--;
23117d15b25SDag-Erling Smørgrav }
23217d15b25SDag-Erling Smørgrav (*ret)++;
23317d15b25SDag-Erling Smørgrav }
23417d15b25SDag-Erling Smørgrav }
23517d15b25SDag-Erling Smørgrav
23617d15b25SDag-Erling Smørgrav /** print number formatted */
23717d15b25SDag-Erling Smørgrav static void
print_num(char ** at,size_t * left,int * ret,int minw,int precision,int prgiven,int zeropad,int minus,int plus,int space,int zero,int negative,char * buf,int len)23817d15b25SDag-Erling Smørgrav print_num(char** at, size_t* left, int* ret, int minw, int precision,
23917d15b25SDag-Erling Smørgrav int prgiven, int zeropad, int minus, int plus, int space,
24017d15b25SDag-Erling Smørgrav int zero, int negative, char* buf, int len)
24117d15b25SDag-Erling Smørgrav {
24217d15b25SDag-Erling Smørgrav int w = len; /* excludes minus sign */
24317d15b25SDag-Erling Smørgrav char s = get_negsign(negative, plus, space);
24417d15b25SDag-Erling Smørgrav if(minus) {
24517d15b25SDag-Erling Smørgrav /* left adjust the number into the field, space padding */
24617d15b25SDag-Erling Smørgrav /* calc numw = [sign][zeroes][number] */
24717d15b25SDag-Erling Smørgrav int numw = w;
24817d15b25SDag-Erling Smørgrav if(precision == 0 && zero) numw = 0;
24917d15b25SDag-Erling Smørgrav if(numw < precision) numw = precision;
25017d15b25SDag-Erling Smørgrav if(s) numw++;
25117d15b25SDag-Erling Smørgrav
25217d15b25SDag-Erling Smørgrav /* sign */
25317d15b25SDag-Erling Smørgrav if(s) print_pad(at, left, ret, s, 1);
25417d15b25SDag-Erling Smørgrav
25517d15b25SDag-Erling Smørgrav /* number */
25617d15b25SDag-Erling Smørgrav if(precision == 0 && zero) {
25717d15b25SDag-Erling Smørgrav /* "" for the number */
25817d15b25SDag-Erling Smørgrav } else {
25917d15b25SDag-Erling Smørgrav if(w < precision)
26017d15b25SDag-Erling Smørgrav print_pad(at, left, ret, '0', precision - w);
26117d15b25SDag-Erling Smørgrav spool_str_rev(at, left, ret, buf, len);
26217d15b25SDag-Erling Smørgrav }
26317d15b25SDag-Erling Smørgrav /* spaces */
26417d15b25SDag-Erling Smørgrav if(numw < minw)
26517d15b25SDag-Erling Smørgrav print_pad(at, left, ret, ' ', minw - numw);
26617d15b25SDag-Erling Smørgrav } else {
26717d15b25SDag-Erling Smørgrav /* pad on the left of the number */
26817d15b25SDag-Erling Smørgrav /* calculate numw has width of [sign][zeroes][number] */
26917d15b25SDag-Erling Smørgrav int numw = w;
27017d15b25SDag-Erling Smørgrav if(precision == 0 && zero) numw = 0;
27117d15b25SDag-Erling Smørgrav if(numw < precision) numw = precision;
27217d15b25SDag-Erling Smørgrav if(!prgiven && zeropad && numw < minw) numw = minw;
27317d15b25SDag-Erling Smørgrav else if(s) numw++;
27417d15b25SDag-Erling Smørgrav
27517d15b25SDag-Erling Smørgrav /* pad with spaces */
27617d15b25SDag-Erling Smørgrav if(numw < minw)
27717d15b25SDag-Erling Smørgrav print_pad(at, left, ret, ' ', minw - numw);
27817d15b25SDag-Erling Smørgrav /* print sign (and one less zeropad if so) */
27917d15b25SDag-Erling Smørgrav if(s) {
28017d15b25SDag-Erling Smørgrav print_pad(at, left, ret, s, 1);
28117d15b25SDag-Erling Smørgrav numw--;
28217d15b25SDag-Erling Smørgrav }
28317d15b25SDag-Erling Smørgrav /* pad with zeroes */
28417d15b25SDag-Erling Smørgrav if(w < numw)
28517d15b25SDag-Erling Smørgrav print_pad(at, left, ret, '0', numw - w);
28617d15b25SDag-Erling Smørgrav if(precision == 0 && zero)
28717d15b25SDag-Erling Smørgrav return;
28817d15b25SDag-Erling Smørgrav /* print the characters for the value */
28917d15b25SDag-Erling Smørgrav spool_str_rev(at, left, ret, buf, len);
29017d15b25SDag-Erling Smørgrav }
29117d15b25SDag-Erling Smørgrav }
29217d15b25SDag-Erling Smørgrav
29317d15b25SDag-Erling Smørgrav /** print %d and %i */
29417d15b25SDag-Erling Smørgrav static void
print_num_d(char ** at,size_t * left,int * ret,int value,int minw,int precision,int prgiven,int zeropad,int minus,int plus,int space)29517d15b25SDag-Erling Smørgrav print_num_d(char** at, size_t* left, int* ret, int value,
29617d15b25SDag-Erling Smørgrav int minw, int precision, int prgiven, int zeropad, int minus,
29717d15b25SDag-Erling Smørgrav int plus, int space)
29817d15b25SDag-Erling Smørgrav {
29917d15b25SDag-Erling Smørgrav char buf[PRINT_DEC_BUFSZ];
30017d15b25SDag-Erling Smørgrav int negative = (value < 0);
30117d15b25SDag-Erling Smørgrav int zero = (value == 0);
30217d15b25SDag-Erling Smørgrav int len = print_dec(buf, (int)sizeof(buf),
30317d15b25SDag-Erling Smørgrav (unsigned int)(negative?-value:value));
30417d15b25SDag-Erling Smørgrav print_num(at, left, ret, minw, precision, prgiven, zeropad, minus,
30517d15b25SDag-Erling Smørgrav plus, space, zero, negative, buf, len);
30617d15b25SDag-Erling Smørgrav }
30717d15b25SDag-Erling Smørgrav
30817d15b25SDag-Erling Smørgrav /** print %ld and %li */
30917d15b25SDag-Erling Smørgrav static void
print_num_ld(char ** at,size_t * left,int * ret,long value,int minw,int precision,int prgiven,int zeropad,int minus,int plus,int space)31017d15b25SDag-Erling Smørgrav print_num_ld(char** at, size_t* left, int* ret, long value,
31117d15b25SDag-Erling Smørgrav int minw, int precision, int prgiven, int zeropad, int minus,
31217d15b25SDag-Erling Smørgrav int plus, int space)
31317d15b25SDag-Erling Smørgrav {
31417d15b25SDag-Erling Smørgrav char buf[PRINT_DEC_BUFSZ];
31517d15b25SDag-Erling Smørgrav int negative = (value < 0);
31617d15b25SDag-Erling Smørgrav int zero = (value == 0);
31717d15b25SDag-Erling Smørgrav int len = print_dec_l(buf, (int)sizeof(buf),
31817d15b25SDag-Erling Smørgrav (unsigned long)(negative?-value:value));
31917d15b25SDag-Erling Smørgrav print_num(at, left, ret, minw, precision, prgiven, zeropad, minus,
32017d15b25SDag-Erling Smørgrav plus, space, zero, negative, buf, len);
32117d15b25SDag-Erling Smørgrav }
32217d15b25SDag-Erling Smørgrav
32317d15b25SDag-Erling Smørgrav /** print %lld and %lli */
32417d15b25SDag-Erling Smørgrav static void
print_num_lld(char ** at,size_t * left,int * ret,long long value,int minw,int precision,int prgiven,int zeropad,int minus,int plus,int space)32517d15b25SDag-Erling Smørgrav print_num_lld(char** at, size_t* left, int* ret, long long value,
32617d15b25SDag-Erling Smørgrav int minw, int precision, int prgiven, int zeropad, int minus,
32717d15b25SDag-Erling Smørgrav int plus, int space)
32817d15b25SDag-Erling Smørgrav {
32917d15b25SDag-Erling Smørgrav char buf[PRINT_DEC_BUFSZ];
33017d15b25SDag-Erling Smørgrav int negative = (value < 0);
33117d15b25SDag-Erling Smørgrav int zero = (value == 0);
33217d15b25SDag-Erling Smørgrav int len = print_dec_ll(buf, (int)sizeof(buf),
33317d15b25SDag-Erling Smørgrav (unsigned long long)(negative?-value:value));
33417d15b25SDag-Erling Smørgrav print_num(at, left, ret, minw, precision, prgiven, zeropad, minus,
33517d15b25SDag-Erling Smørgrav plus, space, zero, negative, buf, len);
33617d15b25SDag-Erling Smørgrav }
33717d15b25SDag-Erling Smørgrav
33817d15b25SDag-Erling Smørgrav /** print %u */
33917d15b25SDag-Erling Smørgrav static void
print_num_u(char ** at,size_t * left,int * ret,unsigned int value,int minw,int precision,int prgiven,int zeropad,int minus,int plus,int space)34017d15b25SDag-Erling Smørgrav print_num_u(char** at, size_t* left, int* ret, unsigned int value,
34117d15b25SDag-Erling Smørgrav int minw, int precision, int prgiven, int zeropad, int minus,
34217d15b25SDag-Erling Smørgrav int plus, int space)
34317d15b25SDag-Erling Smørgrav {
34417d15b25SDag-Erling Smørgrav char buf[PRINT_DEC_BUFSZ];
34517d15b25SDag-Erling Smørgrav int negative = 0;
34617d15b25SDag-Erling Smørgrav int zero = (value == 0);
34717d15b25SDag-Erling Smørgrav int len = print_dec(buf, (int)sizeof(buf), value);
34817d15b25SDag-Erling Smørgrav print_num(at, left, ret, minw, precision, prgiven, zeropad, minus,
34917d15b25SDag-Erling Smørgrav plus, space, zero, negative, buf, len);
35017d15b25SDag-Erling Smørgrav }
35117d15b25SDag-Erling Smørgrav
35217d15b25SDag-Erling Smørgrav /** print %lu */
35317d15b25SDag-Erling Smørgrav static void
print_num_lu(char ** at,size_t * left,int * ret,unsigned long value,int minw,int precision,int prgiven,int zeropad,int minus,int plus,int space)35417d15b25SDag-Erling Smørgrav print_num_lu(char** at, size_t* left, int* ret, unsigned long value,
35517d15b25SDag-Erling Smørgrav int minw, int precision, int prgiven, int zeropad, int minus,
35617d15b25SDag-Erling Smørgrav int plus, int space)
35717d15b25SDag-Erling Smørgrav {
35817d15b25SDag-Erling Smørgrav char buf[PRINT_DEC_BUFSZ];
35917d15b25SDag-Erling Smørgrav int negative = 0;
36017d15b25SDag-Erling Smørgrav int zero = (value == 0);
36117d15b25SDag-Erling Smørgrav int len = print_dec_l(buf, (int)sizeof(buf), value);
36217d15b25SDag-Erling Smørgrav print_num(at, left, ret, minw, precision, prgiven, zeropad, minus,
36317d15b25SDag-Erling Smørgrav plus, space, zero, negative, buf, len);
36417d15b25SDag-Erling Smørgrav }
36517d15b25SDag-Erling Smørgrav
36617d15b25SDag-Erling Smørgrav /** print %llu */
36717d15b25SDag-Erling Smørgrav static void
print_num_llu(char ** at,size_t * left,int * ret,unsigned long long value,int minw,int precision,int prgiven,int zeropad,int minus,int plus,int space)36817d15b25SDag-Erling Smørgrav print_num_llu(char** at, size_t* left, int* ret, unsigned long long value,
36917d15b25SDag-Erling Smørgrav int minw, int precision, int prgiven, int zeropad, int minus,
37017d15b25SDag-Erling Smørgrav int plus, int space)
37117d15b25SDag-Erling Smørgrav {
37217d15b25SDag-Erling Smørgrav char buf[PRINT_DEC_BUFSZ];
37317d15b25SDag-Erling Smørgrav int negative = 0;
37417d15b25SDag-Erling Smørgrav int zero = (value == 0);
37517d15b25SDag-Erling Smørgrav int len = print_dec_ll(buf, (int)sizeof(buf), value);
37617d15b25SDag-Erling Smørgrav print_num(at, left, ret, minw, precision, prgiven, zeropad, minus,
37717d15b25SDag-Erling Smørgrav plus, space, zero, negative, buf, len);
37817d15b25SDag-Erling Smørgrav }
37917d15b25SDag-Erling Smørgrav
38017d15b25SDag-Erling Smørgrav /** print %x */
38117d15b25SDag-Erling Smørgrav static void
print_num_x(char ** at,size_t * left,int * ret,unsigned int value,int minw,int precision,int prgiven,int zeropad,int minus,int plus,int space)38217d15b25SDag-Erling Smørgrav print_num_x(char** at, size_t* left, int* ret, unsigned int value,
38317d15b25SDag-Erling Smørgrav int minw, int precision, int prgiven, int zeropad, int minus,
38417d15b25SDag-Erling Smørgrav int plus, int space)
38517d15b25SDag-Erling Smørgrav {
38617d15b25SDag-Erling Smørgrav char buf[PRINT_DEC_BUFSZ];
38717d15b25SDag-Erling Smørgrav int negative = 0;
38817d15b25SDag-Erling Smørgrav int zero = (value == 0);
38917d15b25SDag-Erling Smørgrav int len = print_hex(buf, (int)sizeof(buf), value);
39017d15b25SDag-Erling Smørgrav print_num(at, left, ret, minw, precision, prgiven, zeropad, minus,
39117d15b25SDag-Erling Smørgrav plus, space, zero, negative, buf, len);
39217d15b25SDag-Erling Smørgrav }
39317d15b25SDag-Erling Smørgrav
39417d15b25SDag-Erling Smørgrav /** print %lx */
39517d15b25SDag-Erling Smørgrav static void
print_num_lx(char ** at,size_t * left,int * ret,unsigned long value,int minw,int precision,int prgiven,int zeropad,int minus,int plus,int space)39617d15b25SDag-Erling Smørgrav print_num_lx(char** at, size_t* left, int* ret, unsigned long value,
39717d15b25SDag-Erling Smørgrav int minw, int precision, int prgiven, int zeropad, int minus,
39817d15b25SDag-Erling Smørgrav int plus, int space)
39917d15b25SDag-Erling Smørgrav {
40017d15b25SDag-Erling Smørgrav char buf[PRINT_DEC_BUFSZ];
40117d15b25SDag-Erling Smørgrav int negative = 0;
40217d15b25SDag-Erling Smørgrav int zero = (value == 0);
40317d15b25SDag-Erling Smørgrav int len = print_hex_l(buf, (int)sizeof(buf), value);
40417d15b25SDag-Erling Smørgrav print_num(at, left, ret, minw, precision, prgiven, zeropad, minus,
40517d15b25SDag-Erling Smørgrav plus, space, zero, negative, buf, len);
40617d15b25SDag-Erling Smørgrav }
40717d15b25SDag-Erling Smørgrav
40817d15b25SDag-Erling Smørgrav /** print %llx */
40917d15b25SDag-Erling Smørgrav static void
print_num_llx(char ** at,size_t * left,int * ret,unsigned long long value,int minw,int precision,int prgiven,int zeropad,int minus,int plus,int space)41017d15b25SDag-Erling Smørgrav print_num_llx(char** at, size_t* left, int* ret, unsigned long long value,
41117d15b25SDag-Erling Smørgrav int minw, int precision, int prgiven, int zeropad, int minus,
41217d15b25SDag-Erling Smørgrav int plus, int space)
41317d15b25SDag-Erling Smørgrav {
41417d15b25SDag-Erling Smørgrav char buf[PRINT_DEC_BUFSZ];
41517d15b25SDag-Erling Smørgrav int negative = 0;
41617d15b25SDag-Erling Smørgrav int zero = (value == 0);
41717d15b25SDag-Erling Smørgrav int len = print_hex_ll(buf, (int)sizeof(buf), value);
41817d15b25SDag-Erling Smørgrav print_num(at, left, ret, minw, precision, prgiven, zeropad, minus,
41917d15b25SDag-Erling Smørgrav plus, space, zero, negative, buf, len);
42017d15b25SDag-Erling Smørgrav }
42117d15b25SDag-Erling Smørgrav
42217d15b25SDag-Erling Smørgrav /** print %llp */
42317d15b25SDag-Erling Smørgrav static void
print_num_llp(char ** at,size_t * left,int * ret,void * value,int minw,int precision,int prgiven,int zeropad,int minus,int plus,int space)42417d15b25SDag-Erling Smørgrav print_num_llp(char** at, size_t* left, int* ret, void* value,
42517d15b25SDag-Erling Smørgrav int minw, int precision, int prgiven, int zeropad, int minus,
42617d15b25SDag-Erling Smørgrav int plus, int space)
42717d15b25SDag-Erling Smørgrav {
42817d15b25SDag-Erling Smørgrav char buf[PRINT_DEC_BUFSZ];
42917d15b25SDag-Erling Smørgrav int negative = 0;
43017d15b25SDag-Erling Smørgrav int zero = (value == 0);
43117d15b25SDag-Erling Smørgrav #if defined(UINTPTR_MAX) && defined(UINT32_MAX) && (UINTPTR_MAX == UINT32_MAX)
43217d15b25SDag-Erling Smørgrav /* avoid warning about upcast on 32bit systems */
43317d15b25SDag-Erling Smørgrav unsigned long long llvalue = (unsigned long)value;
43417d15b25SDag-Erling Smørgrav #else
43517d15b25SDag-Erling Smørgrav unsigned long long llvalue = (unsigned long long)value;
43617d15b25SDag-Erling Smørgrav #endif
43717d15b25SDag-Erling Smørgrav int len = print_hex_ll(buf, (int)sizeof(buf), llvalue);
43817d15b25SDag-Erling Smørgrav if(zero) {
43917d15b25SDag-Erling Smørgrav buf[0]=')';
44017d15b25SDag-Erling Smørgrav buf[1]='l';
44117d15b25SDag-Erling Smørgrav buf[2]='i';
44217d15b25SDag-Erling Smørgrav buf[3]='n';
44317d15b25SDag-Erling Smørgrav buf[4]='(';
44417d15b25SDag-Erling Smørgrav len = 5;
44517d15b25SDag-Erling Smørgrav } else {
44617d15b25SDag-Erling Smørgrav /* put '0x' in front of the (reversed) buffer result */
44717d15b25SDag-Erling Smørgrav if(len < PRINT_DEC_BUFSZ)
44817d15b25SDag-Erling Smørgrav buf[len++] = 'x';
44917d15b25SDag-Erling Smørgrav if(len < PRINT_DEC_BUFSZ)
45017d15b25SDag-Erling Smørgrav buf[len++] = '0';
45117d15b25SDag-Erling Smørgrav }
45217d15b25SDag-Erling Smørgrav print_num(at, left, ret, minw, precision, prgiven, zeropad, minus,
45317d15b25SDag-Erling Smørgrav plus, space, zero, negative, buf, len);
45417d15b25SDag-Erling Smørgrav }
45517d15b25SDag-Erling Smørgrav
45617d15b25SDag-Erling Smørgrav #define PRINT_FLOAT_BUFSZ 64 /* xx.yy with 20.20 about the max */
45717d15b25SDag-Erling Smørgrav /** spool remainder after the decimal point to buffer, in reverse */
45817d15b25SDag-Erling Smørgrav static int
print_remainder(char * buf,int max,double r,int prec)45917d15b25SDag-Erling Smørgrav print_remainder(char* buf, int max, double r, int prec)
46017d15b25SDag-Erling Smørgrav {
46117d15b25SDag-Erling Smørgrav unsigned long long cap = 1;
46217d15b25SDag-Erling Smørgrav unsigned long long value;
46317d15b25SDag-Erling Smørgrav int len, i;
46417d15b25SDag-Erling Smørgrav if(prec > 19) prec = 19; /* max we can do */
46517d15b25SDag-Erling Smørgrav if(max < prec) return 0;
46617d15b25SDag-Erling Smørgrav for(i=0; i<prec; i++) {
46717d15b25SDag-Erling Smørgrav cap *= 10;
46817d15b25SDag-Erling Smørgrav }
46917d15b25SDag-Erling Smørgrav r *= (double)cap;
47017d15b25SDag-Erling Smørgrav value = (unsigned long long)r;
47117d15b25SDag-Erling Smørgrav /* see if we need to round up */
47217d15b25SDag-Erling Smørgrav if(((unsigned long long)((r - (double)value)*10.0)) >= 5) {
47317d15b25SDag-Erling Smørgrav value++;
47417d15b25SDag-Erling Smørgrav /* that might carry to numbers before the comma, if so,
47517d15b25SDag-Erling Smørgrav * just ignore that rounding. failure because 64bitprintout */
47617d15b25SDag-Erling Smørgrav if(value >= cap)
47717d15b25SDag-Erling Smørgrav value = cap-1;
47817d15b25SDag-Erling Smørgrav }
47917d15b25SDag-Erling Smørgrav len = print_dec_ll(buf, max, value);
48017d15b25SDag-Erling Smørgrav while(len < prec) { /* pad with zeroes, e.g. if 0.0012 */
48117d15b25SDag-Erling Smørgrav buf[len++] = '0';
48217d15b25SDag-Erling Smørgrav }
48317d15b25SDag-Erling Smørgrav if(len < max)
48417d15b25SDag-Erling Smørgrav buf[len++] = '.';
48517d15b25SDag-Erling Smørgrav return len;
48617d15b25SDag-Erling Smørgrav }
48717d15b25SDag-Erling Smørgrav
48817d15b25SDag-Erling Smørgrav /** spool floating point to buffer */
48917d15b25SDag-Erling Smørgrav static int
print_float(char * buf,int max,double value,int prec)49017d15b25SDag-Erling Smørgrav print_float(char* buf, int max, double value, int prec)
49117d15b25SDag-Erling Smørgrav {
49217d15b25SDag-Erling Smørgrav /* as xxx.xxx if prec==0, no '.', with prec decimals after . */
49317d15b25SDag-Erling Smørgrav /* no conversion for NAN and INF, because we do not want to require
49417d15b25SDag-Erling Smørgrav linking with -lm. */
49517d15b25SDag-Erling Smørgrav /* Thus, the conversions use 64bit integers to convert the numbers,
49617d15b25SDag-Erling Smørgrav * which makes 19 digits before and after the decimal point the max */
49717d15b25SDag-Erling Smørgrav unsigned long long whole = (unsigned long long)value;
49817d15b25SDag-Erling Smørgrav double remain = value - (double)whole;
49917d15b25SDag-Erling Smørgrav int len = 0;
50017d15b25SDag-Erling Smørgrav if(prec != 0)
50117d15b25SDag-Erling Smørgrav len = print_remainder(buf, max, remain, prec);
50217d15b25SDag-Erling Smørgrav len += print_dec_ll(buf+len, max-len, whole);
50317d15b25SDag-Erling Smørgrav return len;
50417d15b25SDag-Erling Smørgrav }
50517d15b25SDag-Erling Smørgrav
50617d15b25SDag-Erling Smørgrav /** print %f */
50717d15b25SDag-Erling Smørgrav static void
print_num_f(char ** at,size_t * left,int * ret,double value,int minw,int precision,int prgiven,int zeropad,int minus,int plus,int space)50817d15b25SDag-Erling Smørgrav print_num_f(char** at, size_t* left, int* ret, double value,
50917d15b25SDag-Erling Smørgrav int minw, int precision, int prgiven, int zeropad, int minus,
51017d15b25SDag-Erling Smørgrav int plus, int space)
51117d15b25SDag-Erling Smørgrav {
51217d15b25SDag-Erling Smørgrav char buf[PRINT_FLOAT_BUFSZ];
51317d15b25SDag-Erling Smørgrav int negative = (value < 0);
51417d15b25SDag-Erling Smørgrav int zero = 0;
51517d15b25SDag-Erling Smørgrav int len;
51617d15b25SDag-Erling Smørgrav if(!prgiven) precision = 6;
51717d15b25SDag-Erling Smørgrav len = print_float(buf, (int)sizeof(buf), negative?-value:value,
51817d15b25SDag-Erling Smørgrav precision);
51917d15b25SDag-Erling Smørgrav print_num(at, left, ret, minw, 1, 0, zeropad, minus,
52017d15b25SDag-Erling Smørgrav plus, space, zero, negative, buf, len);
52117d15b25SDag-Erling Smørgrav }
52217d15b25SDag-Erling Smørgrav
52317d15b25SDag-Erling Smørgrav /* rudimentary %g support */
52417d15b25SDag-Erling Smørgrav static int
print_float_g(char * buf,int max,double value,int prec)52517d15b25SDag-Erling Smørgrav print_float_g(char* buf, int max, double value, int prec)
52617d15b25SDag-Erling Smørgrav {
52717d15b25SDag-Erling Smørgrav unsigned long long whole = (unsigned long long)value;
52817d15b25SDag-Erling Smørgrav double remain = value - (double)whole;
52917d15b25SDag-Erling Smørgrav int before = 0;
53017d15b25SDag-Erling Smørgrav int len = 0;
53117d15b25SDag-Erling Smørgrav
53217d15b25SDag-Erling Smørgrav /* number of digits before the decimal point */
53317d15b25SDag-Erling Smørgrav while(whole > 0) {
53417d15b25SDag-Erling Smørgrav before++;
53517d15b25SDag-Erling Smørgrav whole /= 10;
53617d15b25SDag-Erling Smørgrav }
53717d15b25SDag-Erling Smørgrav whole = (unsigned long long)value;
53817d15b25SDag-Erling Smørgrav
53917d15b25SDag-Erling Smørgrav if(prec > before && remain != 0.0) {
54017d15b25SDag-Erling Smørgrav /* see if the last decimals are zero, if so, skip them */
54117d15b25SDag-Erling Smørgrav len = print_remainder(buf, max, remain, prec-before);
54217d15b25SDag-Erling Smørgrav while(len > 0 && buf[0]=='0') {
54317d15b25SDag-Erling Smørgrav memmove(buf, buf+1, --len);
54417d15b25SDag-Erling Smørgrav }
54517d15b25SDag-Erling Smørgrav }
54617d15b25SDag-Erling Smørgrav len += print_dec_ll(buf+len, max-len, whole);
54717d15b25SDag-Erling Smørgrav return len;
54817d15b25SDag-Erling Smørgrav }
54917d15b25SDag-Erling Smørgrav
55017d15b25SDag-Erling Smørgrav
55117d15b25SDag-Erling Smørgrav /** print %g */
55217d15b25SDag-Erling Smørgrav static void
print_num_g(char ** at,size_t * left,int * ret,double value,int minw,int precision,int prgiven,int zeropad,int minus,int plus,int space)55317d15b25SDag-Erling Smørgrav print_num_g(char** at, size_t* left, int* ret, double value,
55417d15b25SDag-Erling Smørgrav int minw, int precision, int prgiven, int zeropad, int minus,
55517d15b25SDag-Erling Smørgrav int plus, int space)
55617d15b25SDag-Erling Smørgrav {
55717d15b25SDag-Erling Smørgrav char buf[PRINT_FLOAT_BUFSZ];
55817d15b25SDag-Erling Smørgrav int negative = (value < 0);
55917d15b25SDag-Erling Smørgrav int zero = 0;
56017d15b25SDag-Erling Smørgrav int len;
56117d15b25SDag-Erling Smørgrav if(!prgiven) precision = 6;
56217d15b25SDag-Erling Smørgrav if(precision == 0) precision = 1;
56317d15b25SDag-Erling Smørgrav len = print_float_g(buf, (int)sizeof(buf), negative?-value:value,
56417d15b25SDag-Erling Smørgrav precision);
56517d15b25SDag-Erling Smørgrav print_num(at, left, ret, minw, 1, 0, zeropad, minus,
56617d15b25SDag-Erling Smørgrav plus, space, zero, negative, buf, len);
56717d15b25SDag-Erling Smørgrav }
56817d15b25SDag-Erling Smørgrav
56917d15b25SDag-Erling Smørgrav
57017d15b25SDag-Erling Smørgrav /** strnlen (compat implementation) */
57117d15b25SDag-Erling Smørgrav static int
my_strnlen(const char * s,int max)57217d15b25SDag-Erling Smørgrav my_strnlen(const char* s, int max)
57317d15b25SDag-Erling Smørgrav {
57417d15b25SDag-Erling Smørgrav int i;
57517d15b25SDag-Erling Smørgrav for(i=0; i<max; i++)
57617d15b25SDag-Erling Smørgrav if(s[i]==0)
57717d15b25SDag-Erling Smørgrav return i;
57817d15b25SDag-Erling Smørgrav return max;
57917d15b25SDag-Erling Smørgrav }
58017d15b25SDag-Erling Smørgrav
58117d15b25SDag-Erling Smørgrav /** print %s */
58217d15b25SDag-Erling Smørgrav static void
print_str(char ** at,size_t * left,int * ret,char * s,int minw,int precision,int prgiven,int minus)58317d15b25SDag-Erling Smørgrav print_str(char** at, size_t* left, int* ret, char* s,
58417d15b25SDag-Erling Smørgrav int minw, int precision, int prgiven, int minus)
58517d15b25SDag-Erling Smørgrav {
58617d15b25SDag-Erling Smørgrav int w;
58717d15b25SDag-Erling Smørgrav /* with prec: no more than x characters from this string, stop at 0 */
58817d15b25SDag-Erling Smørgrav if(prgiven)
58917d15b25SDag-Erling Smørgrav w = my_strnlen(s, precision);
59017d15b25SDag-Erling Smørgrav else w = (int)strlen(s); /* up to the nul */
59117d15b25SDag-Erling Smørgrav if(w < minw && !minus)
59217d15b25SDag-Erling Smørgrav print_pad(at, left, ret, ' ', minw - w);
59317d15b25SDag-Erling Smørgrav spool_str(at, left, ret, s, w);
59417d15b25SDag-Erling Smørgrav if(w < minw && minus)
59517d15b25SDag-Erling Smørgrav print_pad(at, left, ret, ' ', minw - w);
59617d15b25SDag-Erling Smørgrav }
59717d15b25SDag-Erling Smørgrav
59817d15b25SDag-Erling Smørgrav /** print %c */
59917d15b25SDag-Erling Smørgrav static void
print_char(char ** at,size_t * left,int * ret,int c,int minw,int minus)60017d15b25SDag-Erling Smørgrav print_char(char** at, size_t* left, int* ret, int c,
60117d15b25SDag-Erling Smørgrav int minw, int minus)
60217d15b25SDag-Erling Smørgrav {
60317d15b25SDag-Erling Smørgrav if(1 < minw && !minus)
60417d15b25SDag-Erling Smørgrav print_pad(at, left, ret, ' ', minw - 1);
60517d15b25SDag-Erling Smørgrav print_pad(at, left, ret, c, 1);
60617d15b25SDag-Erling Smørgrav if(1 < minw && minus)
60717d15b25SDag-Erling Smørgrav print_pad(at, left, ret, ' ', minw - 1);
60817d15b25SDag-Erling Smørgrav }
60917d15b25SDag-Erling Smørgrav
61017d15b25SDag-Erling Smørgrav
61117d15b25SDag-Erling Smørgrav /**
61217d15b25SDag-Erling Smørgrav * Print to string.
61317d15b25SDag-Erling Smørgrav * str: string buffer for result. result will be null terminated.
61417d15b25SDag-Erling Smørgrav * size: size of the buffer. null is put inside buffer.
61517d15b25SDag-Erling Smørgrav * format: printf format string.
61617d15b25SDag-Erling Smørgrav * arg: '...' arguments to print.
61717d15b25SDag-Erling Smørgrav * returns number of characters. a null is printed after this.
61817d15b25SDag-Erling Smørgrav * return number of bytes that would have been written
61917d15b25SDag-Erling Smørgrav * if the buffer had been large enough.
62017d15b25SDag-Erling Smørgrav *
62117d15b25SDag-Erling Smørgrav * supported format specifiers:
62217d15b25SDag-Erling Smørgrav * %s, %u, %d, %x, %i, %f, %g, %c, %p, %n.
62317d15b25SDag-Erling Smørgrav * length: l, ll (for d, u, x).
62417d15b25SDag-Erling Smørgrav * precision: 6.6d (for d, u, x)
62517d15b25SDag-Erling Smørgrav * %f, %g precisions, 0.3f
62617d15b25SDag-Erling Smørgrav * %20s, '.*s'
62717d15b25SDag-Erling Smørgrav * and %%.
62817d15b25SDag-Erling Smørgrav */
vsnprintf(char * str,size_t size,const char * format,va_list arg)62917d15b25SDag-Erling Smørgrav int vsnprintf(char* str, size_t size, const char* format, va_list arg)
63017d15b25SDag-Erling Smørgrav {
63117d15b25SDag-Erling Smørgrav char* at = str;
63217d15b25SDag-Erling Smørgrav size_t left = size;
63317d15b25SDag-Erling Smørgrav int ret = 0;
63417d15b25SDag-Erling Smørgrav const char* fmt = format;
63517d15b25SDag-Erling Smørgrav int conv, minw, precision, prgiven, zeropad, minus, plus, space, length;
63617d15b25SDag-Erling Smørgrav while(*fmt) {
63717d15b25SDag-Erling Smørgrav /* copy string before % */
63817d15b25SDag-Erling Smørgrav while(*fmt && *fmt!='%') {
63917d15b25SDag-Erling Smørgrav if(left > 1) {
64017d15b25SDag-Erling Smørgrav *at++ = *fmt++;
64117d15b25SDag-Erling Smørgrav left--;
64217d15b25SDag-Erling Smørgrav } else fmt++;
64317d15b25SDag-Erling Smørgrav ret++;
64417d15b25SDag-Erling Smørgrav }
64517d15b25SDag-Erling Smørgrav
64617d15b25SDag-Erling Smørgrav /* see if we are at end */
64717d15b25SDag-Erling Smørgrav if(!*fmt) break;
64817d15b25SDag-Erling Smørgrav
64917d15b25SDag-Erling Smørgrav /* fetch next argument % designation from format string */
65017d15b25SDag-Erling Smørgrav fmt++; /* skip the '%' */
65117d15b25SDag-Erling Smørgrav
65217d15b25SDag-Erling Smørgrav /********************************/
65317d15b25SDag-Erling Smørgrav /* get the argument designation */
65417d15b25SDag-Erling Smørgrav /********************************/
65517d15b25SDag-Erling Smørgrav /* we must do this vararg stuff inside this function for
65617d15b25SDag-Erling Smørgrav * portability. Hence, get_designation, and print_designation
65717d15b25SDag-Erling Smørgrav * are not their own functions. */
65817d15b25SDag-Erling Smørgrav
65917d15b25SDag-Erling Smørgrav /* printout designation:
66017d15b25SDag-Erling Smørgrav * conversion specifier: x, d, u, s, c, n, m, p
66117d15b25SDag-Erling Smørgrav * flags: # not supported
66217d15b25SDag-Erling Smørgrav * 0 zeropad (on the left)
66317d15b25SDag-Erling Smørgrav * - left adjust (right by default)
66417d15b25SDag-Erling Smørgrav * ' ' printspace for positive number (in - position).
66517d15b25SDag-Erling Smørgrav * + alwayssign
66617d15b25SDag-Erling Smørgrav * fieldwidth: [1-9][0-9]* minimum field width.
66717d15b25SDag-Erling Smørgrav * if this is * then type int next argument specifies the minwidth.
66817d15b25SDag-Erling Smørgrav * if this is negative, the - flag is set (with positive width).
66917d15b25SDag-Erling Smørgrav * precision: period[digits]*, %.2x.
67017d15b25SDag-Erling Smørgrav * if this is * then type int next argument specifies the precision.
67117d15b25SDag-Erling Smørgrav * just '.' or negative value means precision=0.
67217d15b25SDag-Erling Smørgrav * this is mindigits to print for d, i, u, x
67317d15b25SDag-Erling Smørgrav * this is aftercomma digits for f
67417d15b25SDag-Erling Smørgrav * this is max number significant digits for g
67517d15b25SDag-Erling Smørgrav * maxnumber characters to be printed for s
67617d15b25SDag-Erling Smørgrav * length: 0-none (int), 1-l (long), 2-ll (long long)
67717d15b25SDag-Erling Smørgrav * notsupported: hh (char), h (short), L (long double), q, j, z, t
67817d15b25SDag-Erling Smørgrav * Does not support %m$ and *m$ argument designation as array indices.
67917d15b25SDag-Erling Smørgrav * Does not support %#x
68017d15b25SDag-Erling Smørgrav *
68117d15b25SDag-Erling Smørgrav */
68217d15b25SDag-Erling Smørgrav minw = 0;
68317d15b25SDag-Erling Smørgrav precision = 1;
68417d15b25SDag-Erling Smørgrav prgiven = 0;
68517d15b25SDag-Erling Smørgrav zeropad = 0;
68617d15b25SDag-Erling Smørgrav minus = 0;
68717d15b25SDag-Erling Smørgrav plus = 0;
68817d15b25SDag-Erling Smørgrav space = 0;
68917d15b25SDag-Erling Smørgrav length = 0;
69017d15b25SDag-Erling Smørgrav
69117d15b25SDag-Erling Smørgrav /* get flags in any order */
69217d15b25SDag-Erling Smørgrav for(;;) {
69317d15b25SDag-Erling Smørgrav if(*fmt == '0')
69417d15b25SDag-Erling Smørgrav zeropad = 1;
69517d15b25SDag-Erling Smørgrav else if(*fmt == '-')
69617d15b25SDag-Erling Smørgrav minus = 1;
69717d15b25SDag-Erling Smørgrav else if(*fmt == '+')
69817d15b25SDag-Erling Smørgrav plus = 1;
69917d15b25SDag-Erling Smørgrav else if(*fmt == ' ')
70017d15b25SDag-Erling Smørgrav space = 1;
70117d15b25SDag-Erling Smørgrav else break;
70217d15b25SDag-Erling Smørgrav fmt++;
70317d15b25SDag-Erling Smørgrav }
70417d15b25SDag-Erling Smørgrav
70517d15b25SDag-Erling Smørgrav /* field width */
70617d15b25SDag-Erling Smørgrav if(*fmt == '*') {
70717d15b25SDag-Erling Smørgrav fmt++; /* skip char */
70817d15b25SDag-Erling Smørgrav minw = va_arg(arg, int);
70917d15b25SDag-Erling Smørgrav if(minw < 0) {
71017d15b25SDag-Erling Smørgrav minus = 1;
71117d15b25SDag-Erling Smørgrav minw = -minw;
71217d15b25SDag-Erling Smørgrav }
71317d15b25SDag-Erling Smørgrav } else while(*fmt >= '0' && *fmt <= '9') {
71417d15b25SDag-Erling Smørgrav minw = minw*10 + (*fmt++)-'0';
71517d15b25SDag-Erling Smørgrav }
71617d15b25SDag-Erling Smørgrav
71717d15b25SDag-Erling Smørgrav /* precision */
71817d15b25SDag-Erling Smørgrav if(*fmt == '.') {
71917d15b25SDag-Erling Smørgrav fmt++; /* skip period */
72017d15b25SDag-Erling Smørgrav prgiven = 1;
72117d15b25SDag-Erling Smørgrav precision = 0;
72217d15b25SDag-Erling Smørgrav if(*fmt == '*') {
72317d15b25SDag-Erling Smørgrav fmt++; /* skip char */
72417d15b25SDag-Erling Smørgrav precision = va_arg(arg, int);
72517d15b25SDag-Erling Smørgrav if(precision < 0)
72617d15b25SDag-Erling Smørgrav precision = 0;
72717d15b25SDag-Erling Smørgrav } else while(*fmt >= '0' && *fmt <= '9') {
72817d15b25SDag-Erling Smørgrav precision = precision*10 + (*fmt++)-'0';
72917d15b25SDag-Erling Smørgrav }
73017d15b25SDag-Erling Smørgrav }
73117d15b25SDag-Erling Smørgrav
73217d15b25SDag-Erling Smørgrav /* length */
73317d15b25SDag-Erling Smørgrav if(*fmt == 'l') {
73417d15b25SDag-Erling Smørgrav fmt++; /* skip char */
73517d15b25SDag-Erling Smørgrav length = 1;
73617d15b25SDag-Erling Smørgrav if(*fmt == 'l') {
73717d15b25SDag-Erling Smørgrav fmt++; /* skip char */
73817d15b25SDag-Erling Smørgrav length = 2;
73917d15b25SDag-Erling Smørgrav }
74017d15b25SDag-Erling Smørgrav }
74117d15b25SDag-Erling Smørgrav
74217d15b25SDag-Erling Smørgrav /* get the conversion */
74317d15b25SDag-Erling Smørgrav if(!*fmt) conv = 0;
74417d15b25SDag-Erling Smørgrav else conv = *fmt++;
74517d15b25SDag-Erling Smørgrav
74617d15b25SDag-Erling Smørgrav /***********************************/
74717d15b25SDag-Erling Smørgrav /* print that argument designation */
74817d15b25SDag-Erling Smørgrav /***********************************/
74917d15b25SDag-Erling Smørgrav switch(conv) {
75017d15b25SDag-Erling Smørgrav case 'i':
75117d15b25SDag-Erling Smørgrav case 'd':
75217d15b25SDag-Erling Smørgrav if(length == 0)
75317d15b25SDag-Erling Smørgrav print_num_d(&at, &left, &ret, va_arg(arg, int),
75417d15b25SDag-Erling Smørgrav minw, precision, prgiven, zeropad, minus, plus, space);
75517d15b25SDag-Erling Smørgrav else if(length == 1)
75617d15b25SDag-Erling Smørgrav print_num_ld(&at, &left, &ret, va_arg(arg, long),
75717d15b25SDag-Erling Smørgrav minw, precision, prgiven, zeropad, minus, plus, space);
75817d15b25SDag-Erling Smørgrav else if(length == 2)
75917d15b25SDag-Erling Smørgrav print_num_lld(&at, &left, &ret,
76017d15b25SDag-Erling Smørgrav va_arg(arg, long long),
76117d15b25SDag-Erling Smørgrav minw, precision, prgiven, zeropad, minus, plus, space);
76217d15b25SDag-Erling Smørgrav break;
76317d15b25SDag-Erling Smørgrav case 'u':
76417d15b25SDag-Erling Smørgrav if(length == 0)
76517d15b25SDag-Erling Smørgrav print_num_u(&at, &left, &ret,
76617d15b25SDag-Erling Smørgrav va_arg(arg, unsigned int),
76717d15b25SDag-Erling Smørgrav minw, precision, prgiven, zeropad, minus, plus, space);
76817d15b25SDag-Erling Smørgrav else if(length == 1)
76917d15b25SDag-Erling Smørgrav print_num_lu(&at, &left, &ret,
77017d15b25SDag-Erling Smørgrav va_arg(arg, unsigned long),
77117d15b25SDag-Erling Smørgrav minw, precision, prgiven, zeropad, minus, plus, space);
77217d15b25SDag-Erling Smørgrav else if(length == 2)
77317d15b25SDag-Erling Smørgrav print_num_llu(&at, &left, &ret,
77417d15b25SDag-Erling Smørgrav va_arg(arg, unsigned long long),
77517d15b25SDag-Erling Smørgrav minw, precision, prgiven, zeropad, minus, plus, space);
77617d15b25SDag-Erling Smørgrav break;
77717d15b25SDag-Erling Smørgrav case 'x':
77817d15b25SDag-Erling Smørgrav if(length == 0)
77917d15b25SDag-Erling Smørgrav print_num_x(&at, &left, &ret,
78017d15b25SDag-Erling Smørgrav va_arg(arg, unsigned int),
78117d15b25SDag-Erling Smørgrav minw, precision, prgiven, zeropad, minus, plus, space);
78217d15b25SDag-Erling Smørgrav else if(length == 1)
78317d15b25SDag-Erling Smørgrav print_num_lx(&at, &left, &ret,
78417d15b25SDag-Erling Smørgrav va_arg(arg, unsigned long),
78517d15b25SDag-Erling Smørgrav minw, precision, prgiven, zeropad, minus, plus, space);
78617d15b25SDag-Erling Smørgrav else if(length == 2)
78717d15b25SDag-Erling Smørgrav print_num_llx(&at, &left, &ret,
78817d15b25SDag-Erling Smørgrav va_arg(arg, unsigned long long),
78917d15b25SDag-Erling Smørgrav minw, precision, prgiven, zeropad, minus, plus, space);
79017d15b25SDag-Erling Smørgrav break;
79117d15b25SDag-Erling Smørgrav case 's':
79217d15b25SDag-Erling Smørgrav print_str(&at, &left, &ret, va_arg(arg, char*),
79317d15b25SDag-Erling Smørgrav minw, precision, prgiven, minus);
79417d15b25SDag-Erling Smørgrav break;
79517d15b25SDag-Erling Smørgrav case 'c':
79617d15b25SDag-Erling Smørgrav print_char(&at, &left, &ret, va_arg(arg, int),
79717d15b25SDag-Erling Smørgrav minw, minus);
79817d15b25SDag-Erling Smørgrav break;
79917d15b25SDag-Erling Smørgrav case 'n':
80017d15b25SDag-Erling Smørgrav *va_arg(arg, int*) = ret;
80117d15b25SDag-Erling Smørgrav break;
80217d15b25SDag-Erling Smørgrav case 'm':
80317d15b25SDag-Erling Smørgrav print_str(&at, &left, &ret, strerror(errno),
80417d15b25SDag-Erling Smørgrav minw, precision, prgiven, minus);
80517d15b25SDag-Erling Smørgrav break;
80617d15b25SDag-Erling Smørgrav case 'p':
80717d15b25SDag-Erling Smørgrav print_num_llp(&at, &left, &ret, va_arg(arg, void*),
80817d15b25SDag-Erling Smørgrav minw, precision, prgiven, zeropad, minus, plus, space);
80917d15b25SDag-Erling Smørgrav break;
81017d15b25SDag-Erling Smørgrav case '%':
81117d15b25SDag-Erling Smørgrav print_pad(&at, &left, &ret, '%', 1);
81217d15b25SDag-Erling Smørgrav break;
81317d15b25SDag-Erling Smørgrav case 'f':
81417d15b25SDag-Erling Smørgrav print_num_f(&at, &left, &ret, va_arg(arg, double),
81517d15b25SDag-Erling Smørgrav minw, precision, prgiven, zeropad, minus, plus, space);
81617d15b25SDag-Erling Smørgrav break;
81717d15b25SDag-Erling Smørgrav case 'g':
81817d15b25SDag-Erling Smørgrav print_num_g(&at, &left, &ret, va_arg(arg, double),
81917d15b25SDag-Erling Smørgrav minw, precision, prgiven, zeropad, minus, plus, space);
82017d15b25SDag-Erling Smørgrav break;
82117d15b25SDag-Erling Smørgrav /* unknown */
82217d15b25SDag-Erling Smørgrav default:
82317d15b25SDag-Erling Smørgrav case 0: break;
82417d15b25SDag-Erling Smørgrav }
82517d15b25SDag-Erling Smørgrav }
82617d15b25SDag-Erling Smørgrav
82717d15b25SDag-Erling Smørgrav /* zero terminate */
82817d15b25SDag-Erling Smørgrav if(left > 0)
82917d15b25SDag-Erling Smørgrav *at = 0;
83017d15b25SDag-Erling Smørgrav return ret;
83117d15b25SDag-Erling Smørgrav }
83217d15b25SDag-Erling Smørgrav
83317d15b25SDag-Erling Smørgrav #ifdef SNPRINTF_TEST
83417d15b25SDag-Erling Smørgrav
83517d15b25SDag-Erling Smørgrav /** do tests */
83617d15b25SDag-Erling Smørgrav #undef snprintf
83717d15b25SDag-Erling Smørgrav #define DOTEST(bufsz, result, retval, ...) do { \
83817d15b25SDag-Erling Smørgrav char buf[bufsz]; \
83917d15b25SDag-Erling Smørgrav printf("now test %s\n", #__VA_ARGS__); \
84017d15b25SDag-Erling Smørgrav int r=my_snprintf(buf, sizeof(buf), __VA_ARGS__); \
84117d15b25SDag-Erling Smørgrav if(r != retval || strcmp(buf, result) != 0) { \
84217d15b25SDag-Erling Smørgrav printf("error test(%s) was \"%s\":%d\n", \
84317d15b25SDag-Erling Smørgrav ""#bufsz", "#result", "#retval", "#__VA_ARGS__, \
84417d15b25SDag-Erling Smørgrav buf, r); \
84517d15b25SDag-Erling Smørgrav exit(1); \
84617d15b25SDag-Erling Smørgrav } \
84717d15b25SDag-Erling Smørgrav r=snprintf(buf, sizeof(buf), __VA_ARGS__); \
84817d15b25SDag-Erling Smørgrav if(r != retval || strcmp(buf, result) != 0) { \
84917d15b25SDag-Erling Smørgrav printf("error test(%s) differs with system, \"%s\":%d\n", \
85017d15b25SDag-Erling Smørgrav ""#bufsz", "#result", "#retval", "#__VA_ARGS__, \
85117d15b25SDag-Erling Smørgrav buf, r); \
85217d15b25SDag-Erling Smørgrav exit(1); \
85317d15b25SDag-Erling Smørgrav } \
85417d15b25SDag-Erling Smørgrav printf("test(\"%s\":%d) passed\n", buf, r); \
85517d15b25SDag-Erling Smørgrav } while(0);
85617d15b25SDag-Erling Smørgrav
85717d15b25SDag-Erling Smørgrav /** test program */
main(void)85817d15b25SDag-Erling Smørgrav int main(void)
85917d15b25SDag-Erling Smørgrav {
86017d15b25SDag-Erling Smørgrav int x = 0;
86117d15b25SDag-Erling Smørgrav
86217d15b25SDag-Erling Smørgrav /* bufsize, expectedstring, expectedretval, snprintf arguments */
86317d15b25SDag-Erling Smørgrav DOTEST(1024, "hello", 5, "hello");
86417d15b25SDag-Erling Smørgrav DOTEST(1024, "h", 1, "h");
86517d15b25SDag-Erling Smørgrav /* warning from gcc for format string, but it does work
86617d15b25SDag-Erling Smørgrav * DOTEST(1024, "", 0, ""); */
86717d15b25SDag-Erling Smørgrav
86817d15b25SDag-Erling Smørgrav DOTEST(3, "he", 5, "hello");
86917d15b25SDag-Erling Smørgrav DOTEST(1, "", 7, "%d", 7823089);
87017d15b25SDag-Erling Smørgrav
87117d15b25SDag-Erling Smørgrav /* test positive numbers */
87217d15b25SDag-Erling Smørgrav DOTEST(1024, "0", 1, "%d", 0);
87317d15b25SDag-Erling Smørgrav DOTEST(1024, "1", 1, "%d", 1);
87417d15b25SDag-Erling Smørgrav DOTEST(1024, "9", 1, "%d", 9);
87517d15b25SDag-Erling Smørgrav DOTEST(1024, "15", 2, "%d", 15);
87617d15b25SDag-Erling Smørgrav DOTEST(1024, "ab15cd", 6, "ab%dcd", 15);
87717d15b25SDag-Erling Smørgrav DOTEST(1024, "167", 3, "%d", 167);
87817d15b25SDag-Erling Smørgrav DOTEST(1024, "7823089", 7, "%d", 7823089);
87917d15b25SDag-Erling Smørgrav DOTEST(1024, " 12", 3, "%3d", 12);
88017d15b25SDag-Erling Smørgrav DOTEST(1024, "012", 3, "%.3d", 12);
88117d15b25SDag-Erling Smørgrav DOTEST(1024, "012", 3, "%3.3d", 12);
88217d15b25SDag-Erling Smørgrav DOTEST(1024, "012", 3, "%03d", 12);
88317d15b25SDag-Erling Smørgrav DOTEST(1024, " 012", 4, "%4.3d", 12);
88417d15b25SDag-Erling Smørgrav DOTEST(1024, "", 0, "%.0d", 0);
88517d15b25SDag-Erling Smørgrav
88617d15b25SDag-Erling Smørgrav /* test negative numbers */
88717d15b25SDag-Erling Smørgrav DOTEST(1024, "-1", 2, "%d", -1);
88817d15b25SDag-Erling Smørgrav DOTEST(1024, "-12", 3, "%3d", -12);
88917d15b25SDag-Erling Smørgrav DOTEST(1024, " -2", 3, "%3d", -2);
89017d15b25SDag-Erling Smørgrav DOTEST(1024, "-012", 4, "%.3d", -12);
89117d15b25SDag-Erling Smørgrav DOTEST(1024, "-012", 4, "%3.3d", -12);
89217d15b25SDag-Erling Smørgrav DOTEST(1024, "-012", 4, "%4.3d", -12);
89317d15b25SDag-Erling Smørgrav DOTEST(1024, " -012", 5, "%5.3d", -12);
89417d15b25SDag-Erling Smørgrav DOTEST(1024, "-12", 3, "%03d", -12);
89517d15b25SDag-Erling Smørgrav DOTEST(1024, "-02", 3, "%03d", -2);
89617d15b25SDag-Erling Smørgrav DOTEST(1024, "-15", 3, "%d", -15);
89717d15b25SDag-Erling Smørgrav DOTEST(1024, "-7307", 5, "%d", -7307);
89817d15b25SDag-Erling Smørgrav DOTEST(1024, "-12 ", 5, "%-5d", -12);
89917d15b25SDag-Erling Smørgrav DOTEST(1024, "-00012", 6, "%-.5d", -12);
90017d15b25SDag-Erling Smørgrav
90117d15b25SDag-Erling Smørgrav /* test + and space flags */
90217d15b25SDag-Erling Smørgrav DOTEST(1024, "+12", 3, "%+d", 12);
90317d15b25SDag-Erling Smørgrav DOTEST(1024, " 12", 3, "% d", 12);
90417d15b25SDag-Erling Smørgrav
90517d15b25SDag-Erling Smørgrav /* test %u */
90617d15b25SDag-Erling Smørgrav DOTEST(1024, "12", 2, "%u", 12);
90717d15b25SDag-Erling Smørgrav DOTEST(1024, "0", 1, "%u", 0);
90817d15b25SDag-Erling Smørgrav DOTEST(1024, "4294967295", 10, "%u", 0xffffffff);
90917d15b25SDag-Erling Smørgrav
91017d15b25SDag-Erling Smørgrav /* test %x */
91117d15b25SDag-Erling Smørgrav DOTEST(1024, "0", 1, "%x", 0);
91217d15b25SDag-Erling Smørgrav DOTEST(1024, "c", 1, "%x", 12);
91317d15b25SDag-Erling Smørgrav DOTEST(1024, "12ab34cd", 8, "%x", 0x12ab34cd);
91417d15b25SDag-Erling Smørgrav
91517d15b25SDag-Erling Smørgrav /* test %llu, %lld */
91617d15b25SDag-Erling Smørgrav DOTEST(1024, "18446744073709551615", 20, "%llu",
91717d15b25SDag-Erling Smørgrav (long long)0xffffffffffffffff);
91817d15b25SDag-Erling Smørgrav DOTEST(1024, "-9223372036854775808", 20, "%lld",
91917d15b25SDag-Erling Smørgrav (long long)0x8000000000000000);
92017d15b25SDag-Erling Smørgrav DOTEST(1024, "9223372036854775808", 19, "%llu",
92117d15b25SDag-Erling Smørgrav (long long)0x8000000000000000);
92217d15b25SDag-Erling Smørgrav
92317d15b25SDag-Erling Smørgrav /* test %s */
92417d15b25SDag-Erling Smørgrav DOTEST(1024, "hello", 5, "%s", "hello");
92517d15b25SDag-Erling Smørgrav DOTEST(1024, " hello", 10, "%10s", "hello");
92617d15b25SDag-Erling Smørgrav DOTEST(1024, "hello ", 10, "%-10s", "hello");
92717d15b25SDag-Erling Smørgrav DOTEST(1024, "he", 2, "%.2s", "hello");
92817d15b25SDag-Erling Smørgrav DOTEST(1024, " he", 4, "%4.2s", "hello");
92917d15b25SDag-Erling Smørgrav DOTEST(1024, " h", 4, "%4.2s", "h");
93017d15b25SDag-Erling Smørgrav
93117d15b25SDag-Erling Smørgrav /* test %c */
93217d15b25SDag-Erling Smørgrav DOTEST(1024, "a", 1, "%c", 'a');
93317d15b25SDag-Erling Smørgrav /* warning from gcc for format string, but it does work
93417d15b25SDag-Erling Smørgrav DOTEST(1024, " a", 5, "%5c", 'a');
93517d15b25SDag-Erling Smørgrav DOTEST(1024, "a", 1, "%.0c", 'a'); */
93617d15b25SDag-Erling Smørgrav
93717d15b25SDag-Erling Smørgrav /* test %n */
93817d15b25SDag-Erling Smørgrav DOTEST(1024, "hello", 5, "hello%n", &x);
93917d15b25SDag-Erling Smørgrav if(x != 5) { printf("the %%n failed\n"); exit(1); }
94017d15b25SDag-Erling Smørgrav
94117d15b25SDag-Erling Smørgrav /* test %m */
94217d15b25SDag-Erling Smørgrav errno = 0;
94317d15b25SDag-Erling Smørgrav DOTEST(1024, "Success", 7, "%m");
94417d15b25SDag-Erling Smørgrav
94517d15b25SDag-Erling Smørgrav /* test %p */
94617d15b25SDag-Erling Smørgrav DOTEST(1024, "0x10", 4, "%p", (void*)0x10);
94717d15b25SDag-Erling Smørgrav DOTEST(1024, "(nil)", 5, "%p", (void*)0x0);
94817d15b25SDag-Erling Smørgrav
94917d15b25SDag-Erling Smørgrav /* test %% */
95017d15b25SDag-Erling Smørgrav DOTEST(1024, "%", 1, "%%");
95117d15b25SDag-Erling Smørgrav
95217d15b25SDag-Erling Smørgrav /* test %f */
95317d15b25SDag-Erling Smørgrav DOTEST(1024, "0.000000", 8, "%f", 0.0);
95417d15b25SDag-Erling Smørgrav DOTEST(1024, "0.00", 4, "%.2f", 0.0);
95517d15b25SDag-Erling Smørgrav /* differs, "-0.00" DOTEST(1024, "0.00", 4, "%.2f", -0.0); */
95617d15b25SDag-Erling Smørgrav DOTEST(1024, "234.00", 6, "%.2f", 234.005);
95717d15b25SDag-Erling Smørgrav DOTEST(1024, "8973497.1246", 12, "%.4f", 8973497.12456);
95817d15b25SDag-Erling Smørgrav DOTEST(1024, "-12.000000", 10, "%f", -12.0);
95917d15b25SDag-Erling Smørgrav DOTEST(1024, "6", 1, "%.0f", 6.0);
96017d15b25SDag-Erling Smørgrav
96117d15b25SDag-Erling Smørgrav DOTEST(1024, "6", 1, "%g", 6.0);
96217d15b25SDag-Erling Smørgrav DOTEST(1024, "6.1", 3, "%g", 6.1);
96317d15b25SDag-Erling Smørgrav DOTEST(1024, "6.15", 4, "%g", 6.15);
96417d15b25SDag-Erling Smørgrav
96517d15b25SDag-Erling Smørgrav /* These format strings are from the code of NSD, Unbound, ldns */
96617d15b25SDag-Erling Smørgrav
96717d15b25SDag-Erling Smørgrav DOTEST(1024, "abcdef", 6, "%s", "abcdef");
96817d15b25SDag-Erling Smørgrav DOTEST(1024, "005", 3, "%03u", 5);
96917d15b25SDag-Erling Smørgrav DOTEST(1024, "12345", 5, "%03u", 12345);
97017d15b25SDag-Erling Smørgrav DOTEST(1024, "5", 1, "%d", 5);
97117d15b25SDag-Erling Smørgrav DOTEST(1024, "(nil)", 5, "%p", NULL);
97217d15b25SDag-Erling Smørgrav DOTEST(1024, "12345", 5, "%ld", (long)12345);
97317d15b25SDag-Erling Smørgrav DOTEST(1024, "12345", 5, "%lu", (long)12345);
97417d15b25SDag-Erling Smørgrav DOTEST(1024, " 12345", 12, "%12u", (unsigned)12345);
97517d15b25SDag-Erling Smørgrav DOTEST(1024, "12345", 5, "%u", (unsigned)12345);
97617d15b25SDag-Erling Smørgrav DOTEST(1024, "12345", 5, "%llu", (unsigned long long)12345);
97717d15b25SDag-Erling Smørgrav DOTEST(1024, "12345", 5, "%x", 0x12345);
97817d15b25SDag-Erling Smørgrav DOTEST(1024, "12345", 5, "%llx", (long long)0x12345);
97917d15b25SDag-Erling Smørgrav DOTEST(1024, "012345", 6, "%6.6d", 12345);
98017d15b25SDag-Erling Smørgrav DOTEST(1024, "012345", 6, "%6.6u", 12345);
98117d15b25SDag-Erling Smørgrav DOTEST(1024, "1234.54", 7, "%g", 1234.54);
98217d15b25SDag-Erling Smørgrav DOTEST(1024, "123456789.54", 12, "%.12g", 123456789.54);
98317d15b25SDag-Erling Smørgrav DOTEST(1024, "3456789123456.54", 16, "%.16g", 3456789123456.54);
98417d15b25SDag-Erling Smørgrav /* %24g does not work with 24 digits, not enough accuracy,
98517d15b25SDag-Erling Smørgrav * the first 16 digits are correct */
98617d15b25SDag-Erling Smørgrav DOTEST(1024, "12345", 5, "%3.3d", 12345);
98717d15b25SDag-Erling Smørgrav DOTEST(1024, "000", 3, "%3.3d", 0);
98817d15b25SDag-Erling Smørgrav DOTEST(1024, "001", 3, "%3.3d", 1);
98917d15b25SDag-Erling Smørgrav DOTEST(1024, "012", 3, "%3.3d", 12);
99017d15b25SDag-Erling Smørgrav DOTEST(1024, "-012", 4, "%3.3d", -12);
99117d15b25SDag-Erling Smørgrav DOTEST(1024, "he", 2, "%.2s", "hello");
99217d15b25SDag-Erling Smørgrav DOTEST(1024, "helloworld", 10, "%s%s", "hello", "world");
99317d15b25SDag-Erling Smørgrav DOTEST(1024, "he", 2, "%.*s", 2, "hello");
99417d15b25SDag-Erling Smørgrav DOTEST(1024, " hello", 7, "%*s", 7, "hello");
99517d15b25SDag-Erling Smørgrav DOTEST(1024, "hello ", 7, "%*s", -7, "hello");
99617d15b25SDag-Erling Smørgrav DOTEST(1024, "0", 1, "%c", '0');
99717d15b25SDag-Erling Smørgrav DOTEST(1024, "A", 1, "%c", 'A');
99817d15b25SDag-Erling Smørgrav DOTEST(1024, "", 1, "%c", 0);
99917d15b25SDag-Erling Smørgrav DOTEST(1024, "\010", 1, "%c", 8);
100017d15b25SDag-Erling Smørgrav DOTEST(1024, "%", 1, "%%");
100117d15b25SDag-Erling Smørgrav DOTEST(1024, "0a", 2, "%02x", 0x0a);
100217d15b25SDag-Erling Smørgrav DOTEST(1024, "bd", 2, "%02x", 0xbd);
100317d15b25SDag-Erling Smørgrav DOTEST(1024, "12", 2, "%02ld", (long)12);
100417d15b25SDag-Erling Smørgrav DOTEST(1024, "02", 2, "%02ld", (long)2);
100517d15b25SDag-Erling Smørgrav DOTEST(1024, "02", 2, "%02u", (unsigned)2);
100617d15b25SDag-Erling Smørgrav DOTEST(1024, "765432", 6, "%05u", (unsigned)765432);
100717d15b25SDag-Erling Smørgrav DOTEST(1024, "10.234", 6, "%0.3f", 10.23421);
100817d15b25SDag-Erling Smørgrav DOTEST(1024, "123456.234", 10, "%0.3f", 123456.23421);
100917d15b25SDag-Erling Smørgrav DOTEST(1024, "123456789.234", 13, "%0.3f", 123456789.23421);
101017d15b25SDag-Erling Smørgrav DOTEST(1024, "123456.23", 9, "%.2f", 123456.23421);
101117d15b25SDag-Erling Smørgrav DOTEST(1024, "123456", 6, "%.0f", 123456.23421);
101217d15b25SDag-Erling Smørgrav DOTEST(1024, "0123", 4, "%.4x", 0x0123);
101317d15b25SDag-Erling Smørgrav DOTEST(1024, "00000123", 8, "%.8x", 0x0123);
101417d15b25SDag-Erling Smørgrav DOTEST(1024, "ffeb0cde", 8, "%.8x", 0xffeb0cde);
101517d15b25SDag-Erling Smørgrav DOTEST(1024, " 987654321", 10, "%10lu", (unsigned long)987654321);
101617d15b25SDag-Erling Smørgrav DOTEST(1024, " 987654321", 12, "%12lu", (unsigned long)987654321);
101717d15b25SDag-Erling Smørgrav DOTEST(1024, "987654321", 9, "%i", 987654321);
101817d15b25SDag-Erling Smørgrav DOTEST(1024, "-87654321", 9, "%i", -87654321);
101917d15b25SDag-Erling Smørgrav DOTEST(1024, "hello ", 16, "%-16s", "hello");
102017d15b25SDag-Erling Smørgrav DOTEST(1024, " ", 16, "%-16s", "");
102117d15b25SDag-Erling Smørgrav DOTEST(1024, "a ", 16, "%-16s", "a");
102217d15b25SDag-Erling Smørgrav DOTEST(1024, "foobarfoobar ", 16, "%-16s", "foobarfoobar");
102317d15b25SDag-Erling Smørgrav DOTEST(1024, "foobarfoobarfoobar", 18, "%-16s", "foobarfoobarfoobar");
102417d15b25SDag-Erling Smørgrav
102517d15b25SDag-Erling Smørgrav /* combined expressions */
102617d15b25SDag-Erling Smørgrav DOTEST(1024, "foo 1.0 size 512 edns", 21,
102717d15b25SDag-Erling Smørgrav "foo %s size %d %s%s", "1.0", 512, "", "edns");
102817d15b25SDag-Erling Smørgrav DOTEST(15, "foo 1.0 size 5", 21,
102917d15b25SDag-Erling Smørgrav "foo %s size %d %s%s", "1.0", 512, "", "edns");
103017d15b25SDag-Erling Smørgrav DOTEST(1024, "packet 1203ceff id", 18,
103117d15b25SDag-Erling Smørgrav "packet %2.2x%2.2x%2.2x%2.2x id", 0x12, 0x03, 0xce, 0xff);
103217d15b25SDag-Erling Smørgrav DOTEST(1024, "/tmp/testbound_123abcd.tmp", 26, "/tmp/testbound_%u%s%s.tmp", 123, "ab", "cd");
103317d15b25SDag-Erling Smørgrav
103417d15b25SDag-Erling Smørgrav return 0;
103517d15b25SDag-Erling Smørgrav }
103617d15b25SDag-Erling Smørgrav #endif /* SNPRINTF_TEST */
1037