xref: /netbsd-src/external/gpl3/gdb/dist/libiberty/vsnprintf.c (revision 5173eb0a33e5d83890ba976253e703be4c92557c)
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