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