198b9484cSchristos /* Implement the vsnprintf function. 2*5173eb0aSchristos Copyright (C) 2003-2024 Free Software Foundation, Inc. 398b9484cSchristos Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>. 498b9484cSchristos 598b9484cSchristos This file is part of the libiberty library. This library is free 698b9484cSchristos software; you can redistribute it and/or modify it under the 798b9484cSchristos terms of the GNU General Public License as published by the 898b9484cSchristos Free Software Foundation; either version 2, or (at your option) 998b9484cSchristos any later version. 1098b9484cSchristos 1198b9484cSchristos This library is distributed in the hope that it will be useful, 1298b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 1398b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1498b9484cSchristos GNU General Public License for more details. 1598b9484cSchristos 1698b9484cSchristos You should have received a copy of the GNU General Public License 1798b9484cSchristos along with GNU CC; see the file COPYING. If not, write to 1898b9484cSchristos the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 1998b9484cSchristos 2098b9484cSchristos As a special exception, if you link this library with files 2198b9484cSchristos compiled with a GNU compiler to produce an executable, this does not cause 2298b9484cSchristos the resulting executable to be covered by the GNU General Public License. 2398b9484cSchristos This exception does not however invalidate any other reasons why 2498b9484cSchristos the executable file might be covered by the GNU General Public License. */ 2598b9484cSchristos 2698b9484cSchristos /* 2798b9484cSchristos 2898b9484cSchristos @deftypefn Supplemental int vsnprintf (char *@var{buf}, size_t @var{n}, @ 2998b9484cSchristos const char *@var{format}, va_list @var{ap}) 3098b9484cSchristos 3198b9484cSchristos This function is similar to @code{vsprintf}, but it will write to 3298b9484cSchristos @var{buf} at most @code{@var{n}-1} bytes of text, followed by a 3398b9484cSchristos terminating null byte, for a total of @var{n} bytes. On error the 3498b9484cSchristos return value is -1, otherwise it returns the number of characters that 3598b9484cSchristos would have been printed had @var{n} been sufficiently large, 3698b9484cSchristos regardless of the actual value of @var{n}. Note some pre-C99 system 3798b9484cSchristos libraries do not implement this correctly so users cannot generally 3898b9484cSchristos rely on the return value if the system version of this function is 3998b9484cSchristos used. 4098b9484cSchristos 4198b9484cSchristos @end deftypefn 4298b9484cSchristos 4398b9484cSchristos */ 4498b9484cSchristos 4598b9484cSchristos #include "config.h" 4698b9484cSchristos #include "ansidecl.h" 4798b9484cSchristos 4898b9484cSchristos #include <stdarg.h> 4998b9484cSchristos #ifdef HAVE_STRING_H 5098b9484cSchristos #include <string.h> 5198b9484cSchristos #endif 5298b9484cSchristos #ifdef HAVE_STDLIB_H 5398b9484cSchristos #include <stdlib.h> 5498b9484cSchristos #endif 5598b9484cSchristos 5698b9484cSchristos #include "libiberty.h" 5798b9484cSchristos 5898b9484cSchristos /* This implementation relies on a working vasprintf. */ 5998b9484cSchristos int 6098b9484cSchristos vsnprintf (char *s, size_t n, const char *format, va_list ap) 6198b9484cSchristos { 6298b9484cSchristos char *buf = 0; 6398b9484cSchristos int result = vasprintf (&buf, format, ap); 6498b9484cSchristos 6598b9484cSchristos if (!buf) 6698b9484cSchristos return -1; 6798b9484cSchristos if (result < 0) 6898b9484cSchristos { 6998b9484cSchristos free (buf); 7098b9484cSchristos return -1; 7198b9484cSchristos } 7298b9484cSchristos 7398b9484cSchristos result = strlen (buf); 7498b9484cSchristos if (n > 0) 7598b9484cSchristos { 7698b9484cSchristos if ((long) n > result) 7798b9484cSchristos memcpy (s, buf, result+1); 7898b9484cSchristos else 7998b9484cSchristos { 8098b9484cSchristos memcpy (s, buf, n-1); 8198b9484cSchristos s[n - 1] = 0; 8298b9484cSchristos } 8398b9484cSchristos } 8498b9484cSchristos free (buf); 8598b9484cSchristos return result; 8698b9484cSchristos } 8798b9484cSchristos 8898b9484cSchristos #ifdef TEST 8998b9484cSchristos /* Set the buffer to a known state. */ 9098b9484cSchristos #define CLEAR(BUF) do { memset ((BUF), 'X', sizeof (BUF)); (BUF)[14] = '\0'; } while (0) 9198b9484cSchristos /* For assertions. */ 9298b9484cSchristos #define VERIFY(P) do { if (!(P)) abort(); } while (0) 9398b9484cSchristos 9498b9484cSchristos static int ATTRIBUTE_PRINTF_3 9598b9484cSchristos checkit (char *s, size_t n, const char *format, ...) 9698b9484cSchristos { 9798b9484cSchristos int result; 98837edd6bSchristos va_list ap; 99837edd6bSchristos va_start (ap, format); 10098b9484cSchristos result = vsnprintf (s, n, format, ap); 101837edd6bSchristos va_end (ap); 10298b9484cSchristos return result; 10398b9484cSchristos } 10498b9484cSchristos 10598b9484cSchristos extern int main (void); 10698b9484cSchristos int 10798b9484cSchristos main (void) 10898b9484cSchristos { 10998b9484cSchristos char buf[128]; 11098b9484cSchristos int status; 11198b9484cSchristos 11298b9484cSchristos CLEAR (buf); 11398b9484cSchristos status = checkit (buf, 10, "%s:%d", "foobar", 9); 11498b9484cSchristos VERIFY (status==8 && memcmp (buf, "foobar:9\0XXXXX\0", 15) == 0); 11598b9484cSchristos 11698b9484cSchristos CLEAR (buf); 11798b9484cSchristos status = checkit (buf, 9, "%s:%d", "foobar", 9); 11898b9484cSchristos VERIFY (status==8 && memcmp (buf, "foobar:9\0XXXXX\0", 15) == 0); 11998b9484cSchristos 12098b9484cSchristos CLEAR (buf); 12198b9484cSchristos status = checkit (buf, 8, "%s:%d", "foobar", 9); 12298b9484cSchristos VERIFY (status==8 && memcmp (buf, "foobar:\0XXXXXX\0", 15) == 0); 12398b9484cSchristos 12498b9484cSchristos CLEAR (buf); 12598b9484cSchristos status = checkit (buf, 7, "%s:%d", "foobar", 9); 12698b9484cSchristos VERIFY (status==8 && memcmp (buf, "foobar\0XXXXXXX\0", 15) == 0); 12798b9484cSchristos 12898b9484cSchristos CLEAR (buf); 12998b9484cSchristos status = checkit (buf, 6, "%s:%d", "foobar", 9); 13098b9484cSchristos VERIFY (status==8 && memcmp (buf, "fooba\0XXXXXXXX\0", 15) == 0); 13198b9484cSchristos 13298b9484cSchristos CLEAR (buf); 13398b9484cSchristos status = checkit (buf, 2, "%s:%d", "foobar", 9); 13498b9484cSchristos VERIFY (status==8 && memcmp (buf, "f\0XXXXXXXXXXXX\0", 15) == 0); 13598b9484cSchristos 13698b9484cSchristos CLEAR (buf); 13798b9484cSchristos status = checkit (buf, 1, "%s:%d", "foobar", 9); 13898b9484cSchristos VERIFY (status==8 && memcmp (buf, "\0XXXXXXXXXXXXX\0", 15) == 0); 13998b9484cSchristos 14098b9484cSchristos CLEAR (buf); 14198b9484cSchristos status = checkit (buf, 0, "%s:%d", "foobar", 9); 14298b9484cSchristos VERIFY (status==8 && memcmp (buf, "XXXXXXXXXXXXXX\0", 15) == 0); 14398b9484cSchristos 14498b9484cSchristos return 0; 14598b9484cSchristos } 14698b9484cSchristos #endif /* TEST */ 147