197785Spdeuskar/* Implement the vsnprintf function.
2170141Sjfv   Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
3170141Sjfv   Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>.
497785Spdeuskar
5170141SjfvThis file is part of the libiberty library.  This library is free
697785Spdeuskarsoftware; you can redistribute it and/or modify it under the
797785Spdeuskarterms of the GNU General Public License as published by the
897785SpdeuskarFree Software Foundation; either version 2, or (at your option)
997785Spdeuskarany later version.
1097785Spdeuskar
11112472SpdeuskarThis library is distributed in the hope that it will be useful,
12146663Stackermanbut WITHOUT ANY WARRANTY; without even the implied warranty of
1397785SpdeuskarMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1497785SpdeuskarGNU General Public License for more details.
1597785Spdeuskar
1697785SpdeuskarYou should have received a copy of the GNU General Public License
1797785Spdeuskaralong with GNU CC; see the file COPYING.  If not, write to
1897785Spdeuskarthe Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
1997785Spdeuskar
2097785SpdeuskarAs a special exception, if you link this library with files
21112472Spdeuskarcompiled with a GNU compiler to produce an executable, this does not cause
22112472Spdeuskarthe resulting executable to be covered by the GNU General Public License.
2397785SpdeuskarThis exception does not however invalidate any other reasons why
24170141Sjfvthe executable file might be covered by the GNU General Public License. */
25170141Sjfv
2697785Spdeuskar/*
27146663Stackerman
28169240Sjfv@deftypefn Supplemental int vsnprintf (char *@var{buf}, size_t @var{n}, const char *@var{format}, va_list @var{ap})
2997785Spdeuskar
3097785SpdeuskarThis function is similar to vsprintf, but it will print at most
3197785Spdeuskar@var{n} characters.  On error the return value is -1, otherwise it
32146663Stackermanreturns the number of characters that would have been printed had
33146663Stackerman@var{n} been sufficiently large, regardless of the actual value of
3497785Spdeuskar@var{n}.  Note some pre-C99 system libraries do not implement this
35146663Stackermancorrectly so users cannot generally rely on the return value if the
36146663Stackermansystem version of this function is used.
3797785Spdeuskar
38157566Sglebius@end deftypefn
3997785Spdeuskar
4097785Spdeuskar*/
41146663Stackerman
4297785Spdeuskar#include "config.h"
43157566Sglebius#include "ansidecl.h"
4497785Spdeuskar
4597785Spdeuskar#include <stdarg.h>
46146663Stackerman#ifdef HAVE_STRING_H
47160949Sglebius#include <string.h>
48160949Sglebius#endif
4997785Spdeuskar#ifdef HAVE_STDLIB_H
5097785Spdeuskar#include <stdlib.h>
5197785Spdeuskar#endif
5297785Spdeuskar
53146663Stackerman#include "libiberty.h"
54146663Stackerman
55112472Spdeuskar/* This implementation relies on a working vasprintf.  */
5697785Spdeuskarint
57146663Stackermanvsnprintf (char *s, size_t n, const char *format, va_list ap)
58112472Spdeuskar{
5997785Spdeuskar  char *buf = 0;
60146663Stackerman  int result = vasprintf (&buf, format, ap);
6197785Spdeuskar
6297785Spdeuskar  if (!buf)
6397785Spdeuskar    return -1;
6497785Spdeuskar  if (result < 0)
65169240Sjfv    {
6697785Spdeuskar      free (buf);
67112472Spdeuskar      return -1;
6897785Spdeuskar    }
69146663Stackerman
70112472Spdeuskar  result = strlen (buf);
7197785Spdeuskar  if (n > 0)
72146663Stackerman    {
7397785Spdeuskar      if ((long) n > result)
74146663Stackerman	memcpy (s, buf, result+1);
75146663Stackerman      else
7697785Spdeuskar        {
77169240Sjfv	  memcpy (s, buf, n-1);
7897785Spdeuskar	  s[n - 1] = 0;
79146663Stackerman	}
8097785Spdeuskar    }
81146663Stackerman  free (buf);
8297785Spdeuskar  return result;
83146663Stackerman}
84146663Stackerman
85146663Stackerman#ifdef TEST
86146663Stackerman/* Set the buffer to a known state.  */
87169240Sjfv#define CLEAR(BUF) do { memset ((BUF), 'X', sizeof (BUF)); (BUF)[14] = '\0'; } while (0)
8897785Spdeuskar/* For assertions.  */
89112472Spdeuskar#define VERIFY(P) do { if (!(P)) abort(); } while (0)
90169240Sjfv
9197785Spdeuskarstatic int ATTRIBUTE_PRINTF_3
92169240Sjfvcheckit (char *s, size_t n, const char *format, ...)
93169240Sjfv{
9497785Spdeuskar  int result;
95112472Spdeuskar  VA_OPEN (ap, format);
9697785Spdeuskar  VA_FIXEDARG (ap, char *, s);
97169240Sjfv  VA_FIXEDARG (ap, size_t, n);
98169240Sjfv  VA_FIXEDARG (ap, const char *, format);
99169240Sjfv  result = vsnprintf (s, n, format, ap);
10097785Spdeuskar  VA_CLOSE (ap);
101112472Spdeuskar  return result;
10297785Spdeuskar}
103112472Spdeuskar
10497785Spdeuskarextern int main (void);
105112472Spdeuskarint
106112472Spdeuskarmain (void)
107112472Spdeuskar{
10897785Spdeuskar  char buf[128];
109112472Spdeuskar  int status;
11097785Spdeuskar
111146663Stackerman  CLEAR (buf);
112146663Stackerman  status = checkit (buf, 10, "%s:%d", "foobar", 9);
11397785Spdeuskar  VERIFY (status==8 && memcmp (buf, "foobar:9\0XXXXX\0", 15) == 0);
114112472Spdeuskar
115112472Spdeuskar  CLEAR (buf);
116112472Spdeuskar  status = checkit (buf, 9, "%s:%d", "foobar", 9);
117112472Spdeuskar  VERIFY (status==8 && memcmp (buf, "foobar:9\0XXXXX\0", 15) == 0);
118112472Spdeuskar
119112472Spdeuskar  CLEAR (buf);
120112472Spdeuskar  status = checkit (buf, 8, "%s:%d", "foobar", 9);
121112472Spdeuskar  VERIFY (status==8 && memcmp (buf, "foobar:\0XXXXXX\0", 15) == 0);
122112472Spdeuskar
12397785Spdeuskar  CLEAR (buf);
12497785Spdeuskar  status = checkit (buf, 7, "%s:%d", "foobar", 9);
12597785Spdeuskar  VERIFY (status==8 && memcmp (buf, "foobar\0XXXXXXX\0", 15) == 0);
126146663Stackerman
127146663Stackerman  CLEAR (buf);
12897785Spdeuskar  status = checkit (buf, 6, "%s:%d", "foobar", 9);
12997785Spdeuskar  VERIFY (status==8 && memcmp (buf, "fooba\0XXXXXXXX\0", 15) == 0);
130146663Stackerman
13197785Spdeuskar  CLEAR (buf);
13297785Spdeuskar  status = checkit (buf, 2, "%s:%d", "foobar", 9);
133146663Stackerman  VERIFY (status==8 && memcmp (buf, "f\0XXXXXXXXXXXX\0", 15) == 0);
134146663Stackerman
13597785Spdeuskar  CLEAR (buf);
13697785Spdeuskar  status = checkit (buf, 1, "%s:%d", "foobar", 9);
137169240Sjfv  VERIFY (status==8 && memcmp (buf, "\0XXXXXXXXXXXXX\0", 15) == 0);
138169240Sjfv
13997785Spdeuskar  CLEAR (buf);
140169240Sjfv  status = checkit (buf, 0, "%s:%d", "foobar", 9);
141169240Sjfv  VERIFY (status==8 && memcmp (buf, "XXXXXXXXXXXXXX\0", 15) == 0);
142169240Sjfv
143169240Sjfv  return 0;
14497785Spdeuskar}
14597785Spdeuskar#endif /* TEST */
14697785Spdeuskar