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