diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2005-02-23 15:09:34 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2005-02-23 15:09:34 +0000 |
commit | 2db5c7115e5b37734993603c0381aab7e62c4be9 (patch) | |
tree | 1be931195d1bf1c22bf9a5ca53b9cad9263be6bb /lib | |
parent | 96aac32803af5414ffeec13a16205d7c456df19d (diff) | |
download | mailutils-2db5c7115e5b37734993603c0381aab7e62c4be9.tar.gz mailutils-2db5c7115e5b37734993603c0381aab7e62c4be9.tar.bz2 |
Updated by gnulib-sync
Diffstat (limited to 'lib')
-rw-r--r-- | lib/setenv.c | 334 | ||||
-rw-r--r-- | lib/snprintf.c | 886 | ||||
-rw-r--r-- | lib/snprintf.h | 223 | ||||
-rw-r--r-- | lib/vasprintf.c | 208 | ||||
-rw-r--r-- | lib/xalloc.h | 94 | ||||
-rw-r--r-- | lib/xmalloc.c | 238 | ||||
-rw-r--r-- | lib/xstrtol.c | 163 | ||||
-rw-r--r-- | lib/xstrtol.h | 55 |
8 files changed, 680 insertions, 1521 deletions
diff --git a/lib/setenv.c b/lib/setenv.c index ba965faaa..320469b86 100644 --- a/lib/setenv.c +++ b/lib/setenv.c @@ -1,130 +1,276 @@ -/* Copyright (C) 1992, 1995, 1996, 1997, 2001 Free Software Foundation, Inc. - This file based on setenv.c in the GNU C Library. +/* Copyright (C) 1992,1995-1999,2000-2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. - The GNU C Library is distributed in the hope that it will be useful, + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #if HAVE_CONFIG_H # include <config.h> #endif +#include <alloca.h> #include <errno.h> - -#if HAVE_STDLIB_H -# include <stdlib.h> -#else -#include <sys/types.h> /* For `size_t' */ -#include <stdio.h> /* For `NULL' */ -#endif -#if HAVE_STRING_H -# include <string.h> +#ifndef __set_errno +# define __set_errno(ev) ((errno) = (ev)) #endif -#if HAVE_UNISTD_H + +#include <stdlib.h> +#include <string.h> +#if _LIBC || HAVE_UNISTD_H # include <unistd.h> #endif -#define __environ environ +#if !_LIBC +# include "allocsa.h" +#endif + +#if !_LIBC +# define __environ environ +# ifndef HAVE_ENVIRON_DECL extern char **environ; +# endif +#endif + +#if _LIBC +/* This lock protects against simultaneous modifications of `environ'. */ +# include <bits/libc-lock.h> +__libc_lock_define_initialized (static, envlock) +# define LOCK __libc_lock_lock (envlock) +# define UNLOCK __libc_lock_unlock (envlock) +#else +# define LOCK +# define UNLOCK +#endif + +/* In the GNU C library we must keep the namespace clean. */ +#ifdef _LIBC +# define setenv __setenv +# define clearenv __clearenv +# define tfind __tfind +# define tsearch __tsearch +#endif + +/* In the GNU C library implementation we try to be more clever and + allow arbitrarily many changes of the environment given that the used + values are from a small set. Outside glibc this will eat up all + memory after a while. */ +#if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \ + && defined __GNUC__) +# define USE_TSEARCH 1 +# include <search.h> +typedef int (*compar_fn_t) (const void *, const void *); + +/* This is a pointer to the root of the search tree with the known + values. */ +static void *known_values; -/* LOCK and UNLOCK are defined as no-ops. This makes the libiberty - * implementation MT-Unsafe. */ -#define LOCK -#define UNLOCK +# define KNOWN_VALUE(Str) \ + ({ \ + void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \ + value != NULL ? *(char **) value : NULL; \ + }) +# define STORE_VALUE(Str) \ + tsearch (Str, &known_values, (compar_fn_t) strcmp) + +#else +# undef USE_TSEARCH + +# define KNOWN_VALUE(Str) NULL +# define STORE_VALUE(Str) do { } while (0) + +#endif -/* Below this point, it's verbatim code from the glibc-2.0 implementation */ /* If this variable is not a null pointer we allocated the current environment. */ static char **last_environ; +/* This function is used by `setenv' and `putenv'. The difference between + the two functions is that for the former must create a new string which + is then placed in the environment, while the argument of `putenv' + must be used directly. This is all complicated by the fact that we try + to reuse values once generated for a `setenv' call since we can never + free the strings. */ int -setenv (name, value, replace) - const char *name; - const char *value; - int replace; +__add_to_environ (const char *name, const char *value, const char *combined, + int replace) { register char **ep; register size_t size; const size_t namelen = strlen (name); - const size_t vallen = strlen (value) + 1; + const size_t vallen = value != NULL ? strlen (value) + 1 : 0; LOCK; + /* We have to get the pointer now that we have the lock and not earlier + since another thread might have created a new environment. */ + ep = __environ; + size = 0; - if (__environ != NULL) - for (ep = __environ; *ep != NULL; ++ep) - if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') - break; - else - ++size; + if (ep != NULL) + { + for (; *ep != NULL; ++ep) + if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') + break; + else + ++size; + } - if (__environ == NULL || *ep == NULL) + if (ep == NULL || *ep == NULL) { char **new_environ; - if (__environ == last_environ && __environ != NULL) - /* We allocated this space; we can extend it. */ - new_environ = (char **) realloc (last_environ, - (size + 2) * sizeof (char *)); - else - new_environ = (char **) malloc ((size + 2) * sizeof (char *)); +#ifdef USE_TSEARCH + char *new_value; +#endif + /* We allocated this space; we can extend it. */ + new_environ = + (char **) (last_environ == NULL + ? malloc ((size + 2) * sizeof (char *)) + : realloc (last_environ, (size + 2) * sizeof (char *))); if (new_environ == NULL) { UNLOCK; return -1; } - new_environ[size] = malloc (namelen + 1 + vallen); - if (new_environ[size] == NULL) + /* If the whole entry is given add it. */ + if (combined != NULL) + /* We must not add the string to the search tree since it belongs + to the user. */ + new_environ[size] = (char *) combined; + else { - free ((char *) new_environ); - errno = ENOMEM; - UNLOCK; - return -1; + /* See whether the value is already known. */ +#ifdef USE_TSEARCH +# ifdef _LIBC + new_value = (char *) alloca (namelen + 1 + vallen); + __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), + value, vallen); +# else + new_value = (char *) allocsa (namelen + 1 + vallen); + if (new_value == NULL) + { + __set_errno (ENOMEM); + UNLOCK; + return -1; + } + memcpy (new_value, name, namelen); + new_value[namelen] = '='; + memcpy (&new_value[namelen + 1], value, vallen); +# endif + + new_environ[size] = KNOWN_VALUE (new_value); + if (new_environ[size] == NULL) +#endif + { + new_environ[size] = (char *) malloc (namelen + 1 + vallen); + if (new_environ[size] == NULL) + { +#if defined USE_TSEARCH && !defined _LIBC + freesa (new_value); +#endif + __set_errno (ENOMEM); + UNLOCK; + return -1; + } + +#ifdef USE_TSEARCH + memcpy (new_environ[size], new_value, namelen + 1 + vallen); +#else + memcpy (new_environ[size], name, namelen); + new_environ[size][namelen] = '='; + memcpy (&new_environ[size][namelen + 1], value, vallen); +#endif + /* And save the value now. We cannot do this when we remove + the string since then we cannot decide whether it is a + user string or not. */ + STORE_VALUE (new_environ[size]); + } +#if defined USE_TSEARCH && !defined _LIBC + freesa (new_value); +#endif } if (__environ != last_environ) memcpy ((char *) new_environ, (char *) __environ, size * sizeof (char *)); - memcpy (new_environ[size], name, namelen); - new_environ[size][namelen] = '='; - memcpy (&new_environ[size][namelen + 1], value, vallen); - new_environ[size + 1] = NULL; last_environ = __environ = new_environ; } else if (replace) { - size_t len = strlen (*ep); - if (len + 1 < namelen + 1 + vallen) + char *np; + + /* Use the user string if given. */ + if (combined != NULL) + np = (char *) combined; + else { - /* The existing string is too short; malloc a new one. */ - char *new = malloc (namelen + 1 + vallen); - if (new == NULL) +#ifdef USE_TSEARCH + char *new_value; +# ifdef _LIBC + new_value = alloca (namelen + 1 + vallen); + __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), + value, vallen); +# else + new_value = allocsa (namelen + 1 + vallen); + if (new_value == NULL) { + __set_errno (ENOMEM); UNLOCK; return -1; } - *ep = new; + memcpy (new_value, name, namelen); + new_value[namelen] = '='; + memcpy (&new_value[namelen + 1], value, vallen); +# endif + + np = KNOWN_VALUE (new_value); + if (np == NULL) +#endif + { + np = malloc (namelen + 1 + vallen); + if (np == NULL) + { +#if defined USE_TSEARCH && !defined _LIBC + freesa (new_value); +#endif + __set_errno (ENOMEM); + UNLOCK; + return -1; + } + +#ifdef USE_TSEARCH + memcpy (np, new_value, namelen + 1 + vallen); +#else + memcpy (np, name, namelen); + np[namelen] = '='; + memcpy (&np[namelen + 1], value, vallen); +#endif + /* And remember the value. */ + STORE_VALUE (np); + } +#if defined USE_TSEARCH && !defined _LIBC + freesa (new_value); +#endif } - memcpy (*ep, name, namelen); - (*ep)[namelen] = '='; - memcpy (&(*ep)[namelen + 1], value, vallen); + + *ep = np; } UNLOCK; @@ -132,25 +278,51 @@ setenv (name, value, replace) return 0; } -void -unsetenv (name) - const char *name; +int +setenv (const char *name, const char *value, int replace) { - const size_t len = strlen (name); - char **ep; + return __add_to_environ (name, value, NULL, replace); +} +/* The `clearenv' was planned to be added to POSIX.1 but probably + never made it. Nevertheless the POSIX.9 standard (POSIX bindings + for Fortran 77) requires this function. */ +int +clearenv (void) +{ LOCK; - for (ep = __environ; *ep; ++ep) - if (!strncmp (*ep, name, len) && (*ep)[len] == '=') - { - /* Found it. Remove this pointer by moving later ones back. */ - char **dp = ep; - do - dp[0] = dp[1]; - while (*dp++); - /* Continue the loop in case NAME appears again. */ - } + if (__environ == last_environ && __environ != NULL) + { + /* We allocated this environment so we can free it. */ + free (__environ); + last_environ = NULL; + } + + /* Clear the environment pointer removes the whole environment. */ + __environ = NULL; UNLOCK; + + return 0; +} + +#ifdef _LIBC +static void +free_mem (void) +{ + /* Remove all traces. */ + clearenv (); + + /* Now remove the search tree. */ + __tdestroy (known_values, free); + known_values = NULL; } +text_set_element (__libc_subfreeres, free_mem); + + +# undef setenv +# undef clearenv +weak_alias (__setenv, setenv) +weak_alias (__clearenv, clearenv) +#endif diff --git a/lib/snprintf.c b/lib/snprintf.c index 57ffb6c3a..9a4edc1f5 100644 --- a/lib/snprintf.c +++ b/lib/snprintf.c @@ -1,868 +1,60 @@ - -/* - Unix snprintf implementation. - Version 1.3 +/* Formatted output to strings. + Copyright (C) 2004 Free Software Foundation, Inc. + Written by Simon Josefsson. This program is free software; you can redistribute it and/or modify - it under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Revision History: - - 1.3: - * add #include <config.h> ifdef HAVE_CONFIG_H - * cosmetic change, when exponent is 0 print xxxE+00 - instead of xxxE-00 - 1.2: - * put the program under LGPL. - 1.1: - * added changes from Miles Bader - * corrected a bug with %f - * added support for %#g - * added more comments :-) - 1.0: - * supporting must ANSI syntaxic_sugars - 0.0: - * suppot %s %c %d - - THANKS(for the patches and ideas): - Miles Bader - Cyrille Rustom - Jacek Slabocewiz - Mike Parker(mouse) - -*/ - -#include "snprintf.h" - -/* - * Find the nth power of 10 - */ -PRIVATE double -#ifdef __STDC__ -pow_10(int n) -#else -pow_10(n) -int n; -#endif -{ - int i; - double P; - - if (n < 0) - for (i = 1, P = 1., n = -n ; i <= n ; i++) {P *= .1;} - else - for (i = 1, P = 1. ; i <= n ; i++) {P *= 10.0;} - return P; -} - -/* - * Find the integral part of the log in base 10 - * Note: this not a real log10() - I just need and approximation(integerpart) of x in: - 10^x ~= r - * log_10(200) = 2; - * log_10(250) = 2; - */ -PRIVATE int -#ifdef __STDC__ -log_10(double r) -#else -log_10(r) -double r; -#endif -{ - int i = 0; - double result = 1.; - - if (r < 0.) - r = -r; - - if (r < 1.) { - while (result >= r) {result *= .1; i++;} - return (-i); - } else { - while (result <= r) {result *= 10.; i++;} - return (i - 1); - } -} - -/* - * This function return the fraction part of a double - * and set in ip the integral part. - * In many ways it resemble the modf() found on most Un*x - */ -PRIVATE double -#ifdef __STDC__ -integral(double real, double * ip) -#else -integral(real, ip) -double real; -double * ip; -#endif -{ - int j; - double i, s, p; - double real_integral = 0.; - -/* take care of the obvious */ -/* equal to zero ? */ - if (real == 0.) { - *ip = 0.; - return (0.); - } - -/* negative number ? */ - if (real < 0.) - real = -real; - -/* a fraction ? */ - if ( real < 1.) { - *ip = 0.; - return real; - } -/* the real work :-) */ - for (j = log_10(real); j >= 0; j--) { - p = pow_10(j); - s = (real - real_integral)/p; - i = 0.; - while (i + 1. <= s) {i++;} - real_integral += i*p; - } - *ip = real_integral; - return (real - real_integral); -} - -#define PRECISION 1.e-6 -/* - * return an ascii representation of the integral part of the number - * and set fract to be an ascii representation of the fraction part - * the container for the fraction and the integral part or staticly - * declare with fix size - */ -PRIVATE char * -#ifdef __STDC__ -numtoa(double number, int base, int precision, char ** fract) -#else -numtoa(number, base, precision, fract) -double number; -int base; -int precision; -char ** fract; -#endif -{ - register int i, j; - double ip, fp; /* integer and fraction part */ - double fraction; - int digits = MAX_INT - 1; - static char integral_part[MAX_INT]; - static char fraction_part[MAX_FRACT]; - double sign; - int ch; - -/* taking care of the obvious case: 0.0 */ - if (number == 0.) { - integral_part[0] = '0'; - integral_part[1] = '\0'; - fraction_part[0] = '0'; - fraction_part[1] = '\0'; - return integral_part; - } - -/* for negative numbers */ - if ((sign = number) < 0.) { - number = -number; - digits--; /* sign consume one digit */ - } - - fraction = integral(number, &ip); - number = ip; -/* do the integral part */ - if ( ip == 0.) { - integral_part[0] = '0'; - i = 1; - } else { - for ( i = 0; i < digits && number != 0.; ++i) { - number /= base; - fp = integral(number, &ip); - ch = (int)((fp + PRECISION)*base); /* force to round */ - integral_part[i] = (ch <= 9) ? ch + '0' : ch + 'a' - 10; - if (! isxdigit(integral_part[i])) /* bail out overflow !! */ - break; - number = ip; - } - } - -/* Oh No !! out of bound, ho well fill it up ! */ - if (number != 0.) - for (i = 0; i < digits; ++i) - integral_part[i] = '9'; + GNU General Public License for more details. -/* put the sign ? */ - if (sign < 0.) - integral_part[i++] = '-'; + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - integral_part[i] = '\0'; - -/* reverse every thing */ - for ( i--, j = 0; j < i; j++, i--) - SWAP_INT(integral_part[i], integral_part[j]); - -/* the fractionnal part */ - for (i=0, fp=fraction; precision > 0 && i < MAX_FRACT ; i++, precision-- ) { - fraction_part[i] = (int)((fp + PRECISION)*10. + '0'); - if (! isdigit(fraction_part[i])) /* underflow ? */ - break; - fp = (fp*10.0) - (double)(long)((fp + PRECISION)*10.); - } - fraction_part[i] = '\0'; - - if (fract != (char **)0) - *fract = fraction_part; - - return integral_part; - -} - -/* for %d and friends, it puts in holder - * the representation with the right padding - */ -PRIVATE void -#ifdef __STDC__ -decimal(struct DATA *p, double d) -#else -decimal(p, d) -struct DATA *p; -double d; +#ifdef HAVE_CONFIG_H +# include <config.h> #endif -{ - char *tmp; - tmp = itoa(d); - p->width -= strlen(tmp); - PAD_RIGHT(p); - PUT_PLUS(d, p); - PUT_SPACE(d, p); - while (*tmp) { /* the integral */ - PUT_CHAR(*tmp, p); - tmp++; - } - PAD_LEFT(p); -} - -/* for %o octal representation */ -PRIVATE void -#ifdef __STDC__ -octal(struct DATA *p, double d) -#else -octal(p, d) -struct DATA *p; -double d; -#endif -{ - char *tmp; - - tmp = otoa(d); - p->width -= strlen(tmp); - PAD_RIGHT(p); - if (p->square == FOUND) /* had prefix '0' for octal */ - PUT_CHAR('0', p); - while (*tmp) { /* octal */ - PUT_CHAR(*tmp, p); - tmp++; - } - PAD_LEFT(p); -} - -/* for %x %X hexadecimal representation */ -PRIVATE void -#ifdef __STDC__ -hexa(struct DATA *p, double d) -#else -hexa(p, d) -struct DATA *p; -double d; -#endif -{ - char *tmp; - - tmp = htoa(d); - p->width -= strlen(tmp); - PAD_RIGHT(p); - if (p->square == FOUND) { /* prefix '0x' for hexa */ - PUT_CHAR('0', p); PUT_CHAR(*p->pf, p); - } - while (*tmp) { /* hexa */ - PUT_CHAR((*p->pf == 'X' ? toupper(*tmp) : *tmp), p); - tmp++; - } - PAD_LEFT(p); -} - -/* %s strings */ -PRIVATE void -#ifdef __STDC__ -strings(struct DATA *p, char *tmp) -#else -strings(p, tmp) -struct DATA *p; -char *tmp; -#endif -{ - int i; - - i = strlen(tmp); - if (p->precision != NOT_FOUND) /* the smallest number */ - i = (i < p->precision ? i : p->precision); - p->width -= i; - PAD_RIGHT(p); - while (i-- > 0) { /* put the sting */ - PUT_CHAR(*tmp, p); - tmp++; - } - PAD_LEFT(p); -} - -/* %f or %g floating point representation */ -PRIVATE void -#ifdef __STDC__ -floating(struct DATA *p, double d) -#else -floating(p, d) -struct DATA *p; -double d; -#endif -{ - char *tmp, *tmp2; - int i; - - DEF_PREC(p); - d = ROUND(d, p); - tmp = dtoa(d, p->precision, &tmp2); - /* calculate the padding. 1 for the dot */ - p->width = p->width - - ((d > 0. && p->justify == RIGHT) ? 1:0) - - ((p->space == FOUND) ? 1:0) - - strlen(tmp) - p->precision - 1; - PAD_RIGHT(p); - PUT_PLUS(d, p); - PUT_SPACE(d, p); - while (*tmp) { /* the integral */ - PUT_CHAR(*tmp, p); - tmp++; - } - if (p->precision != 0 || p->square == FOUND) - PUT_CHAR('.', p); /* put the '.' */ - if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */ - for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--) - tmp2[i] = '\0'; - for (; *tmp2; tmp2++) - PUT_CHAR(*tmp2, p); /* the fraction */ - - PAD_LEFT(p); -} - -/* %e %E %g exponent representation */ -PRIVATE void -#ifdef __STDC__ -exponent(struct DATA *p, double d) -#else -exponent(p, d) -struct DATA *p; -double d; -#endif -{ - char *tmp, *tmp2; - int j, i; - - DEF_PREC(p); - j = log_10(d); - d = d / pow_10(j); /* get the Mantissa */ - d = ROUND(d, p); - tmp = dtoa(d, p->precision, &tmp2); - /* 1 for unit, 1 for the '.', 1 for 'e|E', - * 1 for '+|-', 3 for 'exp' */ - /* calculate how much padding need */ - p->width = p->width - - ((d > 0. && p->justify == RIGHT) ? 1:0) - - ((p->space == FOUND) ? 1:0) - p->precision - 7; - PAD_RIGHT(p); - PUT_PLUS(d, p); - PUT_SPACE(d, p); - while (*tmp) {/* the integral */ - PUT_CHAR(*tmp, p); - tmp++; - } - if (p->precision != 0 || p->square == FOUND) - PUT_CHAR('.', p); /* the '.' */ - if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */ - for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--) - tmp2[i] = '\0'; - for (; *tmp2; tmp2++) - PUT_CHAR(*tmp2, p); /* the fraction */ - - if (*p->pf == 'g' || *p->pf == 'e') { /* the exponent put the 'e|E' */ - PUT_CHAR('e', p); - } else - PUT_CHAR('E', p); - if (j >= 0) { /* the sign of the exp */ - PUT_CHAR('+', p); - } else { - PUT_CHAR('-', p); - j = -j; - } - tmp = itoa((double)j); - if (j < 9) { /* need to pad the exponent with 0 '000' */ - PUT_CHAR('0', p); PUT_CHAR('0', p); - } else if (j < 99) - PUT_CHAR('0', p); - while (*tmp) { /* the exponent */ - PUT_CHAR(*tmp, p); - tmp++; - } - PAD_LEFT(p); -} - -/* initialize the conversion specifiers */ -PRIVATE void -#ifdef __STDC__ -conv_flag(char * s, struct DATA * p) -#else -conv_flag(s, p) -char * s; -struct DATA * p; -#endif -{ - char number[MAX_FIELD/2]; - int i; - - /* reset the flags. */ - p->precision = p->width = NOT_FOUND; - p->star_w = p->star_p = NOT_FOUND; - p->square = p->space = NOT_FOUND; - p->a_long = p->justify = NOT_FOUND; - p->a_longlong = NOT_FOUND; - p->pad = ' '; - - for(;s && *s ;s++) { - switch(*s) { - case ' ': p->space = FOUND; break; - case '#': p->square = FOUND; break; - case '*': if (p->width == NOT_FOUND) - p->width = p->star_w = FOUND; - else - p->precision = p->star_p = FOUND; - break; - case '+': p->justify = RIGHT; break; - case '-': p->justify = LEFT; break; - case '.': if (p->width == NOT_FOUND) - p->width = 0; - break; - case '0': p->pad = '0'; break; - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': /* gob all the digits */ - for (i = 0; isdigit(*s); i++, s++) - if (i < MAX_FIELD/2 - 1) - number[i] = *s; - number[i] = '\0'; - if (p->width == NOT_FOUND) - p->width = atoi(number); - else - p->precision = atoi(number); - s--; /* went to far go back */ - break; - } - } -} - -PUBLIC int -#ifdef __STDC__ -vsnprintf(char *string, size_t length, const char * format, va_list args) -#else -vsnprintf(string, length, format, args) -char *string; -size_t length; -char * format; -va_list args; -#endif -{ - struct DATA data; - char conv_field[MAX_FIELD]; - double d; /* temporary holder */ - int state; - int i; - - data.length = length - 1; /* leave room for '\0' */ - data.holder = string; - data.pf = format; - data.counter = 0; - - -/* sanity check, the string must be > 1 */ - if (length < 1) - return -1; - - - for (; *data.pf && (data.counter < data.length); data.pf++) { - if ( *data.pf == '%' ) { /* we got a magic % cookie */ - conv_flag((char *)0, &data); /* initialise format flags */ - for (state = 1; *data.pf && state;) { - switch (*(++data.pf)) { - case '\0': /* a NULL here ? ? bail out */ - *data.holder = '\0'; - return data.counter; - break; - case 'f': /* float, double */ - STAR_ARGS(&data); - if (data.a_long == FOUND) - d = va_arg(args, LONG_DOUBLE); - else - d = va_arg(args, double); - floating(&data, d); - state = 0; - break; - case 'g': - case 'G': - STAR_ARGS(&data); - DEF_PREC(&data); - if (data.a_long == FOUND) - d = va_arg(args, LONG_DOUBLE); - else - d = va_arg(args, double); - i = log_10(d); - /* - * for '%g|%G' ANSI: use f if exponent - * is in the range or [-4,p] exclusively - * else use %e|%E - */ - if (-4 < i && i < data.precision) - floating(&data, d); - else - exponent(&data, d); - state = 0; - break; - case 'e': - case 'E': /* Exponent double */ - STAR_ARGS(&data); - if (data.a_long == FOUND) - d = va_arg(args, LONG_DOUBLE); - else - d = va_arg(args, double); - exponent(&data, d); - state = 0; - break; - case 'u': /* unsigned decimal */ - STAR_ARGS(&data); - if (data.a_longlong == FOUND) - d = va_arg(args, unsigned LONG_LONG); - else if (data.a_long == FOUND) - d = va_arg(args, unsigned long); - else - d = va_arg(args, unsigned int); - decimal(&data, d); - state = 0; - break; - case 'd': /* decimal */ - STAR_ARGS(&data); - if (data.a_longlong == FOUND) - d = va_arg(args, LONG_LONG); - else if (data.a_long == FOUND) - d = va_arg(args, long); - else - d = va_arg(args, int); - decimal(&data, d); - state = 0; - break; - case 'o': /* octal */ - STAR_ARGS(&data); - if (data.a_longlong == FOUND) - d = va_arg(args, LONG_LONG); - else if (data.a_long == FOUND) - d = va_arg(args, long); - else - d = va_arg(args, int); - octal(&data, d); - state = 0; - break; - case 'x': - case 'X': /* hexadecimal */ - STAR_ARGS(&data); - if (data.a_longlong == FOUND) - d = va_arg(args, LONG_LONG); - else if (data.a_long == FOUND) - d = va_arg(args, long); - else - d = va_arg(args, int); - hexa(&data, d); - state = 0; - break; - case 'c': /* character */ - d = va_arg(args, int); - PUT_CHAR(d, &data); - state = 0; - break; - case 's': /* string */ - STAR_ARGS(&data); - strings(&data, va_arg(args, char *)); - state = 0; - break; - case 'n': - *(va_arg(args, int *)) = data.counter; /* what's the count ? */ - state = 0; - break; - case 'q': - data.a_longlong = FOUND; - break; - case 'L': - case 'l': - if (data.a_long == FOUND) - data.a_longlong = FOUND; - else - data.a_long = FOUND; - break; - case 'h': - break; - case '%': /* nothing just % */ - PUT_CHAR('%', &data); - state = 0; - break; - case '#': case ' ': case '+': case '*': - case '-': case '.': case '0': case '1': - case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - /* initialize width and precision */ - for (i = 0; isflag(*data.pf); i++, data.pf++) - if (i < MAX_FIELD - 1) - conv_field[i] = *data.pf; - conv_field[i] = '\0'; - conv_flag(conv_field, &data); - data.pf--; /* went to far go back */ - break; - default: - /* is this an error ? maybe bail out */ - state = 0; - break; - } /* end switch */ - } /* end of for state */ - } else { /* not % */ - PUT_CHAR(*data.pf, &data); /* add the char the string */ - } - } - - *data.holder = '\0'; /* the end ye ! */ +#include "snprintf.h" - return data.counter; -} +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> -#ifndef HAVE_SNPRINTF +#include "minmax.h" +#include "vasnprintf.h" -PUBLIC int -#if __STDC__ -snprintf(char *string, size_t length, const char * format, ...) -#else -snprintf(string, length, format, va_alist) -char *string; -size_t length; -char * format; -va_dcl -#endif +/* Print formatted output to string STR. Similar to sprintf, but + additional length SIZE limit how much is written into STR. Returns + string length of formatted string (which may be larger than SIZE). + STR may be NULL, in which case nothing will be written. On error, + return a negative value. */ +int +snprintf (char *str, size_t size, const char *format, ...) { - int rval; + char *output; + size_t len; va_list args; -#if __STDC__ - va_start(a |