diff options
Diffstat (limited to 'gnu')
-rw-r--r-- | gnu/lib/libiberty/src/lrealpath.c | 128 | ||||
-rw-r--r-- | gnu/lib/libiberty/src/make-relative-prefix.c | 55 | ||||
-rw-r--r-- | gnu/lib/libiberty/src/mempcpy.c | 48 | ||||
-rw-r--r-- | gnu/lib/libiberty/src/pex-common.h | 42 | ||||
-rw-r--r-- | gnu/lib/libiberty/src/pex-djgpp.c | 103 | ||||
-rw-r--r-- | gnu/lib/libiberty/src/pex-mpw.c | 161 | ||||
-rw-r--r-- | gnu/lib/libiberty/src/pex-msdos.c | 147 | ||||
-rw-r--r-- | gnu/lib/libiberty/src/pex-os2.c | 72 | ||||
-rw-r--r-- | gnu/lib/libiberty/src/pex-unix.c | 166 | ||||
-rw-r--r-- | gnu/lib/libiberty/src/pex-win32.c | 243 | ||||
-rw-r--r-- | gnu/lib/libiberty/src/pexecute.txh | 63 | ||||
-rw-r--r-- | gnu/lib/libiberty/src/snprintf.c | 65 | ||||
-rw-r--r-- | gnu/lib/libiberty/src/stpcpy.c | 49 | ||||
-rw-r--r-- | gnu/lib/libiberty/src/stpncpy.c | 54 | ||||
-rw-r--r-- | gnu/lib/libiberty/src/vsnprintf.c | 153 |
15 files changed, 1525 insertions, 24 deletions
diff --git a/gnu/lib/libiberty/src/lrealpath.c b/gnu/lib/libiberty/src/lrealpath.c new file mode 100644 index 00000000000..b001b38ef66 --- /dev/null +++ b/gnu/lib/libiberty/src/lrealpath.c @@ -0,0 +1,128 @@ +/* Libiberty realpath. Like realpath, but more consistent behavior. + Based on gdb_realpath from GDB. + + Copyright 2003 Free Software Foundation, Inc. + + This file is part of the libiberty library. + + 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 of the License, 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 General Public License for more details. + + 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. */ + +/* + +@deftypefn Replacement {const char*} lrealpath (const char *@var{name}) + +Given a pointer to a string containing a pathname, returns a canonical +version of the filename. Symlinks will be resolved, and ``.'' and ``..'' +components will be simplified. The returned value will be allocated using +@code{malloc}, or @code{NULL} will be returned on a memory allocation error. + +@end deftypefn + +*/ + +#include "config.h" +#include "ansidecl.h" +#include "libiberty.h" + +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +/* On GNU libc systems the declaration is only visible with _GNU_SOURCE. */ +#if defined(HAVE_CANONICALIZE_FILE_NAME) \ + && defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME) +extern char *canonicalize_file_name (const char *); +#endif + +#if defined(HAVE_REALPATH) +# if defined (PATH_MAX) +# define REALPATH_LIMIT PATH_MAX +# else +# if defined (MAXPATHLEN) +# define REALPATH_LIMIT MAXPATHLEN +# endif +# endif +#endif + +char * +lrealpath (filename) + const char *filename; +{ + /* Method 1: The system has a compile time upper bound on a filename + path. Use that and realpath() to canonicalize the name. This is + the most common case. Note that, if there isn't a compile time + upper bound, you want to avoid realpath() at all costs. */ +#if defined(REALPATH_LIMIT) + { + char buf[REALPATH_LIMIT]; + const char *rp = realpath (filename, buf); + if (rp == NULL) + rp = filename; + return strdup (rp); + } +#endif /* REALPATH_LIMIT */ + + /* Method 2: The host system (i.e., GNU) has the function + canonicalize_file_name() which malloc's a chunk of memory and + returns that, use that. */ +#if defined(HAVE_CANONICALIZE_FILE_NAME) + { + char *rp = canonicalize_file_name (filename); + if (rp == NULL) + return strdup (filename); + else + return rp; + } +#endif + + /* Method 3: Now we're getting desperate! The system doesn't have a + compile time buffer size and no alternative function. Query the + OS, using pathconf(), for the buffer limit. Care is needed + though, some systems do not limit PATH_MAX (return -1 for + pathconf()) making it impossible to pass a correctly sized buffer + to realpath() (it could always overflow). On those systems, we + skip this. */ +#if defined (HAVE_REALPATH) && defined (HAVE_UNISTD_H) + { + /* Find out the max path size. */ + long path_max = pathconf ("/", _PC_PATH_MAX); + if (path_max > 0) + { + /* PATH_MAX is bounded. */ + char *buf, *rp, *ret; + buf = malloc (path_max); + if (buf == NULL) + return NULL; + rp = realpath (filename, buf); + ret = strdup (rp ? rp : filename); + free (buf); + return ret; + } + } +#endif + + /* This system is a lost cause, just duplicate the filename. */ + return strdup (filename); +} diff --git a/gnu/lib/libiberty/src/make-relative-prefix.c b/gnu/lib/libiberty/src/make-relative-prefix.c index c208cdce024..dc4f8d5259d 100644 --- a/gnu/lib/libiberty/src/make-relative-prefix.c +++ b/gnu/lib/libiberty/src/make-relative-prefix.c @@ -23,16 +23,25 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA @deftypefn Extension {const char*} make_relative_prefix (const char *@var{progname}, const char *@var{bin_prefix}, const char *@var{prefix}) -Given three strings @var{progname}, @var{bin_prefix}, @var{prefix}, return a string -that gets to @var{prefix} starting with the directory portion of @var{progname} and -a relative pathname of the difference between @var{bin_prefix} and @var{prefix}. - -For example, if @var{bin_prefix} is @code{/alpha/beta/gamma/gcc/delta}, @var{prefix} -is @code{/alpha/beta/gamma/omega/}, and @var{progname} is @code{/red/green/blue/gcc}, -then this function will return @code{/red/green/blue/../../omega/}. - -The return value is normally allocated via @code{malloc}. If no relative prefix -can be found, return @code{NULL}. +Given three paths @var{progname}, @var{bin_prefix}, @var{prefix}, +return the path that is in the same position relative to +@var{progname}'s directory as @var{prefix} is relative to +@var{bin_prefix}. That is, a string starting with the directory +portion of @var{progname}, followed by a relative pathname of the +difference between @var{bin_prefix} and @var{prefix}. + +If @var{progname} does not contain any directory separators, +@code{make_relative_prefix} will search @env{PATH} to find a program +named @var{progname}. Also, if @var{progname} is a symbolic link, +the symbolic link will be resolved. + +For example, if @var{bin_prefix} is @code{/alpha/beta/gamma/gcc/delta}, +@var{prefix} is @code{/alpha/beta/gamma/omega/}, and @var{progname} is +@code{/red/green/blue/gcc}, then this function will return +@code{/red/green/blue/../../omega/}. + +The return value is normally allocated via @code{malloc}. If no +relative prefix can be found, return @code{NULL}. @end deftypefn @@ -223,19 +232,14 @@ make_relative_prefix (progname, bin_prefix, prefix) int prog_num, bin_num, prefix_num; int i, n, common; int needed_len; - char *ret, *ptr; + char *ret, *ptr, *full_progname = NULL; if (progname == NULL || bin_prefix == NULL || prefix == NULL) return NULL; - prog_dirs = split_directories (progname, &prog_num); - bin_dirs = split_directories (bin_prefix, &bin_num); - if (bin_dirs == NULL || prog_dirs == NULL) - return NULL; - /* If there is no full pathname, try to find the program by checking in each of the directories specified in the PATH environment variable. */ - if (prog_num == 1) + if (lbasename (progname) == progname) { char *temp; @@ -278,14 +282,7 @@ make_relative_prefix (progname, bin_prefix, prefix) #endif ) { - free_split_directories (prog_dirs); progname = nstore; - prog_dirs = split_directories (progname, &prog_num); - if (prog_dirs == NULL) - { - free_split_directories (bin_dirs); - return NULL; - } break; } @@ -299,6 +296,16 @@ make_relative_prefix (progname, bin_prefix, prefix) } } + full_progname = lrealpath (progname); + if (full_progname == NULL) + return NULL; + + prog_dirs = split_directories (full_progname, &prog_num); + bin_dirs = split_directories (bin_prefix, &bin_num); + free (full_progname); + if (bin_dirs == NULL || prog_dirs == NULL) + return NULL; + /* Remove the program name from comparison of directory names. */ prog_num--; diff --git a/gnu/lib/libiberty/src/mempcpy.c b/gnu/lib/libiberty/src/mempcpy.c new file mode 100644 index 00000000000..b0dccfa6167 --- /dev/null +++ b/gnu/lib/libiberty/src/mempcpy.c @@ -0,0 +1,48 @@ +/* Implement the mempcpy function. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>. + +This file is part of the libiberty library. +Libiberty 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. + +Libiberty 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 libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* + +@deftypefn Supplemental void* mempcpy (void *@var{out}, const void *@var{in}, size_t @var{length}) + +Copies @var{length} bytes from memory region @var{in} to region +@var{out}. Returns a pointer to @var{out} + @var{length}. + +@end deftypefn + +*/ + +#include <ansidecl.h> +#ifdef ANSI_PROTOTYPES +#include <stddef.h> +#else +#define size_t unsigned long +#endif + +extern PTR memcpy PARAMS ((PTR, const PTR, size_t)); + +PTR +mempcpy (dst, src, len) + PTR dst; + const PTR src; + size_t len; +{ + return (char *) memcpy (dst, src, len) + len; +} diff --git a/gnu/lib/libiberty/src/pex-common.h b/gnu/lib/libiberty/src/pex-common.h new file mode 100644 index 00000000000..da2f71e1247 --- /dev/null +++ b/gnu/lib/libiberty/src/pex-common.h @@ -0,0 +1,42 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. Shared logic. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003 + Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty 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. + +Libiberty 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 libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef PEX_COMMON_H +#define PEX_COMMON_H + +#include "config.h" +#include "libiberty.h" + +#define install_error_msg "installation problem, cannot exec `%s'" + +/* stdin file number. */ +#define STDIN_FILE_NO 0 + +/* stdout file number. */ +#define STDOUT_FILE_NO 1 + +/* value of `pipe': port index for reading. */ +#define READ_PORT 0 + +/* value of `pipe': port index for writing. */ +#define WRITE_PORT 1 + +#endif diff --git a/gnu/lib/libiberty/src/pex-djgpp.c b/gnu/lib/libiberty/src/pex-djgpp.c new file mode 100644 index 00000000000..968e7841215 --- /dev/null +++ b/gnu/lib/libiberty/src/pex-djgpp.c @@ -0,0 +1,103 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. DJGPP specialization. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003 + Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty 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. + +Libiberty 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 libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "pex-common.h" + +#include <stdio.h> +#include <errno.h> +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <process.h> + +/* Use ECHILD if available, otherwise use EINVAL. */ +#ifdef ECHILD +#define PWAIT_ERROR ECHILD +#else +#define PWAIT_ERROR EINVAL +#endif + +/* MSDOS doesn't multitask, but for the sake of a consistent interface + the code behaves like it does. pexecute runs the program, tucks the + exit code away, and returns a "pid". pwait must be called to fetch the + exit code. */ + +/* For communicating information from pexecute to pwait. */ +static int last_pid = 0; +static int last_status = 0; +static int last_reaped = 0; + +int +pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags) + const char *program; + char * const *argv; + const char *this_pname; + const char *temp_base; + char **errmsg_fmt, **errmsg_arg; + int flags; +{ + int rc; + + last_pid++; + if (last_pid < 0) + last_pid = 1; + + if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE) + abort (); + + /* ??? What are the possible return values from spawnv? */ + rc = (flags & PEXECUTE_SEARCH ? spawnvp : spawnv) (P_WAIT, program, argv); + + if (rc == -1) + { + *errmsg_fmt = install_error_msg; + *errmsg_arg = (char *)program; + return -1; + } + + /* Tuck the status away for pwait, and return a "pid". */ + last_status = rc << 8; + return last_pid; +} + +int +pwait (pid, status, flags) + int pid; + int *status; + int flags; +{ + /* On MSDOS each pexecute must be followed by its associated pwait. */ + if (pid != last_pid + /* Called twice for the same child? */ + || pid == last_reaped) + { + errno = PWAIT_ERROR; + return -1; + } + /* ??? Here's an opportunity to canonicalize the values in STATUS. + Needed? */ + *status = (last_status >> 8); + last_reaped = last_pid; + return last_pid; +} diff --git a/gnu/lib/libiberty/src/pex-mpw.c b/gnu/lib/libiberty/src/pex-mpw.c new file mode 100644 index 00000000000..9a8879c9b27 --- /dev/null +++ b/gnu/lib/libiberty/src/pex-mpw.c @@ -0,0 +1,161 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. MPW specialization. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003 + Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty 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. + +Libiberty 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 libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "pex-common.h" + +#include <stdio.h> +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +/* MPW pexecute doesn't actually run anything; instead, it writes out + script commands that, when run, will do the actual executing. + + For example, in GCC's case, GCC will write out several script commands: + + cpp ... + cc1 ... + as ... + ld ... + + and then exit. None of the above programs will have run yet. The task + that called GCC will then execute the script and cause cpp,etc. to run. + The caller must invoke pfinish before calling exit. This adds + the finishing touches to the generated script. */ + +static int first_time = 1; + +extern void mpwify_filename PARAMS ((const char *, char *)); + +int +pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags) + const char *program; + char * const *argv; + const char *this_pname; + const char *temp_base; + char **errmsg_fmt, **errmsg_arg; + int flags; +{ + char tmpprogram[255]; + char *cp, *tmpname; + int i; + + mpwify_filename (program, tmpprogram); + if (first_time) + { + printf ("Set Failed 0\n"); + first_time = 0; + } + + fputs ("If {Failed} == 0\n", stdout); + /* If being verbose, output a copy of the command. It should be + accurate enough and escaped enough to be "clickable". */ + if (flags & PEXECUTE_VERBOSE) + { + fputs ("\tEcho ", stdout); + fputc ('\'', stdout); + fputs (tmpprogram, stdout); + fputc ('\'', stdout); + fputc (' ', stdout); + for (i=1; argv[i]; i++) + { + fputc ('\'', stdout); + /* See if we have an argument that needs fixing. */ + if (strchr(argv[i], '/')) + { + tmpname = (char *) xmalloc (256); + mpwify_filename (argv[i], tmpname); + argv[i] = tmpname; + } + for (cp = argv[i]; *cp; cp++) + { + /* Write an Option-d escape char in front of special chars. */ + if (strchr("'+", *cp)) + fputc ('\266', stdout); + fputc (*cp, stdout); + } + fputc ('\'', stdout); + fputc (' ', stdout); + } + fputs ("\n", stdout); + } + fputs ("\t", stdout); + fputs (tmpprogram, stdout); + fputc (' ', stdout); + + for (i=1; argv[i]; i++) + { + /* See if we have an argument that needs fixing. */ + if (strchr(argv[i], '/')) + { + tmpname = (char *) xmalloc (256); + mpwify_filename (argv[i], tmpname); + argv[i] = tmpname; + } + if (strchr (argv[i], ' ')) + fputc ('\'', stdout); + for (cp = argv[i]; *cp; cp++) + { + /* Write an Option-d escape char in front of special chars. */ + if (strchr("'+", *cp)) + fputc ('\266', stdout); + fputc (*cp, stdout); + } + if (strchr (argv[i], ' ')) + fputc ('\'', stdout); + fputc (' ', stdout); + } + + fputs ("\n", stdout); + + /* Output commands that arrange to clean up and exit if a failure occurs. + We have to be careful to collect the status from the program that was + run, rather than some other script command. Also, we don't exit + immediately, since necessary cleanups are at the end of the script. */ + fputs ("\tSet TmpStatus {Status}\n", stdout); + fputs ("\tIf {TmpStatus} != 0\n", stdout); + fputs ("\t\tSet Failed {TmpStatus}\n", stdout); + fputs ("\tEnd\n", stdout); + fputs ("End\n", stdout); + + /* We're just composing a script, can't fail here. */ + return 0; +} + +int +pwait (pid, status, flags) + int pid; + int *status; + int flags; +{ + *status = 0; + return 0; +} + +/* Write out commands that will exit with the correct error code + if something in the script failed. */ + +void +pfinish () +{ + printf ("\tExit \"{Failed}\"\n"); +} + diff --git a/gnu/lib/libiberty/src/pex-msdos.c b/gnu/lib/libiberty/src/pex-msdos.c new file mode 100644 index 00000000000..d61c129b97f --- /dev/null +++ b/gnu/lib/libiberty/src/pex-msdos.c @@ -0,0 +1,147 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. Generic MSDOS specialization. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003 + Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty 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. + +Libiberty 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 libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "pex-common.h" + +#include <stdio.h> +#include <errno.h> +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#include "safe-ctype.h" +#include <process.h> + +/* MSDOS doesn't multitask, but for the sake of a consistent interface + the code behaves like it does. pexecute runs the program, tucks the + exit code away, and returns a "pid". pwait must be called to fetch the + exit code. */ + +/* For communicating information from pexecute to pwait. */ +static int last_pid = 0; +static int last_status = 0; +static int last_reaped = 0; + +int +pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags) + const char *program; + char * const *argv; + const char *this_pname; + const char *temp_base; + char **errmsg_fmt, **errmsg_arg; + int flags; +{ + int rc; + char *scmd, *rf; + FILE *argfile; + int i, el = flags & PEXECUTE_SEARCH ? 4 : 0; + + last_pid++; + if (last_pid < 0) + last_pid = 1; + + if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE) + abort (); + + if (temp_base == 0) + temp_base = choose_temp_base (); + scmd = (char *) xmalloc (strlen (program) + strlen (temp_base) + 6 + el); + rf = scmd + strlen(program) + 2 + el; + sprintf (scmd, "%s%s @%s.gp", program, + (flags & PEXECUTE_SEARCH ? ".exe" : ""), temp_base); + argfile = fopen (rf, "w"); + if (argfile == 0) + { + int errno_save = errno; + free (scmd); + errno = errno_save; + *errmsg_fmt = "cannot open `%s.gp'"; + *errmsg_arg = temp_base; + return -1; + } + + for (i=1; argv[i]; i++) + { + char *cp; + for (cp = argv[i]; *cp; cp++) + { + if (*cp == '"' || *cp == '\'' || *cp == '\\' || ISSPACE (*cp)) + fputc ('\\', argfile); + fputc (*cp, argfile); + } + fputc ('\n', argfile); + } + fclose (argfile); + + rc = system (scmd); + + { + int errno_save = errno; + remove (rf); + free (scmd); + errno = errno_save; + } + + if (rc == -1) + { + *errmsg_fmt = install_error_msg; + *errmsg_arg = (char *)program; + return -1; + } + + /* Tuck the status away for pwait, and return a "pid". */ + last_status = rc << 8; + return last_pid; +} + +/* Use ECHILD if available, otherwise use EINVAL. */ +#ifdef ECHILD +#define PWAIT_ERROR ECHILD +#else +#define PWAIT_ERROR EINVAL +#endif + +int +pwait (pid, status, flags) + int pid; + int *status; + int flags; +{ + /* On MSDOS each pexecute must be followed by its associated pwait. */ + if (pid != last_pid + /* Called twice for the same child? */ + || pid == last_reaped) + { + errno = PWAIT_ERROR; + return -1; + } + /* ??? Here's an opportunity to canonicalize the values in STATUS. + Needed? */ + *status = last_status; + last_reaped = last_pid; + return last_pid; +} diff --git a/gnu/lib/libiberty/src/pex-os2.c b/gnu/lib/libiberty/src/pex-os2.c new file mode 100644 index 00000000000..d9eacf1f8f3 --- /dev/null +++ b/gnu/lib/libiberty/src/pex-os2.c @@ -0,0 +1,72 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. OS/2 specialization. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003 + Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty 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. + +Libiberty 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 libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "pex-common.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif + +/* ??? Does OS2 have process.h? */ +extern int spawnv (); +extern int spawnvp (); + +int +pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags) + const char *program; + char * const *argv; + const char *this_pname; + const char *temp_base; + char **errmsg_fmt, **errmsg_arg; + int flags; +{ + int pid; + + if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE) + abort (); + /* ??? Presumably 1 == _P_NOWAIT. */ + pid = (flags & PEXECUTE_SEARCH ? spawnvp : spawnv) (1, program, argv); + if (pid == -1) + { + *errmsg_fmt = install_error_msg; + *errmsg_arg = program; + return -1; + } + return pid; +} + +int +pwait (pid, status, flags) + int pid; + int *status; + int flags; +{ + /* ??? Here's an opportunity to canonicalize the values in STATUS. + Needed? */ + int pid = wait (status); + return pid; +} diff --git a/gnu/lib/libiberty/src/pex-unix.c b/gnu/lib/libiberty/src/pex-unix.c new file mode 100644 index 00000000000..14fe71ed09c --- /dev/null +++ b/gnu/lib/libiberty/src/pex-unix.c @@ -0,0 +1,166 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. Generic Unix version + (also used for UWIN and VMS). + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003 + Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty 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. + +Libiberty 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 libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "pex-common.h" + +#include <stdio.h> +#include <errno.h> +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif + +#ifndef HAVE_WAITPID +#define waitpid(pid, status, flags) wait(status) +#endif + +extern int execv (); +extern int execvp (); + +int +pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags) + const char *program; + char * const *argv; + const char *this_pname; + const char *temp_base ATTRIBUTE_UNUSED; + char **errmsg_fmt, **errmsg_arg; + int flags; +{ + int (*func)() = (flags & PEXECUTE_SEARCH ? execvp : execv); + int pid; + int pdes[2]; + int input_desc, output_desc; + int retries, sleep_interval; + /* Pipe waiting from last process, to be used as input for the next one. + Value is STDIN_FILE_NO if no pipe is waiting + (i.e. the next command is the first of a group). */ + static int last_pipe_input; + + /* If this is the first process, initialize. */ + if (flags & PEXECUTE_FIRST) + last_pipe_input = STDIN_FILE_NO; + + input_desc = last_pipe_input; + + /* If this isn't the last process, make a pipe for its output, + and record it as waiting to be the input to the next process. */ + if (! (flags & PEXECUTE_LAST)) + { + if (pipe (pdes) < 0) + { + *errmsg_fmt = "pipe"; + *errmsg_arg = NULL; + return -1; + } + output_desc = pdes[WRITE_PORT]; + last_pipe_input = pdes[READ_PORT]; + } + else + { + /* Last process. */ + output_desc = STDOUT_FILE_NO; + last_pipe_input = STDIN_FILE_NO; + } + + /* Fork a subprocess; wait and retry if it fails. */ + sleep_interval = 1; + pid = -1; + for (retries = 0; retries < 4; retries++) + { + pid = fork (); + if (pid >= 0) + break; + sleep (sleep_interval); + sleep_interval *= 2; + } + + switch (pid) + { + case -1: + *errmsg_fmt = "fork"; + *errmsg_arg = NULL; + return -1; + + case 0: /* child */ + /* Move the input and output pipes into place, if necessary. */ + if (input_desc != STDIN_FILE_NO) + { + close (STDIN_FILE_NO); + dup (input_desc); + close (input_desc); + } + if (output_desc != STDOUT_FILE_NO) + { + close (STDOUT_FILE_NO); + dup (output_desc); + close (output_desc); + } + + /* Close the parent's descs that aren't wanted here. */ + if (last_pipe_input != STDIN_FILE_NO) + close (last_pipe_input); + + /* Exec the program. */ + (*func) (program, argv); + + fprintf (stderr, "%s: ", this_pname); + fprintf (stderr, install_error_msg, program); + fprintf (stderr, ": %s\n", xstrerror (errno)); + exit (-1); + /* NOTREACHED */ + return 0; + + default: + /* In the parent, after forking. + Close the descriptors that we made for this child. */ + if (input_desc != STDIN_FILE_NO) + close (input_desc); + if (output_desc != STDOUT_FILE_NO) + close (output_desc); + + /* Return child's process number. */ + return pid; + } +} + +int +pwait (pid, status, flags) + int pid; + int *status; + int flags ATTRIBUTE_UNUSED; +{ + /* ??? Here's an opportunity to canonicalize the values in STATUS. + Needed? */ + pid = waitpid (pid, status, 0); + return pid; +} diff --git a/gnu/lib/libiberty/src/pex-win32.c b/gnu/lib/libiberty/src/pex-win32.c new file mode 100644 index 00000000000..bd097a4bb05 --- /dev/null +++ b/gnu/lib/libiberty/src/pex-win32.c @@ -0,0 +1,243 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. Generic Win32 specialization. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003 + Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty 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. + +Libiberty 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 libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "pex-common.h" + +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif + +#include <process.h> +#include <io.h> +#include <fcntl.h> +#include <signal.h> + +/* mingw32 headers may not define the following. */ + +#ifndef _P_WAIT +# define _P_WAIT 0 +# define _P_NOWAIT 1 +# define _P_OVERLAY 2 +# define _P_NOWAITO 3 +# define _P_DETACH 4 + +# define WAIT_CHILD 0 +# define WAIT_GRANDCHILD 1 +#endif + +/* This is a kludge to get around the Microsoft C spawn functions' propensity + to remove the outermost set of double quotes from all arguments. */ + +static const char * const * +fix_argv (argvec) + char **argvec; +{ + int i; + + for (i = 1; argvec[i] != 0; i++) + { + int len, j; + char *temp, *newtemp; + + temp = argvec[i]; + len = strlen (temp); + for (j = 0; j < len; j++) + { + if (temp[j] == '"') + { + newtemp = xmalloc (len + 2); + strncpy (newtemp, temp, j); + newtemp [j] = '\\'; + strncpy (&newtemp [j+1], &temp [j], len-j); + newtemp [len+1] = 0; + temp = newtemp; + len++; + j++; + } + } + + argvec[i] = temp; + } + + for (i = 0; argvec[i] != 0; i++) + { + if (strpbrk (argvec[i], " \t")) + { + int len, trailing_backslash; + char *temp; + + len = strlen (argvec[i]); + trailing_backslash = 0; + + /* There is an added complication when an arg with embedded white + space ends in a backslash (such as in the case of -iprefix arg + passed to cpp). The resulting quoted strings gets misinterpreted + by the command interpreter -- it thinks that the ending quote + is escaped by the trailing backslash and things get confused. + We handle this case by escaping the trailing backslash, provided + it was not escaped in the first place. */ + if (len > 1 + && argvec[i][len-1] == '\\' + && argvec[i][len-2] != '\\') + { + trailing_backslash = 1; + ++len; /* to escape the final backslash. */ + } + + len += 2; /* and for the enclosing quotes. */ + + temp = xmalloc (len + 1); + temp[0] = '"'; + strcpy (temp + 1, argvec[i]); + if (trailing_backslash) + temp[len-2] = '\\'; + temp[len-1] = '"'; + temp[len] = '\0'; + + argvec[i] = temp; + } + } + + return (const char * const *) argvec; +} + +/* Win32 supports pipes */ +int +pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags) + const char *program; + char * const *argv; + const char *this_pname; + const char *temp_base; + char **errmsg_fmt, **errmsg_arg; + int flags; +{ + int pid; + int pdes[2], org_stdin, org_stdout; + int input_desc, output_desc; + int retries, sleep_interval; + + /* Pipe waiting from last process, to be used as input for the next one. + Value is STDIN_FILE_NO if no pipe is waiting + (i.e. the next command is the first of a group). */ + static int last_pipe_input; + + /* If this is the first process, initialize. */ + if (flags & PEXECUTE_FIRST) + last_pipe_input = STDIN_FILE_NO; + + input_desc = last_pipe_input; + + /* If this isn't the last process, make a pipe for its output, + and record it as waiting to be the input to the next process. */ + if (! (flags & PEXECUTE_LAST)) + { + if (_pipe (pdes, 256, O_BINARY) < 0) + { + *errmsg_fmt = "pipe"; + *errmsg_arg = NULL; + return -1; + } + output_desc = pdes[WRITE_PORT]; + last_pipe_input = pdes[READ_PORT]; + } + else + { + /* Last process. */ + output_desc = STDOUT_FILE_NO; + last_pipe_input = STDIN_FILE_NO; + } + + if (input_desc != STDIN_FILE_NO) + { + org_stdin = dup (STDIN_FILE_NO); + dup2 (input_desc, STDIN_FILE_NO); + close (input_desc); + } + + if (output_desc != STDOUT_FILE_NO) + { + org_stdout = dup (STDOUT_FILE_NO); + dup2 (output_desc, STDOUT_FILE_NO); + close (output_desc); + } + + pid = (flags & PEXECUTE_SEARCH ? _spawnvp : _spawnv) + (_P_NOWAIT, program, fix_argv(argv)); + + if (input_desc != STDIN_FILE_NO) + { + dup2 (org_stdin, STDIN_FILE_NO); + close (org_stdin); + } + + if (output_desc != STDOUT_FILE_NO) + { + dup2 (org_stdout, STDOUT_FILE_NO); + close (org_stdout); + } + + if (pid == -1) + { + *errmsg_fmt = install_error_msg; + *errmsg_arg = program; + return -1; + } + + return pid; +} + +/* MS CRTDLL doesn't return enough information in status to decide if the + child exited due to a signal or not, rather it simply returns an + integer with the exit code of the child; eg., if the child exited with + an abort() call and didn't have a handler for SIGABRT, it simply returns + with status = 3. We fix the status code to conform to the usual WIF* + macros. Note that WIFSIGNALED will never be true under CRTDLL. */ + +int +pwait (pid, status, flags) + int pid; + int *status; + int flags; +{ + int termstat; + + pid = _cwait (&termstat, pid, WAIT_CHILD); + + /* ??? Here's an opportunity to canonicalize the values in STATUS. + Needed? */ + + /* cwait returns the child process exit code in termstat. + A value of 3 indicates that the child caught a signal, but not + which one. Since only SIGABRT, SIGFPE and SIGINT do anything, we + report SIGABRT. */ + if (termstat == 3) + *status = SIGABRT; + else + *status = (((termstat) & 0xff) << 8); + + return pid; +} diff --git a/gnu/lib/libiberty/src/pexecute.txh b/gnu/lib/libiberty/src/pexecute.txh new file mode 100644 index 00000000000..269f031cc72 --- /dev/null +++ b/gnu/lib/libiberty/src/pexecute.txh @@ -0,0 +1,63 @@ +@deftypefn Extension int pexecute (const char *@var{program}, char * const *@var{argv}, const char *@var{this_pname}, const char *@var{temp_base}, char **@var{errmsg_fmt}, char **@var{errmsg_arg}, int flags) + +Executes a program. + +@var{program} and @var{argv} are the arguments to +@code{execv}/@code{execvp}. + +@var{this_pname} is name of the calling program (i.e., @code{argv[0]}). + +@var{temp_base} is the path name, sans suffix, of a temporary file to +use if needed. This is currently only needed for MS-DOS ports that +don't use @code{go32} (do any still exist?). Ports that don't need it +can pass @code{NULL}. + +(@code{@var{flags} & PEXECUTE_SEARCH}) is non-zero if @env{PATH} +should be searched (??? It's not clear that GCC passes this flag +correctly). (@code{@var{flags} & PEXECUTE_FIRST}) is nonzero for the +first process in chain. (@code{@var{flags} & PEXECUTE_FIRST}) is +nonzero for the last process in chain. The first/last flags could be +simplified to only mark the last of a chain of processes but that +requires the caller to always mark the last one (and not give up +early if some error occurs). It's more robust to require the caller +to mark both ends of the chain. + +The result is the pid on systems like Unix where we +@code{fork}/@code{exec} and on systems like WIN32 and OS/2 where we +use @code{spawn}. It is up to the caller to wait for the child. + +The result is the @code{WEXITSTATUS} on systems like MS-DOS where we +@code{spawn} and wait for the child here. + +Upon failure, @var{errmsg_fmt} and @var{errmsg_arg} are set to the +text of the error message with an optional argument (if not needed, +@var{errmsg_arg} is set to @code{NULL}), and @minus{}1 is returned. +@code{errno} is available to the caller to use. + +@end deftypefn + +@deftypefn Extension int pwait (int @var{pid}, int *@var{status}, int @var{flags}) + +Waits for a program started by @code{pexecute} to finish. + +@var{pid} is the process id of the task to wait for. @var{status} is +the `status' argument to wait. @var{flags} is currently unused +(allows future enhancement without breaking upward compatibility). +Pass 0 for now. + +The result is the pid of the child reaped, or -1 for failure +(@code{errno} says why). + +On systems that don't support waiting for a particular child, +@var{pid} is ignored. On systems like MS-DOS that don't really +multitask @code{pwait} is just a mechanism to provide a consistent +interface for the caller. + +@end deftypefn + +@undocumented pfinish + +pfinish: finish generation of script + +pfinish is necessary for systems like MPW where a script is generated +that runs the requested programs. diff --git a/gnu/lib/libiberty/src/snprintf.c b/gnu/lib/libiberty/src/snprintf.c new file mode 100644 index 00000000000..89164695b50 --- /dev/null +++ b/gnu/lib/libiberty/src/snprintf.c @@ -0,0 +1,65 @@ +/* Implement the snprintf function. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>. + +This file is part of the libiberty library. This library 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. + +This library 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +As a special exception, if you link this library with files +compiled with a GNU compiler to produce an executable, this does not cause +the resulting executable to be covered by the GNU General Public License. +This exception does not however invalidate any other reasons why +the executable file might be covered by the GNU General Public License. */ + +/* + +@deftypefn Supplemental int snprintf (char *@var{buf}, size_t @var{n}, const char *@var{format}, ...) + +This function is similar to sprintf, but it will print at most @var{n} +characters. On error the return value is -1, otherwise it returns the +number of characters that would have been printed had @var{n} been +sufficiently large, regardless of the actual value of @var{n}. Note +some pre-C99 system libraries do not implement this correctly so users +cannot generally rely on the return value if the system version of +this function is used. + +@end deftypefn + +*/ + +#include "ansidecl.h" + +#ifdef ANSI_PROTOTYPES +#include <stdarg.h> +#include <stddef.h> +#else +#include <varargs.h> +#define size_t unsigned long +#endif + +int vsnprintf PARAMS ((char *, size_t, const char *, va_list)); + +int +snprintf VPARAMS ((char *s, size_t n, const char *format, ...)) +{ + int result; + VA_OPEN (ap, format); + VA_FIXEDARG (ap, char *, s); + VA_FIXEDARG (ap, size_t, n); + VA_FIXEDARG (ap, const char *, format); + result = vsnprintf (s, n, format, ap); + VA_CLOSE (ap); + return result; +} diff --git a/gnu/lib/libiberty/src/stpcpy.c b/gnu/lib/libiberty/src/stpcpy.c new file mode 100644 index 00000000000..a589642fd88 --- /dev/null +++ b/gnu/lib/libiberty/src/stpcpy.c @@ -0,0 +1,49 @@ +/* Implement the stpcpy function. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>. + +This file is part of the libiberty library. +Libiberty 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. + +Libiberty 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 libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* + +@deftypefn Supplemental char* stpcpy (char *@var{dst}, const char *@var{src}) + +Copies the string @var{src} into @var{dst}. Returns a pointer to +@var{dst} + strlen(@var{src}). + +@end deftypefn + +*/ + +#include <ansidecl.h> +#ifdef ANSI_PROTOTYPES +#include <stddef.h> +#else +#define size_t unsigned long +#endif + +extern size_t strlen PARAMS ((const char *)); +extern PTR memcpy PARAMS ((PTR, const PTR, size_t)); + +char * +stpcpy (dst, src) + char *dst; + const char *src; +{ + const size_t len = strlen (src); + return (char *) memcpy (dst, src, len + 1) + len; +} diff --git a/gnu/lib/libiberty/src/stpncpy.c b/gnu/lib/libiberty/src/stpncpy.c new file mode 100644 index 00000000000..cb67b4dbab1 --- /dev/null +++ b/gnu/lib/libiberty/src/stpncpy.c @@ -0,0 +1,54 @@ +/* Implement the stpncpy function. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>. + +This file is part of the libiberty library. +Libiberty 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. + +Libiberty 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 libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* + +@deftypefn Supplemental char* stpncpy (char *@var{dst}, const char *@var{src}, size_t @var{len}) + +Copies the string @var{src} into @var{dst}, copying exactly @var{len} +and padding with zeros if necessary. If @var{len} < strlen(@var{src}) +then return @var{dst} + @var{len}, otherwise returns @var{dst} + +strlen(@var{src}). + +@end deftypefn + +*/ + +#include <ansidecl.h> +#ifdef ANSI_PROTOTYPES +#include <stddef.h> +#else +#define size_t unsigned long +#endif + +extern size_t strlen PARAMS ((const char *)); +extern char *strncpy PARAMS ((char *, const char *, size_t)); + +char * +stpncpy (dst, src, len) + char *dst; + const char *src; + size_t len; +{ + size_t n = strlen (src); + if (n > len) + n = len; + return strncpy (dst, src, len) + n; +} diff --git a/gnu/lib/libiberty/src/vsnprintf.c b/gnu/lib/libiberty/src/vsnprintf.c new file mode 100644 index 00000000000..fd3dd18a91c --- /dev/null +++ b/gnu/lib/libiberty/src/vsnprintf.c @@ -0,0 +1,153 @@ +/* Implement the vsnprintf function. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>. + +This file is part of the libiberty library. This library 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. + +This library 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +As a special exception, if you link this library with files +compiled with a GNU compiler to produce an executable, this does not cause +the resulting executable to be covered by the GNU General Public License. +This exception does not however invalidate any other reasons why +the executable file might be covered by the GNU General Public License. */ + +/* + +@deftypefn Supplemental int vsnprintf (char *@var{buf}, size_t @var{n}, const char *@var{format}, va_list @var{ap}) + +This function is similar to vsprintf, but it will print at most +@var{n} characters. On error the return value is -1, otherwise it +returns the number of characters that would have been printed had +@var{n} been sufficiently large, regardless of the actual value of +@var{n}. Note some pre-C99 system libraries do not implement this +correctly so users cannot generally rely on the return value if the +system version of this function is used. + +@end deftypefn + +*/ + +#include "config.h" +#include "ansidecl.h" + +#ifdef ANSI_PROTOTYPES +#include <stdarg.h> +#else +#include <varargs.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#include "libiberty.h" + +/* This implementation relies on a working vasprintf. */ +int +vsnprintf (s, n, format, ap) + char * s; + size_t n; + const char *format; + va_list ap; +{ + char *buf = 0; + int result = vasprintf (&buf, format, ap); + + if (!buf) + return -1; + if (result < 0) + { + free (buf); + return -1; + } + + result = strlen (buf); + if (n > 0) + { + if ((long) n > result) + memcpy (s, buf, result+1); + else + { + memcpy (s, buf, n-1); + s[n - 1] = 0; + } + } + free (buf); + return result; +} + +#ifdef TEST +/* Set the buffer to a known state. */ +#define CLEAR(BUF) do { memset ((BUF), 'X', sizeof (BUF)); (BUF)[14] = '\0'; } while (0) +/* For assertions. */ +#define VERIFY(P) do { if (!(P)) abort(); } while (0) + +static int ATTRIBUTE_PRINTF_3 +checkit VPARAMS ((char *s, size_t n, const char *format, ...)) +{ + int result; + VA_OPEN (ap, format); + VA_FIXEDARG (ap, char *, s); + VA_FIXEDARG (ap, size_t, n); + VA_FIXEDARG (ap, const char *, format); + result = vsnprintf (s, n, format, ap); + VA_CLOSE (ap); + return result; +} + +extern int main PARAMS ((void)); +int +main () +{ + char buf[128]; + int status; + + CLEAR (buf); + status = checkit (buf, 10, "%s:%d", "foobar", 9); + VERIFY (status==8 && memcmp (buf, "foobar:9\0XXXXX\0", 15) == 0); + + CLEAR (buf); + status = checkit (buf, 9, "%s:%d", "foobar", 9); + VERIFY (status==8 && memcmp (buf, "foobar:9\0XXXXX\0", 15) == 0); + + CLEAR (buf); + status = checkit (buf, 8, "%s:%d", "foobar", 9); + VERIFY (status==8 && memcmp (buf, "foobar:\0XXXXXX\0", 15) == 0); + + CLEAR (buf); + status = checkit (buf, 7, "%s:%d", "foobar", 9); + VERIFY (status==8 && memcmp (buf, "foobar\0XXXXXXX\0", 15) == 0); + + CLEAR (buf); + status = checkit (buf, 6, "%s:%d", "foobar", 9); + VERIFY (status==8 && memcmp (buf, "fooba\0XXXXXXXX\0", 15) == 0); + + CLEAR (buf); + status = checkit (buf, 2, "%s:%d", "foobar", 9); + VERIFY (status==8 && memcmp (buf, "f\0XXXXXXXXXXXX\0", 15) == 0); + + CLEAR (buf); + status = checkit (buf, 1, "%s:%d", "foobar", 9); + VERIFY (status==8 && memcmp (buf, "\0XXXXXXXXXXXXX\0", 15) == 0); + + CLEAR (buf); + status = checkit (buf, 0, "%s:%d", "foobar", 9); + VERIFY (status==8 && memcmp (buf, "XXXXXXXXXXXXXX\0", 15) == 0); + + return 0; +} +#endif /* TEST */ |