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 "u_printf.h" 25#include <assert.h> 26#include <stdarg.h> 27#include "util/macros.h" 28 29/* Some versions of MinGW are missing _vscprintf's declaration, although they 30 * still provide the symbol in the import library. */ 31#ifdef __MINGW32__ 32_CRTIMP int _vscprintf(const char *format, va_list argptr); 33#endif 34 35#ifndef va_copy 36#ifdef __va_copy 37#define va_copy(dest, src) __va_copy((dest), (src)) 38#else 39#define va_copy(dest, src) (dest) = (src) 40#endif 41#endif 42 43size_t util_printf_next_spec_pos(const std::string &s, size_t pos) 44{ 45 size_t next_tok, spec_pos; 46 do { 47 pos = s.find_first_of('%', pos); 48 49 if (pos == std::string::npos) 50 return -1; 51 52 if (s[pos + 1] == '%') { 53 pos += 2; 54 continue; 55 } 56 57 next_tok = s.find_first_of('%', pos + 1); 58 spec_pos = s.find_first_of("cdieEfFgGaAosuxXp", pos + 1); 59 if (spec_pos != std::string::npos) 60 if (spec_pos < next_tok) 61 return spec_pos; 62 63 pos++; 64 } while (1); 65} 66 67size_t util_printf_next_spec_pos(const char *str, size_t pos) 68{ 69 return util_printf_next_spec_pos(std::string(str), pos); 70} 71 72size_t 73u_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