1 /* Formatted output to obstacks. 2 Copyright (C) 2008-2021 Free Software Foundation, Inc. 3 4 This file is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published 6 by the Free Software Foundation; either version 3 of the License, 7 or (at your option) any later version. 8 9 This file is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 16 17 #include <config.h> 18 19 /* Specification. */ 20 #include <stdio.h> 21 22 #include "obstack.h" 23 #include "vasnprintf.h" 24 25 #include <errno.h> 26 #include <stdarg.h> 27 #include <stdlib.h> 28 29 /* Grow an obstack with formatted output. Return the number of bytes 30 added to OBS. No trailing nul byte is added, and the object should 31 be closed with obstack_finish before use. 32 33 Upon memory allocation error, call obstack_alloc_failed_handler. 34 Upon other error, return -1. */ 35 int 36 obstack_printf (struct obstack *obs, const char *format, ...) /* */ 37 { 38 va_list args; 39 int result; 40 41 va_start (args, format); 42 result = obstack_vprintf (obs, format, args); 43 va_end (args); 44 return result; 45 } 46 47 /* Grow an obstack with formatted output. Return the number of bytes 48 added to OBS. No trailing nul byte is added, and the object should 49 be closed with obstack_finish before use. 50 51 Upon memory allocation error, call obstack_alloc_failed_handler. 52 Upon other error, return -1. */ 53 int 54 obstack_vprintf (struct obstack *obs, const char *format, va_list args) /* */ 55 { 56 /* If we are close to the end of the current obstack chunk, use a 57 stack-allocated buffer and copy, to reduce the likelihood of a 58 small-size malloc. Otherwise, print directly into the 59 obstack. */ 60 enum { CUTOFF = 1024 }; 61 char buf[CUTOFF]; 62 char *base = obstack_next_free (obs); 63 size_t len = obstack_room (obs); 64 char *str; 65 66 if (len < CUTOFF) 67 { 68 base = buf; 69 len = CUTOFF; 70 } 71 str = vasnprintf (base, &len, format, args); 72 if (!str) 73 { 74 if (errno == ENOMEM) 75 obstack_alloc_failed_handler (); 76 return -1; 77 } 78 if (str == base && str != buf) 79 /* The output was already computed in place, but we need to 80 account for its size. */ 81 obstack_blank_fast (obs, len); 82 else 83 { 84 /* The output exceeded available obstack space or we used buf; 85 copy the resulting string. */ 86 obstack_grow (obs, str, len); 87 if (str != buf) 88 free (str); 89 } 90 return len; 91 }