1228753Smm/*- 2228753Smm * Copyright (c) 2003-2007 Tim Kientzle 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24228753Smm */ 25228753Smm 26228753Smm#include "archive_platform.h" 27228763Smm__FBSDID("$FreeBSD: stable/10/contrib/libarchive/libarchive/archive_string_sprintf.c 316338 2017-03-31 20:17:30Z mm $"); 28228753Smm 29228753Smm/* 30228753Smm * The use of printf()-family functions can be troublesome 31228753Smm * for space-constrained applications. In addition, correctly 32228753Smm * implementing this function in terms of vsnprintf() requires 33228753Smm * two calls (one to determine the size, another to format the 34228753Smm * result), which in turn requires duplicating the argument list 35228753Smm * using va_copy, which isn't yet universally available. <sigh> 36228753Smm * 37228753Smm * So, I've implemented a bare minimum of printf()-like capability 38228753Smm * here. This is only used to format error messages, so doesn't 39228753Smm * require any floating-point support or field-width handling. 40228753Smm */ 41238856Smm#ifdef HAVE_ERRNO_H 42238856Smm#include <errno.h> 43238856Smm#endif 44228753Smm#include <stdio.h> 45228753Smm 46228753Smm#include "archive_string.h" 47228753Smm#include "archive_private.h" 48228753Smm 49228753Smm/* 50228753Smm * Utility functions to format signed/unsigned integers and append 51228753Smm * them to an archive_string. 52228753Smm */ 53228753Smmstatic void 54228753Smmappend_uint(struct archive_string *as, uintmax_t d, unsigned base) 55228753Smm{ 56316338Smm static const char digits[] = "0123456789abcdef"; 57228753Smm if (d >= base) 58228753Smm append_uint(as, d/base, base); 59228753Smm archive_strappend_char(as, digits[d % base]); 60228753Smm} 61228753Smm 62228753Smmstatic void 63228753Smmappend_int(struct archive_string *as, intmax_t d, unsigned base) 64228753Smm{ 65232153Smm uintmax_t ud; 66232153Smm 67228753Smm if (d < 0) { 68228753Smm archive_strappend_char(as, '-'); 69232153Smm ud = (d == INTMAX_MIN) ? (uintmax_t)(INTMAX_MAX) + 1 : (uintmax_t)(-d); 70232153Smm } else 71232153Smm ud = d; 72232153Smm append_uint(as, ud, base); 73228753Smm} 74228753Smm 75228753Smm 76228753Smmvoid 77232153Smmarchive_string_sprintf(struct archive_string *as, const char *fmt, ...) 78228753Smm{ 79228753Smm va_list ap; 80228753Smm 81228753Smm va_start(ap, fmt); 82228753Smm archive_string_vsprintf(as, fmt, ap); 83228753Smm va_end(ap); 84228753Smm} 85228753Smm 86228753Smm/* 87228753Smm * Like 'vsprintf', but ensures the target is big enough, resizing if 88228753Smm * necessary. 89228753Smm */ 90228753Smmvoid 91232153Smmarchive_string_vsprintf(struct archive_string *as, const char *fmt, 92228753Smm va_list ap) 93228753Smm{ 94228753Smm char long_flag; 95228753Smm intmax_t s; /* Signed integer temp. */ 96228753Smm uintmax_t u; /* Unsigned integer temp. */ 97228753Smm const char *p, *p2; 98232153Smm const wchar_t *pw; 99228753Smm 100232153Smm if (archive_string_ensure(as, 64) == NULL) 101228753Smm __archive_errx(1, "Out of memory"); 102228753Smm 103228753Smm if (fmt == NULL) { 104228753Smm as->s[0] = 0; 105228753Smm return; 106228753Smm } 107228753Smm 108228753Smm for (p = fmt; *p != '\0'; p++) { 109228753Smm const char *saved_p = p; 110228753Smm 111228753Smm if (*p != '%') { 112228753Smm archive_strappend_char(as, *p); 113228753Smm continue; 114228753Smm } 115228753Smm 116228753Smm p++; 117228753Smm 118228753Smm long_flag = '\0'; 119228753Smm switch(*p) { 120228753Smm case 'j': 121228753Smm case 'l': 122232153Smm case 'z': 123232153Smm long_flag = *p; 124228753Smm p++; 125228753Smm break; 126228753Smm } 127228753Smm 128228753Smm switch (*p) { 129228753Smm case '%': 130232153Smm archive_strappend_char(as, '%'); 131228753Smm break; 132228753Smm case 'c': 133228753Smm s = va_arg(ap, int); 134238856Smm archive_strappend_char(as, (char)s); 135228753Smm break; 136228753Smm case 'd': 137228753Smm switch(long_flag) { 138228753Smm case 'j': s = va_arg(ap, intmax_t); break; 139228753Smm case 'l': s = va_arg(ap, long); break; 140232153Smm case 'z': s = va_arg(ap, ssize_t); break; 141228753Smm default: s = va_arg(ap, int); break; 142228753Smm } 143228753Smm append_int(as, s, 10); 144228753Smm break; 145228753Smm case 's': 146232153Smm switch(long_flag) { 147232153Smm case 'l': 148232153Smm pw = va_arg(ap, wchar_t *); 149232153Smm if (pw == NULL) 150232153Smm pw = L"(null)"; 151238856Smm if (archive_string_append_from_wcs(as, pw, 152238856Smm wcslen(pw)) != 0 && errno == ENOMEM) 153238856Smm __archive_errx(1, "Out of memory"); 154232153Smm break; 155232153Smm default: 156232153Smm p2 = va_arg(ap, char *); 157232153Smm if (p2 == NULL) 158232153Smm p2 = "(null)"; 159232153Smm archive_strcat(as, p2); 160232153Smm break; 161232153Smm } 162228753Smm break; 163232153Smm case 'S': 164232153Smm pw = va_arg(ap, wchar_t *); 165232153Smm if (pw == NULL) 166232153Smm pw = L"(null)"; 167238856Smm if (archive_string_append_from_wcs(as, pw, 168238856Smm wcslen(pw)) != 0 && errno == ENOMEM) 169238856Smm __archive_errx(1, "Out of memory"); 170232153Smm break; 171228753Smm case 'o': case 'u': case 'x': case 'X': 172228753Smm /* Common handling for unsigned integer formats. */ 173228753Smm switch(long_flag) { 174228753Smm case 'j': u = va_arg(ap, uintmax_t); break; 175228753Smm case 'l': u = va_arg(ap, unsigned long); break; 176232153Smm case 'z': u = va_arg(ap, size_t); break; 177228753Smm default: u = va_arg(ap, unsigned int); break; 178228753Smm } 179228753Smm /* Format it in the correct base. */ 180228753Smm switch (*p) { 181228753Smm case 'o': append_uint(as, u, 8); break; 182228753Smm case 'u': append_uint(as, u, 10); break; 183228753Smm default: append_uint(as, u, 16); break; 184228753Smm } 185228753Smm break; 186228753Smm default: 187228753Smm /* Rewind and print the initial '%' literally. */ 188228753Smm p = saved_p; 189228753Smm archive_strappend_char(as, *p); 190228753Smm } 191228753Smm } 192228753Smm} 193