1b528cefcSMark Murray /* 2bbd80c28SJacques Vidrine * Copyright (c) 1995-2003 Kungliga Tekniska H�gskolan 3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden). 4b528cefcSMark Murray * All rights reserved. 5b528cefcSMark Murray * 6b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without 7b528cefcSMark Murray * modification, are permitted provided that the following conditions 8b528cefcSMark Murray * are met: 9b528cefcSMark Murray * 10b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright 11b528cefcSMark Murray * notice, this list of conditions and the following disclaimer. 12b528cefcSMark Murray * 13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright 14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the 15b528cefcSMark Murray * documentation and/or other materials provided with the distribution. 16b528cefcSMark Murray * 17b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors 18b528cefcSMark Murray * may be used to endorse or promote products derived from this software 19b528cefcSMark Murray * without specific prior written permission. 20b528cefcSMark Murray * 21b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31b528cefcSMark Murray * SUCH DAMAGE. 32b528cefcSMark Murray */ 33b528cefcSMark Murray 34b528cefcSMark Murray #ifdef HAVE_CONFIG_H 35b528cefcSMark Murray #include <config.h> 36c19800e8SDoug Rabson RCSID("$Id: snprintf.c 21005 2007-06-08 01:54:35Z lha $"); 37b528cefcSMark Murray #endif 38c19800e8SDoug Rabson #if defined(TEST_SNPRINTF) 39c19800e8SDoug Rabson #include "snprintf-test.h" 40c19800e8SDoug Rabson #endif /* TEST_SNPRINTF */ 41b528cefcSMark Murray #include <stdio.h> 42b528cefcSMark Murray #include <stdarg.h> 43b528cefcSMark Murray #include <stdlib.h> 44b528cefcSMark Murray #include <string.h> 45b528cefcSMark Murray #include <ctype.h> 46c19800e8SDoug Rabson #include "roken.h" 47c19800e8SDoug Rabson #include <assert.h> 48b528cefcSMark Murray 49b528cefcSMark Murray enum format_flags { 50b528cefcSMark Murray minus_flag = 1, 51b528cefcSMark Murray plus_flag = 2, 52b528cefcSMark Murray space_flag = 4, 53b528cefcSMark Murray alternate_flag = 8, 54b528cefcSMark Murray zero_flag = 16 55b528cefcSMark Murray }; 56b528cefcSMark Murray 57b528cefcSMark Murray /* 58b528cefcSMark Murray * Common state 59b528cefcSMark Murray */ 60b528cefcSMark Murray 614137ff4cSJacques Vidrine struct snprintf_state { 62b528cefcSMark Murray unsigned char *str; 63b528cefcSMark Murray unsigned char *s; 64b528cefcSMark Murray unsigned char *theend; 65b528cefcSMark Murray size_t sz; 66b528cefcSMark Murray size_t max_sz; 674137ff4cSJacques Vidrine void (*append_char)(struct snprintf_state *, unsigned char); 68b528cefcSMark Murray /* XXX - methods */ 69b528cefcSMark Murray }; 70b528cefcSMark Murray 714137ff4cSJacques Vidrine #if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF) 72b528cefcSMark Murray static int 734137ff4cSJacques Vidrine sn_reserve (struct snprintf_state *state, size_t n) 74b528cefcSMark Murray { 75b528cefcSMark Murray return state->s + n > state->theend; 76b528cefcSMark Murray } 77b528cefcSMark Murray 784137ff4cSJacques Vidrine static void 794137ff4cSJacques Vidrine sn_append_char (struct snprintf_state *state, unsigned char c) 80b528cefcSMark Murray { 814137ff4cSJacques Vidrine if (!sn_reserve (state, 1)) 82b528cefcSMark Murray *state->s++ = c; 83b528cefcSMark Murray } 84b528cefcSMark Murray #endif 85b528cefcSMark Murray 86b528cefcSMark Murray static int 874137ff4cSJacques Vidrine as_reserve (struct snprintf_state *state, size_t n) 88b528cefcSMark Murray { 89b528cefcSMark Murray if (state->s + n > state->theend) { 90b528cefcSMark Murray int off = state->s - state->str; 91b528cefcSMark Murray unsigned char *tmp; 92b528cefcSMark Murray 93b528cefcSMark Murray if (state->max_sz && state->sz >= state->max_sz) 94b528cefcSMark Murray return 1; 95b528cefcSMark Murray 96b528cefcSMark Murray state->sz = max(state->sz * 2, state->sz + n); 97b528cefcSMark Murray if (state->max_sz) 98b528cefcSMark Murray state->sz = min(state->sz, state->max_sz); 99b528cefcSMark Murray tmp = realloc (state->str, state->sz); 100b528cefcSMark Murray if (tmp == NULL) 101b528cefcSMark Murray return 1; 102b528cefcSMark Murray state->str = tmp; 103b528cefcSMark Murray state->s = state->str + off; 104b528cefcSMark Murray state->theend = state->str + state->sz - 1; 105b528cefcSMark Murray } 106b528cefcSMark Murray return 0; 107b528cefcSMark Murray } 108b528cefcSMark Murray 1094137ff4cSJacques Vidrine static void 1104137ff4cSJacques Vidrine as_append_char (struct snprintf_state *state, unsigned char c) 111b528cefcSMark Murray { 1124137ff4cSJacques Vidrine if(!as_reserve (state, 1)) 113b528cefcSMark Murray *state->s++ = c; 114b528cefcSMark Murray } 1154137ff4cSJacques Vidrine 1164137ff4cSJacques Vidrine /* longest integer types */ 1174137ff4cSJacques Vidrine 1184137ff4cSJacques Vidrine #ifdef HAVE_LONG_LONG 1194137ff4cSJacques Vidrine typedef unsigned long long u_longest; 1204137ff4cSJacques Vidrine typedef long long longest; 1214137ff4cSJacques Vidrine #else 1224137ff4cSJacques Vidrine typedef unsigned long u_longest; 1234137ff4cSJacques Vidrine typedef long longest; 1244137ff4cSJacques Vidrine #endif 1254137ff4cSJacques Vidrine 1264137ff4cSJacques Vidrine 127c19800e8SDoug Rabson 128c19800e8SDoug Rabson static int 129c19800e8SDoug Rabson pad(struct snprintf_state *state, int width, char c) 130c19800e8SDoug Rabson { 131c19800e8SDoug Rabson int len = 0; 132c19800e8SDoug Rabson while(width-- > 0){ 133c19800e8SDoug Rabson (*state->append_char)(state, c); 134c19800e8SDoug Rabson ++len; 135c19800e8SDoug Rabson } 136c19800e8SDoug Rabson return len; 137c19800e8SDoug Rabson } 138c19800e8SDoug Rabson 139c19800e8SDoug Rabson /* return true if we should use alternatve hex form */ 1404137ff4cSJacques Vidrine static int 1414137ff4cSJacques Vidrine use_alternative (int flags, u_longest num, unsigned base) 1424137ff4cSJacques Vidrine { 143c19800e8SDoug Rabson return (flags & alternate_flag) && base == 16 && num != 0; 144b528cefcSMark Murray } 145b528cefcSMark Murray 146b528cefcSMark Murray static int 1474137ff4cSJacques Vidrine append_number(struct snprintf_state *state, 1488373020dSJacques Vidrine u_longest num, unsigned base, const char *rep, 149b528cefcSMark Murray int width, int prec, int flags, int minusp) 150b528cefcSMark Murray { 151b528cefcSMark Murray int len = 0; 1524137ff4cSJacques Vidrine u_longest n = num; 153c19800e8SDoug Rabson char nstr[64]; /* enough for <192 bit octal integers */ 154c19800e8SDoug Rabson int nstart, nlen; 155c19800e8SDoug Rabson char signchar; 156b528cefcSMark Murray 157b528cefcSMark Murray /* given precision, ignore zero flag */ 158b528cefcSMark Murray if(prec != -1) 159b528cefcSMark Murray flags &= ~zero_flag; 160b528cefcSMark Murray else 161b528cefcSMark Murray prec = 1; 162c19800e8SDoug Rabson 163c19800e8SDoug Rabson /* format number as string */ 164c19800e8SDoug Rabson nstart = sizeof(nstr); 165c19800e8SDoug Rabson nlen = 0; 166c19800e8SDoug Rabson nstr[--nstart] = '\0'; 167b528cefcSMark Murray do { 168c19800e8SDoug Rabson assert(nstart > 0); 169c19800e8SDoug Rabson nstr[--nstart] = rep[n % base]; 170c19800e8SDoug Rabson ++nlen; 1714137ff4cSJacques Vidrine n /= base; 1724137ff4cSJacques Vidrine } while(n); 173c19800e8SDoug Rabson 174c19800e8SDoug Rabson /* zero value with zero precision should produce no digits */ 175c19800e8SDoug Rabson if(prec == 0 && num == 0) { 176c19800e8SDoug Rabson nlen--; 177c19800e8SDoug Rabson nstart++; 178b528cefcSMark Murray } 179c19800e8SDoug Rabson 180c19800e8SDoug Rabson /* figure out what char to use for sign */ 181c19800e8SDoug Rabson if(minusp) 182c19800e8SDoug Rabson signchar = '-'; 183c19800e8SDoug Rabson else if((flags & plus_flag)) 184c19800e8SDoug Rabson signchar = '+'; 185c19800e8SDoug Rabson else if((flags & space_flag)) 186c19800e8SDoug Rabson signchar = ' '; 187c19800e8SDoug Rabson else 188c19800e8SDoug Rabson signchar = '\0'; 189c19800e8SDoug Rabson 190c19800e8SDoug Rabson if((flags & alternate_flag) && base == 8) { 191c19800e8SDoug Rabson /* if necessary, increase the precision to 192c19800e8SDoug Rabson make first digit a zero */ 193c19800e8SDoug Rabson 194c19800e8SDoug Rabson /* XXX C99 claims (regarding # and %o) that "if the value and 195c19800e8SDoug Rabson precision are both 0, a single 0 is printed", but there is 196c19800e8SDoug Rabson no such wording for %x. This would mean that %#.o would 197c19800e8SDoug Rabson output "0", but %#.x "". This does not make sense, and is 198c19800e8SDoug Rabson also not what other printf implementations are doing. */ 199c19800e8SDoug Rabson 200c19800e8SDoug Rabson if(prec <= nlen && nstr[nstart] != '0' && nstr[nstart] != '\0') 201c19800e8SDoug Rabson prec = nlen + 1; 202c19800e8SDoug Rabson } 203c19800e8SDoug Rabson 204c19800e8SDoug Rabson /* possible formats: 205c19800e8SDoug Rabson pad | sign | alt | zero | digits 206c19800e8SDoug Rabson sign | alt | zero | digits | pad minus_flag 207c19800e8SDoug Rabson sign | alt | zero | digits zero_flag */ 208c19800e8SDoug Rabson 209c19800e8SDoug Rabson /* if not right justifying or padding with zeros, we need to 210c19800e8SDoug Rabson compute the length of the rest of the string, and then pad with 211c19800e8SDoug Rabson spaces */ 212c19800e8SDoug Rabson if(!(flags & (minus_flag | zero_flag))) { 213c19800e8SDoug Rabson if(prec > nlen) 214c19800e8SDoug Rabson width -= prec; 215c19800e8SDoug Rabson else 216c19800e8SDoug Rabson width -= nlen; 217c19800e8SDoug Rabson 2184137ff4cSJacques Vidrine if(use_alternative(flags, num, base)) 219c19800e8SDoug Rabson width -= 2; 220c19800e8SDoug Rabson 221c19800e8SDoug Rabson if(signchar != '\0') 222b528cefcSMark Murray width--; 223c19800e8SDoug Rabson 224c19800e8SDoug Rabson /* pad to width */ 225c19800e8SDoug Rabson len += pad(state, width, ' '); 226b528cefcSMark Murray } 227c19800e8SDoug Rabson if(signchar != '\0') { 228c19800e8SDoug Rabson (*state->append_char)(state, signchar); 229c19800e8SDoug Rabson ++len; 230b528cefcSMark Murray } 2314137ff4cSJacques Vidrine if(use_alternative(flags, num, base)) { 2324137ff4cSJacques Vidrine (*state->append_char)(state, '0'); 233c19800e8SDoug Rabson (*state->append_char)(state, rep[10] + 23); /* XXX */ 234c19800e8SDoug Rabson len += 2; 235b528cefcSMark Murray } 236c19800e8SDoug Rabson if(flags & zero_flag) { 237c19800e8SDoug Rabson /* pad to width with zeros */ 238c19800e8SDoug Rabson if(prec - nlen > width - len - nlen) 239c19800e8SDoug Rabson len += pad(state, prec - nlen, '0'); 240c19800e8SDoug Rabson else 241c19800e8SDoug Rabson len += pad(state, width - len - nlen, '0'); 242c19800e8SDoug Rabson } else 243c19800e8SDoug Rabson /* pad to prec with zeros */ 244c19800e8SDoug Rabson len += pad(state, prec - nlen, '0'); 245c19800e8SDoug Rabson 246c19800e8SDoug Rabson while(nstr[nstart] != '\0') { 247c19800e8SDoug Rabson (*state->append_char)(state, nstr[nstart++]); 2484137ff4cSJacques Vidrine ++len; 249b528cefcSMark Murray } 250c19800e8SDoug Rabson 251b528cefcSMark Murray if(flags & minus_flag) 252c19800e8SDoug Rabson len += pad(state, width - len, ' '); 253c19800e8SDoug Rabson 2544137ff4cSJacques Vidrine return len; 255b528cefcSMark Murray } 256b528cefcSMark Murray 2574137ff4cSJacques Vidrine /* 2584137ff4cSJacques Vidrine * return length 2594137ff4cSJacques Vidrine */ 2604137ff4cSJacques Vidrine 261b528cefcSMark Murray static int 2624137ff4cSJacques Vidrine append_string (struct snprintf_state *state, 2634137ff4cSJacques Vidrine const unsigned char *arg, 264b528cefcSMark Murray int width, 265b528cefcSMark Murray int prec, 266b528cefcSMark Murray int flags) 267b528cefcSMark Murray { 2684137ff4cSJacques Vidrine int len = 0; 2694137ff4cSJacques Vidrine 2705e9cd1aeSAssar Westerlund if(arg == NULL) 2714137ff4cSJacques Vidrine arg = (const unsigned char*)"(null)"; 2725e9cd1aeSAssar Westerlund 273b528cefcSMark Murray if(prec != -1) 274b528cefcSMark Murray width -= prec; 275b528cefcSMark Murray else 2764137ff4cSJacques Vidrine width -= strlen((const char *)arg); 277b528cefcSMark Murray if(!(flags & minus_flag)) 278c19800e8SDoug Rabson len += pad(state, width, ' '); 279c19800e8SDoug Rabson 280b528cefcSMark Murray if (prec != -1) { 2814137ff4cSJacques Vidrine while (*arg && prec--) { 2824137ff4cSJacques Vidrine (*state->append_char) (state, *arg++); 2834137ff4cSJacques Vidrine ++len; 2844137ff4cSJacques Vidrine } 285b528cefcSMark Murray } else { 2864137ff4cSJacques Vidrine while (*arg) { 2874137ff4cSJacques Vidrine (*state->append_char) (state, *arg++); 2884137ff4cSJacques Vidrine ++len; 2894137ff4cSJacques Vidrine } 290b528cefcSMark Murray } 291b528cefcSMark Murray if(flags & minus_flag) 292c19800e8SDoug Rabson len += pad(state, width, ' '); 2934137ff4cSJacques Vidrine return len; 294b528cefcSMark Murray } 295b528cefcSMark Murray 296b528cefcSMark Murray static int 2974137ff4cSJacques Vidrine append_char(struct snprintf_state *state, 298b528cefcSMark Murray unsigned char arg, 299b528cefcSMark Murray int width, 300b528cefcSMark Murray int flags) 301b528cefcSMark Murray { 3024137ff4cSJacques Vidrine int len = 0; 303b528cefcSMark Murray 3044137ff4cSJacques Vidrine while(!(flags & minus_flag) && --width > 0) { 3054137ff4cSJacques Vidrine (*state->append_char) (state, ' ') ; 3064137ff4cSJacques Vidrine ++len; 3074137ff4cSJacques Vidrine } 3084137ff4cSJacques Vidrine (*state->append_char) (state, arg); 3094137ff4cSJacques Vidrine ++len; 3104137ff4cSJacques Vidrine while((flags & minus_flag) && --width > 0) { 3114137ff4cSJacques Vidrine (*state->append_char) (state, ' '); 3124137ff4cSJacques Vidrine ++len; 3134137ff4cSJacques Vidrine } 314b528cefcSMark Murray return 0; 315b528cefcSMark Murray } 316b528cefcSMark Murray 317b528cefcSMark Murray /* 318b528cefcSMark Murray * This can't be made into a function... 319b528cefcSMark Murray */ 320b528cefcSMark Murray 3214137ff4cSJacques Vidrine #ifdef HAVE_LONG_LONG 3224137ff4cSJacques Vidrine 3234137ff4cSJacques Vidrine #define PARSE_INT_FORMAT(res, arg, unsig) \ 3244137ff4cSJacques Vidrine if (long_long_flag) \ 3254137ff4cSJacques Vidrine res = (unsig long long)va_arg(arg, unsig long long); \ 3264137ff4cSJacques Vidrine else if (long_flag) \ 3274137ff4cSJacques Vidrine res = (unsig long)va_arg(arg, unsig long); \ 328c19800e8SDoug Rabson else if (size_t_flag) \ 329c19800e8SDoug Rabson res = (unsig long)va_arg(arg, size_t); \ 3304137ff4cSJacques Vidrine else if (short_flag) \ 3314137ff4cSJacques Vidrine res = (unsig short)va_arg(arg, unsig int); \ 3324137ff4cSJacques Vidrine else \ 3334137ff4cSJacques Vidrine res = (unsig int)va_arg(arg, unsig int) 3344137ff4cSJacques Vidrine 3354137ff4cSJacques Vidrine #else 3364137ff4cSJacques Vidrine 337b528cefcSMark Murray #define PARSE_INT_FORMAT(res, arg, unsig) \ 338b528cefcSMark Murray if (long_flag) \ 339b528cefcSMark Murray res = (unsig long)va_arg(arg, unsig long); \ 340c19800e8SDoug Rabson else if (size_t_flag) \ 341c19800e8SDoug Rabson res = (unsig long)va_arg(arg, size_t); \ 342b528cefcSMark Murray else if (short_flag) \ 343d61f1c79SMark Murray res = (unsig short)va_arg(arg, unsig int); \ 344b528cefcSMark Murray else \ 345b528cefcSMark Murray res = (unsig int)va_arg(arg, unsig int) 346b528cefcSMark Murray 3474137ff4cSJacques Vidrine #endif 3484137ff4cSJacques Vidrine 349b528cefcSMark Murray /* 3504137ff4cSJacques Vidrine * zyxprintf - return length, as snprintf 351b528cefcSMark Murray */ 352b528cefcSMark Murray 353b528cefcSMark Murray static int 3544137ff4cSJacques Vidrine xyzprintf (struct snprintf_state *state, const char *char_format, va_list ap) 355b528cefcSMark Murray { 356b528cefcSMark Murray const unsigned char *format = (const unsigned char *)char_format; 357b528cefcSMark Murray unsigned char c; 3584137ff4cSJacques Vidrine int len = 0; 359b528cefcSMark Murray 360b528cefcSMark Murray while((c = *format++)) { 361b528cefcSMark Murray if (c == '%') { 362b528cefcSMark Murray int flags = 0; 363b528cefcSMark Murray int width = 0; 364b528cefcSMark Murray int prec = -1; 365c19800e8SDoug Rabson int size_t_flag = 0; 3664137ff4cSJacques Vidrine int long_long_flag = 0; 367b528cefcSMark Murray int long_flag = 0; 368b528cefcSMark Murray int short_flag = 0; 369b528cefcSMark Murray 370b528cefcSMark Murray /* flags */ 371b528cefcSMark Murray while((c = *format++)){ 372b528cefcSMark Murray if(c == '-') 373b528cefcSMark Murray flags |= minus_flag; 374b528cefcSMark Murray else if(c == '+') 375b528cefcSMark Murray flags |= plus_flag; 376b528cefcSMark Murray else if(c == ' ') 377b528cefcSMark Murray flags |= space_flag; 378b528cefcSMark Murray else if(c == '#') 379b528cefcSMark Murray flags |= alternate_flag; 380b528cefcSMark Murray else if(c == '0') 381b528cefcSMark Murray flags |= zero_flag; 382bbd80c28SJacques Vidrine else if(c == '\'') 383bbd80c28SJacques Vidrine ; /* just ignore */ 384b528cefcSMark Murray else 385b528cefcSMark Murray break; 386b528cefcSMark Murray } 387b528cefcSMark Murray 388b528cefcSMark Murray if((flags & space_flag) && (flags & plus_flag)) 389b528cefcSMark Murray flags ^= space_flag; 390b528cefcSMark Murray 391b528cefcSMark Murray if((flags & minus_flag) && (flags & zero_flag)) 392b528cefcSMark Murray flags ^= zero_flag; 393b528cefcSMark Murray 394b528cefcSMark Murray /* width */ 395b528cefcSMark Murray if (isdigit(c)) 396b528cefcSMark Murray do { 397b528cefcSMark Murray width = width * 10 + c - '0'; 398b528cefcSMark Murray c = *format++; 399b528cefcSMark Murray } while(isdigit(c)); 400b528cefcSMark Murray else if(c == '*') { 401b528cefcSMark Murray width = va_arg(ap, int); 402b528cefcSMark Murray c = *format++; 403b528cefcSMark Murray } 404b528cefcSMark Murray 405b528cefcSMark Murray /* precision */ 406b528cefcSMark Murray if (c == '.') { 407b528cefcSMark Murray prec = 0; 408b528cefcSMark Murray c = *format++; 409b528cefcSMark Murray if (isdigit(c)) 410b528cefcSMark Murray do { 411b528cefcSMark Murray prec = prec * 10 + c - '0'; 412b528cefcSMark Murray c = *format++; 413b528cefcSMark Murray } while(isdigit(c)); 414b528cefcSMark Murray else if (c == '*') { 415b528cefcSMark Murray prec = va_arg(ap, int); 416b528cefcSMark Murray c = *format++; 417b528cefcSMark Murray } 418b528cefcSMark Murray } 419b528cefcSMark Murray 420b528cefcSMark Murray /* size */ 421b528cefcSMark Murray 422b528cefcSMark Murray if (c == 'h') { 423b528cefcSMark Murray short_flag = 1; 424b528cefcSMark Murray c = *format++; 425c19800e8SDoug Rabson } else if (c == 'z') { 426c19800e8SDoug Rabson size_t_flag = 1; 427c19800e8SDoug Rabson c = *format++; 428b528cefcSMark Murray } else if (c == 'l') { 429b528cefcSMark Murray long_flag = 1; 430b528cefcSMark Murray c = *format++; 4314137ff4cSJacques Vidrine if (c == 'l') { 4324137ff4cSJacques Vidrine long_long_flag = 1; 4334137ff4cSJacques Vidrine c = *format++; 4344137ff4cSJacques Vidrine } 435b528cefcSMark Murray } 436b528cefcSMark Murray 437c19800e8SDoug Rabson if(c != 'd' && c != 'i') 438c19800e8SDoug Rabson flags &= ~(plus_flag | space_flag); 439c19800e8SDoug Rabson 440b528cefcSMark Murray switch (c) { 441b528cefcSMark Murray case 'c' : 4424137ff4cSJacques Vidrine append_char(state, va_arg(ap, int), width, flags); 4434137ff4cSJacques Vidrine ++len; 444b528cefcSMark Murray break; 445b528cefcSMark Murray case 's' : 4464137ff4cSJacques Vidrine len += append_string(state, 447b528cefcSMark Murray va_arg(ap, unsigned char*), 448b528cefcSMark Murray width, 449b528cefcSMark Murray prec, 4504137ff4cSJacques Vidrine flags); 451b528cefcSMark Murray break; 452b528cefcSMark Murray case 'd' : 453b528cefcSMark Murray case 'i' : { 4544137ff4cSJacques Vidrine longest arg; 4554137ff4cSJacques Vidrine u_longest num; 456b528cefcSMark Murray int minusp = 0; 457b528cefcSMark Murray 458b528cefcSMark Murray PARSE_INT_FORMAT(arg, ap, signed); 459b528cefcSMark Murray 460b528cefcSMark Murray if (arg < 0) { 461b528cefcSMark Murray minusp = 1; 462b528cefcSMark Murray num = -arg; 463b528cefcSMark Murray } else 464b528cefcSMark Murray num = arg; 465b528cefcSMark Murray 4664137ff4cSJacques Vidrine len += append_number (state, num, 10, "0123456789", 4674137ff4cSJacques Vidrine width, prec, flags, minusp); 468b528cefcSMark Murray break; 469b528cefcSMark Murray } 470b528cefcSMark Murray case 'u' : { 4714137ff4cSJacques Vidrine u_longest arg; 472b528cefcSMark Murray 473b528cefcSMark Murray PARSE_INT_FORMAT(arg, ap, unsigned); 474b528cefcSMark Murray 4754137ff4cSJacques Vidrine len += append_number (state, arg, 10, "0123456789", 4764137ff4cSJacques Vidrine width, prec, flags, 0); 477b528cefcSMark Murray break; 478b528cefcSMark Murray } 479b528cefcSMark Murray case 'o' : { 4804137ff4cSJacques Vidrine u_longest arg; 481b528cefcSMark Murray 482b528cefcSMark Murray PARSE_INT_FORMAT(arg, ap, unsigned); 483b528cefcSMark Murray 4844137ff4cSJacques Vidrine len += append_number (state, arg, 010, "01234567", 4854137ff4cSJacques Vidrine width, prec, flags, 0); 486b528cefcSMark Murray break; 487b528cefcSMark Murray } 488b528cefcSMark Murray case 'x' : { 4894137ff4cSJacques Vidrine u_longest arg; 490b528cefcSMark Murray 491b528cefcSMark Murray PARSE_INT_FORMAT(arg, ap, unsigned); 492b528cefcSMark Murray 4934137ff4cSJacques Vidrine len += append_number (state, arg, 0x10, "0123456789abcdef", 4944137ff4cSJacques Vidrine width, prec, flags, 0); 495b528cefcSMark Murray break; 496b528cefcSMark Murray } 497b528cefcSMark Murray case 'X' :{ 4984137ff4cSJacques Vidrine u_longest arg; 499b528cefcSMark Murray 500b528cefcSMark Murray PARSE_INT_FORMAT(arg, ap, unsigned); 501b528cefcSMark Murray 5024137ff4cSJacques Vidrine len += append_number (state, arg, 0x10, "0123456789ABCDEF", 5034137ff4cSJacques Vidrine width, prec, flags, 0); 504b528cefcSMark Murray break; 505b528cefcSMark Murray } 506b528cefcSMark Murray case 'p' : { 507b528cefcSMark Murray unsigned long arg = (unsigned long)va_arg(ap, void*); 508b528cefcSMark Murray 5094137ff4cSJacques Vidrine len += append_number (state, arg, 0x10, "0123456789ABCDEF", 5104137ff4cSJacques Vidrine width, prec, flags, 0); 511b528cefcSMark Murray break; 512b528cefcSMark Murray } 513b528cefcSMark Murray case 'n' : { 514b528cefcSMark Murray int *arg = va_arg(ap, int*); 515b528cefcSMark Murray *arg = state->s - state->str; 516b528cefcSMark Murray break; 517b528cefcSMark Murray } 518b528cefcSMark Murray case '\0' : 519b528cefcSMark Murray --format; 520b528cefcSMark Murray /* FALLTHROUGH */ 521b528cefcSMark Murray case '%' : 5224137ff4cSJacques Vidrine (*state->append_char)(state, c); 5234137ff4cSJacques Vidrine ++len; 524b528cefcSMark Murray break; 525b528cefcSMark Murray default : 5264137ff4cSJacques Vidrine (*state->append_char)(state, '%'); 5274137ff4cSJacques Vidrine (*state->append_char)(state, c); 5284137ff4cSJacques Vidrine len += 2; 529b528cefcSMark Murray break; 530b528cefcSMark Murray } 5314137ff4cSJacques Vidrine } else { 5324137ff4cSJacques Vidrine (*state->append_char) (state, c); 5334137ff4cSJacques Vidrine ++len; 534b528cefcSMark Murray } 5354137ff4cSJacques Vidrine } 5364137ff4cSJacques Vidrine return len; 537b528cefcSMark Murray } 538b528cefcSMark Murray 5394137ff4cSJacques Vidrine #if !defined(HAVE_SNPRINTF) || defined(TEST_SNPRINTF) 540c19800e8SDoug Rabson int ROKEN_LIB_FUNCTION 541b528cefcSMark Murray snprintf (char *str, size_t sz, const char *format, ...) 542b528cefcSMark Murray { 543b528cefcSMark Murray va_list args; 544b528cefcSMark Murray int ret; 545b528cefcSMark Murray 546b528cefcSMark Murray va_start(args, format); 547b528cefcSMark Murray ret = vsnprintf (str, sz, format, args); 5484137ff4cSJacques Vidrine va_end(args); 549b528cefcSMark Murray 550b528cefcSMark Murray #ifdef PARANOIA 551b528cefcSMark Murray { 552b528cefcSMark Murray int ret2; 553b528cefcSMark Murray char *tmp; 554b528cefcSMark Murray 555b528cefcSMark Murray tmp = malloc (sz); 556b528cefcSMark Murray if (tmp == NULL) 557b528cefcSMark Murray abort (); 558b528cefcSMark Murray 5594137ff4cSJacques Vidrine va_start(args, format); 560b528cefcSMark Murray ret2 = vsprintf (tmp, format, args); 5614137ff4cSJacques Vidrine va_end(args); 562b528cefcSMark Murray if (ret != ret2 || strcmp(str, tmp)) 563b528cefcSMark Murray abort (); 564b528cefcSMark Murray free (tmp); 565b528cefcSMark Murray } 566b528cefcSMark Murray #endif 567b528cefcSMark Murray 568b528cefcSMark Murray return ret; 569b528cefcSMark Murray } 570b528cefcSMark Murray #endif 571b528cefcSMark Murray 5724137ff4cSJacques Vidrine #if !defined(HAVE_ASPRINTF) || defined(TEST_SNPRINTF) 573c19800e8SDoug Rabson int ROKEN_LIB_FUNCTION 574b528cefcSMark Murray asprintf (char **ret, const char *format, ...) 575b528cefcSMark Murray { 576b528cefcSMark Murray va_list args; 577b528cefcSMark Murray int val; 578b528cefcSMark Murray 579b528cefcSMark Murray va_start(args, format); 580b528cefcSMark Murray val = vasprintf (ret, format, args); 5814137ff4cSJacques Vidrine va_end(args); 582b528cefcSMark Murray 583b528cefcSMark Murray #ifdef PARANOIA 584b528cefcSMark Murray { 585b528cefcSMark Murray int ret2; 586b528cefcSMark Murray char *tmp; 587b528cefcSMark Murray tmp = malloc (val + 1); 588b528cefcSMark Murray if (tmp == NULL) 589b528cefcSMark Murray abort (); 590b528cefcSMark Murray 5914137ff4cSJacques Vidrine va_start(args, format); 592b528cefcSMark Murray ret2 = vsprintf (tmp, format, args); 5934137ff4cSJacques Vidrine va_end(args); 594b528cefcSMark Murray if (val != ret2 || strcmp(*ret, tmp)) 595b528cefcSMark Murray abort (); 596b528cefcSMark Murray free (tmp); 597b528cefcSMark Murray } 598b528cefcSMark Murray #endif 599b528cefcSMark Murray 600b528cefcSMark Murray return val; 601b528cefcSMark Murray } 602b528cefcSMark Murray #endif 603b528cefcSMark Murray 6044137ff4cSJacques Vidrine #if !defined(HAVE_ASNPRINTF) || defined(TEST_SNPRINTF) 605c19800e8SDoug Rabson int ROKEN_LIB_FUNCTION 606b528cefcSMark Murray asnprintf (char **ret, size_t max_sz, const char *format, ...) 607b528cefcSMark Murray { 608b528cefcSMark Murray va_list args; 609b528cefcSMark Murray int val; 610b528cefcSMark Murray 611b528cefcSMark Murray va_start(args, format); 612b528cefcSMark Murray val = vasnprintf (ret, max_sz, format, args); 613b528cefcSMark Murray 614b528cefcSMark Murray #ifdef PARANOIA 615b528cefcSMark Murray { 616b528cefcSMark Murray int ret2; 617b528cefcSMark Murray char *tmp; 618b528cefcSMark Murray tmp = malloc (val + 1); 619b528cefcSMark Murray if (tmp == NULL) 620b528cefcSMark Murray abort (); 621b528cefcSMark Murray 622b528cefcSMark Murray ret2 = vsprintf (tmp, format, args); 623b528cefcSMark Murray if (val != ret2 || strcmp(*ret, tmp)) 624b528cefcSMark Murray abort (); 625b528cefcSMark Murray free (tmp); 626b528cefcSMark Murray } 627b528cefcSMark Murray #endif 628b528cefcSMark Murray 629b528cefcSMark Murray va_end(args); 630b528cefcSMark Murray return val; 631b528cefcSMark Murray } 632b528cefcSMark Murray #endif 633b528cefcSMark Murray 6344137ff4cSJacques Vidrine #if !defined(HAVE_VASPRINTF) || defined(TEST_SNPRINTF) 635c19800e8SDoug Rabson int ROKEN_LIB_FUNCTION 636b528cefcSMark Murray vasprintf (char **ret, const char *format, va_list args) 637b528cefcSMark Murray { 638b528cefcSMark Murray return vasnprintf (ret, 0, format, args); 639b528cefcSMark Murray } 640b528cefcSMark Murray #endif 641b528cefcSMark Murray 642b528cefcSMark Murray 6434137ff4cSJacques Vidrine #if !defined(HAVE_VASNPRINTF) || defined(TEST_SNPRINTF) 644c19800e8SDoug Rabson int ROKEN_LIB_FUNCTION 645b528cefcSMark Murray vasnprintf (char **ret, size_t max_sz, const char *format, va_list args) 646b528cefcSMark Murray { 647b528cefcSMark Murray int st; 6484137ff4cSJacques Vidrine struct snprintf_state state; 649b528cefcSMark Murray 650b528cefcSMark Murray state.max_sz = max_sz; 651b528cefcSMark Murray state.sz = 1; 652b528cefcSMark Murray state.str = malloc(state.sz); 653b528cefcSMark Murray if (state.str == NULL) { 654b528cefcSMark Murray *ret = NULL; 655b528cefcSMark Murray return -1; 656b528cefcSMark Murray } 657b528cefcSMark Murray state.s = state.str; 658b528cefcSMark Murray state.theend = state.s + state.sz - 1; 659b528cefcSMark Murray state.append_char = as_append_char; 660b528cefcSMark Murray 661b528cefcSMark Murray st = xyzprintf (&state, format, args); 6624137ff4cSJacques Vidrine if (st > state.sz) { 663b528cefcSMark Murray free (state.str); 664b528cefcSMark Murray *ret = NULL; 665b528cefcSMark Murray return -1; 666b528cefcSMark Murray } else { 667b528cefcSMark Murray char *tmp; 668b528cefcSMark Murray 669b528cefcSMark Murray *state.s = '\0'; 6704137ff4cSJacques Vidrine tmp = realloc (state.str, st+1); 671b528cefcSMark Murray if (tmp == NULL) { 672b528cefcSMark Murray free (state.str); 673b528cefcSMark Murray *ret = NULL; 674b528cefcSMark Murray return -1; 675b528cefcSMark Murray } 676b528cefcSMark Murray *ret = tmp; 6774137ff4cSJacques Vidrine return st; 678b528cefcSMark Murray } 679b528cefcSMark Murray } 680b528cefcSMark Murray #endif 681b528cefcSMark Murray 6824137ff4cSJacques Vidrine #if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF) 683c19800e8SDoug Rabson int ROKEN_LIB_FUNCTION 684b528cefcSMark Murray vsnprintf (char *str, size_t sz, const char *format, va_list args) 685b528cefcSMark Murray { 6864137ff4cSJacques Vidrine struct snprintf_state state; 687b528cefcSMark Murray int ret; 688b528cefcSMark Murray unsigned char *ustr = (unsigned char *)str; 689b528cefcSMark Murray 690b528cefcSMark Murray state.max_sz = 0; 691b528cefcSMark Murray state.sz = sz; 692b528cefcSMark Murray state.str = ustr; 693b528cefcSMark Murray state.s = ustr; 6944137ff4cSJacques Vidrine state.theend = ustr + sz - (sz > 0); 695b528cefcSMark Murray state.append_char = sn_append_char; 696b528cefcSMark Murray 697b528cefcSMark Murray ret = xyzprintf (&state, format, args); 698c19800e8SDoug Rabson if (state.s != NULL && sz != 0) 699b528cefcSMark Murray *state.s = '\0'; 7004137ff4cSJacques Vidrine return ret; 701b528cefcSMark Murray } 702b528cefcSMark Murray #endif 703