1// 2// Copyright 2020 Serge Martin 3// 4// Permission is hereby granted, free of charge, to any person obtaining a 5// copy of this software and associated documentation files (the "Software"), 6// to deal in the Software without restriction, including without limitation 7// the rights to use, copy, modify, merge, publish, distribute, sublicense, 8// and/or sell copies of the Software, and to permit persons to whom the 9// Software is furnished to do so, subject to the following conditions: 10// 11// The above copyright notice and this permission notice shall be included in 12// all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 18// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20// OTHER DEALINGS IN THE SOFTWARE. 21// 22// Extract from Serge's printf clover code by airlied. 23 24#include <assert.h> 25#include <stdarg.h> 26#include <string.h> 27 28#include "macros.h" 29#include "u_printf.h" 30 31/* Some versions of MinGW are missing _vscprintf's declaration, although they 32 * still provide the symbol in the import library. */ 33#ifdef __MINGW32__ 34_CRTIMP int _vscprintf(const char *format, va_list argptr); 35#endif 36 37#ifndef va_copy 38#ifdef __va_copy 39#define va_copy(dest, src) __va_copy((dest), (src)) 40#else 41#define va_copy(dest, src) (dest) = (src) 42#endif 43#endif 44 45size_t util_printf_next_spec_pos(const char *str, size_t pos) 46{ 47 if (str == NULL) 48 return -1; 49 50 const char *str_found = str + pos; 51 do { 52 str_found = strchr(str_found, '%'); 53 if (str_found == NULL) 54 return -1; 55 56 ++str_found; 57 if (*str_found == '%') { 58 ++str_found; 59 continue; 60 } 61 62 char *spec_pos = strpbrk(str_found, "cdieEfFgGaAosuxXp%"); 63 if (spec_pos == NULL) { 64 return -1; 65 } else if (*spec_pos == '%') { 66 str_found = spec_pos; 67 } else { 68 return spec_pos - str; 69 } 70 } while (1); 71} 72 73size_t u_printf_length(const char *fmt, va_list untouched_args) 74{ 75 int size; 76 char junk; 77 78 /* Make a copy of the va_list so the original caller can still use it */ 79 va_list args; 80 va_copy(args, untouched_args); 81 82#ifdef _WIN32 83 /* We need to use _vcsprintf to calculate the size as vsnprintf returns -1 84 * if the number of characters to write is greater than count. 85 */ 86 size = _vscprintf(fmt, args); 87 (void)junk; 88#else 89 size = vsnprintf(&junk, 1, fmt, args); 90#endif 91 assert(size >= 0); 92 93 va_end(args); 94 95 return size; 96} 97