From 14c44e2ec42a3c973e268add83a11e3e5fb0b80c Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Fri, 13 Mar 1998 17:02:23 +0000 Subject: [PATCH] Update. 1998-03-13 16:55 Ulrich Drepper * string/tester.c (test_strpbrk): Add more strpbrk tests. (test_strsep): Likewise. Correct horrible bugs. * string/bits/string2.h (strcspn): Optimize also reject string of length 2 and 3. (strspn): Likewise. (strpbrk): Likewise. (strsep): Likewise. Correct bug with successive separators and separators at the end of the string. * sysdeps/generic/strsep.c: Correct bug with successive separators and separators at the end of the string. 1998-03-13 13:11 Tim Waugh * posix/wordexp.c (parse_param): Positional parameters ($1, $2 etc) now handled, as well as $$ (pid). * posix/Makefile (tests): Execute wordexp-test.sh for `make check'. (distribute): Add wordexp-tst.sh. * posix/wordexp-tst.sh: New file. * posix/wordexp.c (parse_param): $# (or ${#}) expands to the number of positional parameters. Renamed substitute_length to seen_hash. Don't free(env) is env is NULL. 1998-03-13 16:50 Ulrich Drepper * libc.map: Add pthread_attr_init to GLIBC_2.1. 1998-03-13 15:01 Ulrich Drepper * gmon/gmon.c: Allow GMON_OUT_PREFIX variable to specify filename for output file replacing gmon.out. Patch by Dean Gaudet . 1998-03-12 Andreas Schwab * elf/dl-misc.c (_dl_debug_message): Fix printing of pid. Clean up namespace. Optimize finding end of line. 1998-03-12 Andreas Schwab * elf/rtld.c (process_envvars): Ignore LD_DEBUG_OUTPUT if running securely. Optimized. (process_dl_debug): Add ':' to list of separators. Optimized. 1998-03-13 10:25 Andreas Schwab --- ChangeLog | 52 +++++++- elf/dl-misc.c | 17 ++- elf/rtld.c | 318 ++++++++++++++++++++++------------------------- gmon/gmon.c | 29 +++-- linuxthreads/ChangeLog | 4 + linuxthreads/weaks.c | 10 +- posix/Makefile | 5 +- posix/wordexp-tst.sh | 71 +++++++++++ posix/wordexp.c | 135 +++++++++++++++----- string/bits/string2.h | 192 +++++++++++++++++++++++++--- string/tester.c | 117 +++++++++++------ sysdeps/generic/strsep.c | 12 +- 12 files changed, 679 insertions(+), 283 deletions(-) create mode 100755 posix/wordexp-tst.sh diff --git a/ChangeLog b/ChangeLog index 1c4056c..8f4a14b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,54 @@ -Fri Mar 13 10:25:26 1998 Andreas Schwab +1998-03-13 16:55 Ulrich Drepper + + * string/tester.c (test_strpbrk): Add more strpbrk tests. + (test_strsep): Likewise. Correct horrible bugs. + + * string/bits/string2.h (strcspn): Optimize also reject string of + length 2 and 3. + (strspn): Likewise. + (strpbrk): Likewise. + (strsep): Likewise. Correct bug with successive separators and + separators at the end of the string. + * sysdeps/generic/strsep.c: Correct bug with successive separators + and separators at the end of the string. + +1998-03-13 13:11 Tim Waugh + + * posix/wordexp.c (parse_param): Positional parameters ($1, $2 + etc) now handled, as well as $$ (pid). + + * posix/Makefile (tests): Execute wordexp-test.sh for `make check'. + (distribute): Add wordexp-tst.sh. + + * posix/wordexp-tst.sh: New file. + + * posix/wordexp.c (parse_param): $# (or ${#}) expands to the + number of positional parameters. Renamed substitute_length to + seen_hash. + Don't free(env) is env is NULL. + +1998-03-13 16:50 Ulrich Drepper + + * libc.map: Add pthread_attr_init to GLIBC_2.1. + +1998-03-13 15:01 Ulrich Drepper + + * gmon/gmon.c: Allow GMON_OUT_PREFIX variable to specify filename + for output file replacing gmon.out. + Patch by Dean Gaudet . + +1998-03-12 Andreas Schwab + + * elf/dl-misc.c (_dl_debug_message): Fix printing of pid. Clean + up namespace. Optimize finding end of line. + +1998-03-12 Andreas Schwab + + * elf/rtld.c (process_envvars): Ignore LD_DEBUG_OUTPUT if running + securely. Optimized. + (process_dl_debug): Add ':' to list of separators. Optimized. + +1998-03-13 10:25 Andreas Schwab * sysdeps/m68k/fpu/bits/mathinline.h (isgreater, isgreaterequal, isless, islessequal, islessgreater, isunordered): Return zero or diff --git a/elf/dl-misc.c b/elf/dl-misc.c index d3b0f34..937aeac 100644 --- a/elf/dl-misc.c +++ b/elf/dl-misc.c @@ -110,7 +110,7 @@ _dl_debug_message (int new_line, const char *msg, ...) va_list ap; if (pid == 0) - pid = getpid (); + pid = __getpid (); va_start (ap, msg); do @@ -125,17 +125,22 @@ _dl_debug_message (int new_line, const char *msg, ...) PID now if needed. */ if (new_line) { - char buf[7] = "00000:\t"; + char buf[7]; + char *p; assert (pid >= 0 && pid < 100000); - _itoa_word (pid, &buf[5], 10, 0); + p = _itoa_word (pid, &buf[5], 10, 0); + while (p > buf) + *--p = '0'; + buf[5] = ':'; + buf[6] = '\t'; __libc_write (_dl_debug_fd, buf, 7); new_line = 0; } - endp = strchr (msg, '\n'); - if (endp == NULL) + endp = msg + strcspn (msg, "\n"); + if (*endp == '\0') { - __libc_write (_dl_debug_fd, msg, strlen (msg)); + __libc_write (_dl_debug_fd, msg, endp - msg); msg = va_arg (ap, const char *); } else diff --git a/elf/rtld.c b/elf/rtld.c index 168fd1b..b160522 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -925,36 +925,25 @@ static int any_debug; /* Process the string given as the parameter which explains which debugging options are enabled. */ static void -process_dl_debug (char *dl_debug) +process_dl_debug (const char *dl_debug) { + size_t len; +#define separators " ,:" do { -#define issep(Ch) ((Ch) == ' ' || (Ch) == ',') + len = 0; /* Skip separating white spaces and commas. */ - while (issep (*dl_debug)) - ++dl_debug; + dl_debug += strspn (dl_debug, separators); if (*dl_debug != '\0') { - if (strncmp (dl_debug, "files", 5) == 0 - && (issep (dl_debug[5]) || dl_debug[5] == '\0')) - { - _dl_debug_files = 1; - _dl_debug_impcalls = 1; - any_debug = 1; - dl_debug += 5; - } - else if (strncmp (dl_debug, "bindings", 8) == 0 - && (issep (dl_debug[8]) || dl_debug[8] == '\0')) - { - _dl_debug_bindings = 1; - _dl_debug_impcalls = 1; - any_debug = 1; - dl_debug += 8; - } - else if (strncmp (dl_debug, "help", 4) == 0 - && (issep (dl_debug[4]) || dl_debug[4] == '\0')) + len = strcspn (dl_debug, separators); + + switch (len) { - _dl_sysdep_message ("\ + case 4: + if (memcmp (dl_debug, "help", 4) == 0) + { + _dl_sysdep_message ("\ Valid options for the LD_DEBUG environment variable are:\n\ \n\ bindings display information about symbol binding\n\ @@ -968,58 +957,77 @@ Valid options for the LD_DEBUG environment variable are:\n\ To direct the debugging output into a file instead of standard output\n\ a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n", NULL); - _exit (0); - } - else if (strncmp (dl_debug, "libs", 4) == 0 - && (issep (dl_debug[4]) || dl_debug[4] == '\0')) - { - _dl_debug_libs = 1; - _dl_debug_impcalls = 1; - any_debug = 1; - dl_debug += 4; - } - else if (strncmp (dl_debug, "reloc", 4) == 0 - && (issep (dl_debug[5]) || dl_debug[5] == '\0')) - { - _dl_debug_reloc = 1; - _dl_debug_impcalls = 1; - any_debug = 1; - dl_debug += 5; - } - else if (strncmp (dl_debug, "symbols", 7) == 0 - && (issep (dl_debug[7]) || dl_debug[7] == '\0')) - { - _dl_debug_symbols = 1; - _dl_debug_impcalls = 1; - any_debug = 1; - dl_debug += 7; - } - else if (strncmp (dl_debug, "versions", 8) == 0 - && (issep (dl_debug[8]) || dl_debug[8] == '\0')) - { - _dl_debug_versions = 1; - _dl_debug_impcalls = 1; - any_debug = 1; - dl_debug += 8; - } - else - { - /* Display a warning and skip everything until next - separator. */ - char *startp = dl_debug; + _exit (0); + } - do - ++dl_debug; - while (*dl_debug != '\0' && !issep (*dl_debug)); + if (memcmp (dl_debug, "libs", 4) == 0) + { + _dl_debug_libs = 1; + _dl_debug_impcalls = 1; + any_debug = 1; + continue; + } + break; + + case 5: + if (memcmp (dl_debug, "reloc", 5) == 0) + { + _dl_debug_reloc = 1; + _dl_debug_impcalls = 1; + any_debug = 1; + continue; + } + + if (memcmp (dl_debug, "files", 5) == 0) + { + _dl_debug_files = 1; + _dl_debug_impcalls = 1; + any_debug = 1; + continue; + } + break; - startp = strndupa (startp, dl_debug - startp); - _dl_sysdep_error ("warning: debug option `", startp, - "' unknown; try LD_DEBUG=help\n", NULL); + case 7: + if (memcmp (dl_debug, "symbols", 7) == 0) + { + _dl_debug_symbols = 1; + _dl_debug_impcalls = 1; + any_debug = 1; + continue; + } + break; + case 8: + if (memcmp (dl_debug, "bindings", 8) == 0) + { + _dl_debug_bindings = 1; + _dl_debug_impcalls = 1; + any_debug = 1; + continue; + } + + if (memcmp (dl_debug, "versions", 8) == 0) + { + _dl_debug_versions = 1; + _dl_debug_impcalls = 1; + any_debug = 1; + continue; + } + break; + + default: + break; } + + { + /* Display a warning and skip everything until next separator. */ + char *startp = strndupa (dl_debug, len); + _dl_sysdep_error ("warning: debug option `", startp, + "' unknown; try LD_DEBUG=help\n", NULL); + } } } - while (*dl_debug != '\0'); + while (*(dl_debug += len) != '\0'); } /* Process all environments variables the dynamic linker must recognize. @@ -1039,126 +1047,94 @@ process_envvars (enum mode *modep, int *lazyp) while ((envline = _dl_next_ld_env_entry (&runp)) != NULL) { - int result; + size_t len = strcspn (envline, "=") - 3; - /* Do we bind early? */ - result = strncmp (&envline[3], "BIND_NOW=", 9); - if (result == 0) + switch (len) { - bind_now = 1; - continue; - } - if (result < 0) - continue; + case 4: + /* Warning level, verbose or not. */ + if (memcmp (&envline[3], "WARN", 4) == 0) + _dl_verbose = envline[8] != '\0'; + break; - /* Debugging of the dynamic linker? */ - result = strncmp (&envline[3], "DEBUG=", 6); - if (result == 0) - { - process_dl_debug (&envline[9]); - continue; - } - if (result < 0) - continue; + case 5: + /* Debugging of the dynamic linker? */ + if (memcmp (&envline[3], "DEBUG", 5) == 0) + process_dl_debug (&envline[9]); + break; - /* Where to place the profiling data file. */ - result = strncmp (&envline[3], "DEBUG_OUTPUT=", 13); - if (result == 0) - { - debug_output = &envline[16]; - continue; - } - if (result < 0) - continue; + case 7: + /* Print information about versions. */ + if (memcmp (&envline[3], "VERBOSE", 7) == 0) + { + version_info = envline[11] != '\0'; + break; + } - /* The library search path. */ - result = strncmp (&envline[3], "LIBRARY_PATH=", 13); - if (result == 0) - { - library_path = &envline[16]; - continue; - } - if (result < 0) - continue; + /* List of objects to be preloaded. */ + if (memcmp (&envline[3], "PRELOAD", 7) == 0) + { + preloadlist = &envline[11]; + break; + } - /* List of objects to be preloaded. */ - result = strncmp (&envline[3], "PRELOAD=", 8); - if (result == 0) - { - preloadlist = &envline[11]; - continue; - } - if (result < 0) - continue; + /* Which shared object shall be profiled. */ + if (memcmp (&envline[3], "PROFILE", 7) == 0) + { + _dl_profile = &envline[11]; + if (*_dl_profile == '\0') + _dl_profile = NULL; + } + break; - /* Which shared object shall be profiled. */ - result = strncmp (&envline[3], "PROFILE=", 8); - if (result == 0) - { - _dl_profile = &envline[11]; - if (*_dl_profile == '\0') - _dl_profile = NULL; - continue; - } - if (result < 0) - continue; + case 8: + /* Do we bind early? */ + if (memcmp (&envline[3], "BIND_NOW", 8) == 0) + bind_now = 1; + break; - /* Where to place the profiling data file. */ - result = strncmp (&envline[3], "PROFILE_OUTPUT=", 15); - if (result == 0) - { - _dl_profile_output = &envline[18]; - if (*_dl_profile_output == '\0') - _dl_profile_output = "/var/tmp"; - continue; - } - if (result < 0) - continue; + case 9: + /* Test whether we want to see the content of the auxiliary + array passed up from the kernel. */ + if (memcmp (&envline[3], "SHOW_AUXV", 9) == 0) + _dl_show_auxv (); + break; - /* Test whether we want to see the content of the auxiliary - array passed up from the kernel. */ - result = strncmp (&envline[3], "SHOW_AUXV=", 10); - if (result == 0) - { - _dl_show_auxv (); - continue; - } - if (result < 0) - continue; + case 12: + /* Where to place the profiling data file. */ + if (memcmp (&envline[3], "DEBUG_OUTPUT", 12) == 0) + { + debug_output = &envline[16]; + break; + } - /* The mode of the dynamic linker can be set. */ - result = strncmp (&envline[3], "TRACE_LOADED_OBJECTS=", 21); - if (result == 0) - { - mode = trace; - continue; - } - if (result < 0) - continue; + /* The library search path. */ + if (memcmp (&envline[3], "LIBRARY_PATH", 12) == 0) + library_path = &envline[16]; + break; - /* Print information about versions. */ - result = strncmp (&envline[3], "VERBOSE=", 8); - if (result == 0) - { - version_info = envline[11] != '\0'; - continue; - } - if (result < 0) - continue; + case 14: + /* Where to place the profiling data file. */ + if (memcmp (&envline[3], "PROFILE_OUTPUT", 14) == 0) + { + _dl_profile_output = &envline[18]; + if (*_dl_profile_output == '\0') + _dl_profile_output = "/var/tmp"; + } + break; - /* Warning level, verbose or not. */ - result = strncmp (&envline[3], "WARN=", 5); - if (result == 0) - { - _dl_verbose = envline[8] != '\0'; - continue; + case 20: + /* The mode of the dynamic linker can be set. */ + if (memcmp (&envline[3], "TRACE_LOADED_OBJECTS", 20) == 0) + mode = trace; + break; } } /* If we have to run the dynamic linker in debugging mode and the LD_DEBUG_OUTPUT environment variable is given, we write the debug messages to this file. */ - if (any_debug && debug_output != NULL) + if (any_debug && debug_output != NULL && !__libc_enable_secure) { _dl_debug_fd = __open (debug_output, O_WRONLY | O_APPEND | O_CREAT, 0666); diff --git a/gmon/gmon.c b/gmon/gmon.c index c3e7c51..0087e8c 100644 --- a/gmon/gmon.c +++ b/gmon/gmon.c @@ -310,16 +310,29 @@ static void write_gmon (void) { struct gmon_hdr ghdr __attribute__ ((aligned (__alignof__ (int)))); - int fd; + int fd = -1; + char *env; - fd = __open ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY, 0666); - if (fd < 0) + env = getenv ("GMON_OUT_PREFIX"); + if (env != NULL && !__libc_enable_secure) { - char buf[300]; - int errnum = errno; - fprintf (stderr, "_mcleanup: gmon.out: %s\n", - _strerror_internal (errnum, buf, sizeof buf)); - return; + size_t len = strlen (env); + char buf[len + 20]; + sprintf (buf, "%s.%u", env, __getpid ()); + fd = __open (buf, O_CREAT|O_TRUNC|O_WRONLY, 0666); + } + + if (fd == -1) + { + fd = __open ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY, 0666); + if (fd < 0) + { + char buf[300]; + int errnum = errno; + fprintf (stderr, "_mcleanup: gmon.out: %s\n", + _strerror_internal (errnum, buf, sizeof buf)); + return; + } } /* write gmon.out header: */ diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog index eb866f0..77aa4a2 100644 --- a/linuxthreads/ChangeLog +++ b/linuxthreads/ChangeLog @@ -1,3 +1,7 @@ +1998-03-13 16:51 Ulrich Drepper + + * weaks.c: Define pthread_attr_init as GLIBC_2.0 and GLIBC_2.1. + 1998-03-13 00:46 Ulrich Drepper * attr.c: Implement pthread_attr_[gs]etguardsize, diff --git a/linuxthreads/weaks.c b/linuxthreads/weaks.c index da645c1..ac8e116 100644 --- a/linuxthreads/weaks.c +++ b/linuxthreads/weaks.c @@ -1,5 +1,5 @@ /* The weak pthread functions for Linux. - Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 1998 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 @@ -26,7 +26,15 @@ extern int __pthread_return_1 __P ((void)); extern void __pthread_return_void __P ((void)); /* Those are pthread functions which return 0 if successful. */ +#if defined HAVE_ELF && defined PIC && defined DO_VERSIONING +weak_alias (__pthread_return_0, __libc_pthread_attr_init_2_0) +symbol_version (__libc_pthread_attr_init_2_0, pthread_attr_init, GLIBC_2.0); +weak_alias (__pthread_return_0, __libc_pthread_attr_init_2_1) +default_symbol_version (__libc_pthread_attr_init_2_1, pthread_attr_init, + GLIBC_2.1); +#else weak_alias (__pthread_return_0, pthread_attr_init) +#endif weak_alias (__pthread_return_0, pthread_attr_destroy) weak_alias (__pthread_return_0, pthread_attr_setdetachstate) weak_alias (__pthread_return_0, pthread_attr_getdetachstate) diff --git a/posix/Makefile b/posix/Makefile index a9b78aa..0fc1787 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -29,7 +29,7 @@ headers := sys/utsname.h sys/times.h sys/wait.h sys/types.h unistd.h \ bits/sched.h re_comp.h wait.h bits/environments.h cpio.h distribute := confstr.h TESTS TESTS2C.sed testcases.h \ - globtest.c globtest.sh + globtest.c globtest.sh wordexp-tst.sh routines := \ uname \ @@ -64,8 +64,9 @@ before-compile := testcases.h include ../Rules ifeq (no,$(cross-compiling)) -tests: $(objpfx)globtest +tests: $(objpfx)globtest $(objpfx)wordexp-test $(SHELL) -e globtest.sh $(common-objpfx) $(elf-objpfx) $(rtld-installed-name) + $(SHELL) -e wordexp-tst.sh $(common-objpfx) $(elf-objpfx) $(rtld-installed-name) endif CFLAGS-regex.c = -Wno-unused -Wno-strict-prototypes diff --git a/posix/wordexp-tst.sh b/posix/wordexp-tst.sh new file mode 100755 index 0000000..e341e64 --- /dev/null +++ b/posix/wordexp-tst.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +# Some of these tests may look a little weird. +# The first parameter to wordexp-test is what it gives to wordexp. +# The others are just there to be parameters. + +common_objpfx=$1; shift +elf_objpfx=$1; shift +rtld_installed_name=$1; shift + +: ${TMPDIR=/tmp} +testout=$TMPDIR/wordexp-test-result + +failed=0 +export IFS=$(echo -e " \t\n") + +${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \ +${common_objpfx}posix/wordexp-test '$*' > ${testout}1 +cat <<"EOF" | cmp - ${testout}1 || failed=1 +wordexp returned 0 +we_wordv[0] = "$*" +EOF + +${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \ +${common_objpfx}posix/wordexp-test '${*}' unquoted > ${testout}2 +cat <<"EOF" | cmp - ${testout}2 || failed=1 +wordexp returned 0 +we_wordv[0] = "${*}" +we_wordv[1] = "unquoted" +EOF + +${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \ +${common_objpfx}posix/wordexp-test '$@' unquoted > ${testout}3 +cat <<"EOF" | cmp - ${testout}3 || failed=1 +wordexp returned 0 +we_wordv[0] = "$@" +we_wordv[1] = "unquoted" +EOF + +${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \ +${common_objpfx}posix/wordexp-test '"$* quoted"' param > ${testout}4 +cat <<"EOF" | cmp - ${testout}4 || failed=1 +wordexp returned 0 +we_wordv[0] = ""$* quoted" param quoted" +EOF + +${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \ +${common_objpfx}posix/wordexp-test '"$@ quoted"' param > ${testout}5 +cat <<"EOF" | cmp - ${testout}5 || failed=1 +wordexp returned 0 +we_wordv[0] = ""$@ quoted"" +we_wordv[1] = "param quoted" +EOF +# Why? Because bash does it that way.. + +${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \ +${common_objpfx}posix/wordexp-test '$#' 2 3 4 5 > ${testout}6 +cat <<"EOF" | cmp - ${testout}6 || failed=1 +wordexp returned 0 +we_wordv[0] = "5" +EOF + +${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \ +${common_objpfx}posix/wordexp-test '$2 ${3}' 2nd 3rd > ${testout}6 +cat <<"EOF" | cmp - ${testout}6 || failed=1 +wordexp returned 0 +we_wordv[0] = "2nd" +we_wordv[1] = "3rd" +EOF + +exit $failed diff --git a/posix/wordexp.c b/posix/wordexp.c index a72a677..0c89e02 100644 --- a/posix/wordexp.c +++ b/posix/wordexp.c @@ -48,7 +48,8 @@ * This is a recursive-descent-style word expansion routine. */ -/* This variable is defined and initialized in the startup code. */ +/* These variables are defined and initialized in the startup code. */ +extern int __libc_argc; extern char **__libc_argv; /* Some forward declarations */ @@ -1016,9 +1017,8 @@ parse_param (char **word, size_t *word_length, size_t *max_length, enum remove_pattern_enum remove = RP_NONE; int colon_seen = 0; int depth = 0; - int substitute_length = 0; + int seen_hash = 0; int error; - int star = 0; for (; words[*offset]; ++(*offset)) { @@ -1066,7 +1066,14 @@ parse_param (char **word, size_t *word_length, size_t *max_length, goto envsubst; case '#': - /* '#' only has special meaning inside braces */ + /* '#' only has special meaning inside braces or as the very + * first character after $ */ + if (*offset == start) + { + seen_hash = 1; + goto envsubst; + } + if (words[start] != '{') { /* Evaluate */ @@ -1078,10 +1085,10 @@ parse_param (char **word, size_t *word_length, size_t *max_length, /* At the start? (i.e. 'string length') */ if (*offset == start + 1) { - substitute_length = 1; + seen_hash = 1; break; } - else if (substitute_length) + else if (seen_hash) goto syntax; /* Separating variable name from prefix pattern? */ @@ -1158,7 +1165,7 @@ parse_param (char **word, size_t *word_length, size_t *max_length, if (!env || !*env) goto syntax; - if (substitute_length) + if (seen_hash) goto syntax; if (action != '\0' || remove != RP_NONE) @@ -1206,22 +1213,29 @@ parse_param (char **word, size_t *word_length, size_t *max_length, break; } - - star = strchr ("*@", words[*offset]) != NULL; - if (isalnum (words[*offset]) || star) + else { - env = w_addchar (env, &env_length, &env_maxlen, words[*offset]); - if (env == NULL) - goto no_space; + int special = (strchr ("*@$", words[*offset]) != NULL + || isdigit (words[*offset])); - if (star) - goto envsubst; + if (isalpha (words[*offset]) || special) + { + env = w_addchar (env, &env_length, &env_maxlen, + words[*offset]); + if (env == NULL) + goto no_space; - break; - } + if (special && words[start] != '{') + goto envsubst; - --(*offset); - goto envsubst; + /* Keep going (get next char) */ + break; + } + + /* Stop and evaluate, remembering char we stopped at */ + --(*offset); + goto envsubst; + } } } @@ -1235,28 +1249,76 @@ envsubst: if (!env || !*env) { - *offset = start - 1; - *word = w_addchar (*word, word_length, max_length, '$'); - free (env); + if (seen_hash) + { + /* $# expands to the number of positional parameters */ + char buffer[21]; + buffer[20] = '\0'; + *word = w_addstr (*word, word_length, max_length, + _itoa_word (__libc_argc - 1, &buffer[20], 10, 0)); + } + else + { + /* Just $ on its own */ + *offset = start - 1; + *word = w_addchar (*word, word_length, max_length, '$'); + } + + if (env) + free (env); + return *word ? 0 : WRDE_NOSPACE; } - /* Is it `$*' or `$@' ? */ - if (strpbrk (env, "*@") != NULL) + /* Is it a special parameter? */ + if (strpbrk (env, "0123456789*@$")) { - size_t plist_len = 1; - int p; - - if (env[1] != '\0') + if (env[1]) { /* Bad substitution if there is more than one character */ + free (env); fprintf (stderr, "${%s}: bad substitution\n", env); return WRDE_SYNTAX; } - if (!quoted || *env == '*') + /* Is it a digit? */ + if (isdigit(*env)) + { + int n = *env - '0'; + char *param; + + free (env); + if (n >= __libc_argc) + /* Substitute NULL */ + return 0; + + /* Replace with the appropriate positional parameter */ + param = __strdup (__libc_argv[n]); + if (!param) + return WRDE_NOSPACE; + + *word = w_addstr (*word, word_length, max_length, param); + return *word ? 0 : WRDE_NOSPACE; + } + /* Is it `$$' ? */ + else if (*env == '$') + { + char pidstr[21]; + + free (env); + pidstr[20] = '\0'; + *word = w_addstr (*word, word_length, max_length, + _itoa_word (getpid(), &pidstr[20], 10, 0)); + return *word ? 0 : WRDE_NOSPACE; + } + /* Is it `$*' or `$@' (unquoted) ? */ + else if (*env == '*' || (*env == '@' && !quoted)) { + size_t plist_len = 1; + int p; + /* Build up value parameter by parameter (copy them) */ + free (env); for (p = 1; __libc_argv[p]; ++p) { char *old_pointer = value; @@ -1287,8 +1349,15 @@ envsubst: if (value) goto maybe_fieldsplit; + + return 0; } + /* Must be a quoted `$@' */ + assert (*env == '@'); + assert (quoted); + free (env); + /* Each parameter is a separate word ("$@") */ if (__libc_argv[0] == NULL) { @@ -1300,13 +1369,14 @@ envsubst: } else { + int p; + for (p = 1; __libc_argv[p + 1]; p++) { char *copy = __strdup (__libc_argv[p]); if (copy == NULL) return WRDE_NOSPACE; - strcpy (copy, __libc_argv[p]); error = w_addword (pwordexp, copy); if (error) { @@ -1319,6 +1389,9 @@ envsubst: if (__libc_argv[p]) { *word = __strdup (__libc_argv[p]); + if (*word == NULL) + return WRDE_NOSPACE; + *max_length = *word_length = strlen (*word); } } @@ -1584,7 +1657,7 @@ envsubst: return 0; } - if (substitute_length) + if (seen_hash) { char param_length[21]; param_length[20] = '\0'; diff --git a/string/bits/string2.h b/string/bits/string2.h index 403bcca..45c6112 100644 --- a/string/bits/string2.h +++ b/string/bits/string2.h @@ -1,5 +1,5 @@ /* Machine-independant string function optimizations. - Copyright (C) 1997 Free Software Foundation, Inc. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1997. @@ -526,7 +526,15 @@ __STRING2_COPY_TYPE (8); ? strlen (s) \ : (((__const unsigned char *) (reject))[1] == '\0' \ ? __strcspn_c1 (s, ((__const char *) (reject))[0]) \ - : strcspn (s, reject))) \ + : (((__const unsigned char *) (reject))[2] == '\0' \ + ? __strcspn_c2 (s, ((__const char *) (reject))[0], \ + ((__const char *) (reject))[1]) \ + : (((__const unsigned char *) (reject))[3] == '\0' \ + ? __strcspn_c3 (s, \ + ((__const char *) (reject))[0], \ + ((__const char *) (reject))[1], \ + ((__const char *) (reject))[2]) \ + : strcspn (s, reject))))) \ : strcspn (s, reject))) __STRING_INLINE size_t __strcspn_c1 (__const char *__s, char __reject); @@ -538,6 +546,31 @@ __strcspn_c1 (__const char *__s, char __reject) ++__result; return __result; } + +__STRING_INLINE size_t __strcspn_c2 (__const char *__s, char __reject1, + char __reject2); +__STRING_INLINE size_t +__strcspn_c2 (__const char *__s, char __reject1, char __reject2) +{ + register size_t __result = 0; + while (__s[__result] != '\0' && __s[__result] != __reject1 + && __s[__result] != __reject2) + ++__result; + return __result; +} + +__STRING_INLINE size_t __strcspn_c3 (__const char *__s, char __reject1, + char __reject2, char __reject3); +__STRING_INLINE size_t +__strcspn_c3 (__const char *__s, char __reject1, char __reject2, + char __reject3) +{ + register size_t __result = 0; + while (__s[__result] != '\0' && __s[__result] != __reject1 + && __s[__result] != __reject2 && __s[__result] != __reject3) + ++__result; + return __result; +} #endif @@ -550,7 +583,15 @@ __strcspn_c1 (__const char *__s, char __reject) ? 0 \ : (((__const unsigned char *) (accept))[1] == '\0' \ ? __strspn_c1 (s, ((__const char *) (accept))[0]) \ - : strspn (s, accept))) \ + : (((__const unsigned char *) (accept))[2] == '\0' \ + ? __strspn_c2 (s, ((__const char *) (accept))[0], \ + ((__const char *) (accept))[1]) \ + : (((__const unsigned char *) (accept))[3] == '\0' \ + ? __strspn_c3 (s, \ + ((__const char *) (accept))[0], \ + ((__const char *) (accept))[1], \ + ((__const char *) (accept))[2]) \ + : strspn (s, accept))))) \ : strspn (s, accept))) __STRING_INLINE size_t __strspn_c1 (__const char *__s, char __accept); @@ -563,6 +604,31 @@ __strspn_c1 (__const char *__s, char __accept) ++__result; return __result; } + +__STRING_INLINE size_t __strspn_c2 (__const char *__s, char __accept1, + char __accept2); +__STRING_INLINE size_t +__strspn_c2 (__const char *__s, char __accept1, char __accept2) +{ + register size_t __result = 0; + /* Please note that __accept1 and __accept2 never can be '\0'. */ + while (__s[__result] == __accept1 || __s[__result] == __accept2) + ++__result; + return __result; +} + +__STRING_INLINE size_t __strspn_c3 (__const char *__s, char __accept1, + char __accept2, char __accept3); +__STRING_INLINE size_t +__strspn_c3 (__const char *__s, char __accept1, char __accept2, char __accept3) +{ + register size_t __result = 0; + /* Please note that __accept1 to __accept3 never can be '\0'. */ + while (__s[__result] == __accept1 || __s[__result] == __accept2 + || __s[__result] == __accept3) + ++__result; + return __result; +} #endif @@ -574,8 +640,40 @@ __strspn_c1 (__const char *__s, char __accept) ? NULL \ : (((__const unsigned char *) (accept))[1] == '\0' \ ? strchr (s, ((__const unsigned char *) (accept))[0]) \ - : strpbrk (s, accept))) \ + : (((__const unsigned char *) (accept))[2] == '\0' \ + ? __strpbrk_c2 (s, ((__const char *) (accept))[0], \ + ((__const char *) (accept))[1]) \ + : (((__const unsigned char *) (accept))[3] == '\0' \ + ? __strpbrk_c3 (s, \ + ((__const char *) (accept))[0], \ + ((__const char *) (accept))[1], \ + ((__const char *) (accept))[2]) \ + : strpbrk (s, accept))))) \ : strpbrk (s, accept))) + +__STRING_INLINE char *__strpbrk_c2 (__const char *__s, char __accept1, + char __accept2); +__STRING_INLINE char * +__strpbrk_c2 (__const char *__s, char __accept1, char __accept2) +{ + /* Please note that __accept1 and __accept2 never can be '\0'. */ + while (*__s != '\0' && *__s != __accept1 && *__s != __accept2) + ++__s; + return *__s == '\0' ? NULL : (char *) __s; +} + +__STRING_INLINE char *__strpbrk_c3 (__const char *__s, char __accept1, + char __accept2, char __accept3); +__STRING_INLINE char * +__strpbrk_c3 (__const char *__s, char __accept1, char __accept2, + char __accept3) +{ + /* Please note that __accept1 to __accept3 never can be '\0'. */ + while (*__s != '\0' && *__s != __accept1 && *__s != __accept2 + && *__s != __accept3) + ++__s; + return *__s == '\0' ? NULL : (char *) __s; +} #endif @@ -612,8 +710,7 @@ strnlen (__const char *__string, size_t __maxlen) (__extension__ (__builtin_constant_p (sep) && __string2_1bptr_p (sep) \ ? (((__const unsigned char *) (sep))[0] != '\0' \ && ((__const unsigned char *) (sep))[1] == '\0' \ - ? __strtok_r_1c (s, ((__const unsigned char *) (sep))[0],\ - nextp) \ + ? __strtok_r_1c (s, ((__const char *) (sep))[0], nextp) \ : strtok_r (s, sep, nextp)) \ : strtok_r (s, sep, nextp))) @@ -652,11 +749,18 @@ __strtok_r_1c (char *__s, char __sep, char **__nextp) # define strsep(s, reject) \ (__extension__ (__builtin_constant_p (reject) && __string2_1bptr_p (reject) \ - ? (((__const unsigned char *) (reject))[0] != '\0' \ - && ((__const unsigned char *) (reject))[1] == '\0' \ + && ((__const unsigned char *) (reject))[0] != '\0' \ + ? (((__const unsigned char *) (reject))[1] == '\0' \ ? __strsep_1c (s, \ - ((__const unsigned char *) (reject))[0]) \ - : __strsep_g (s, reject)) \ + ((__const char *) (reject))[0]) \ + : (((__const unsigned char *) (reject))[2] == '\0' \ + ? __strsep_2c (s, ((__const char *) (reject))[0], \ + ((__const char *) (reject))[1]) \ + : (((__const unsigned char *) (reject))[3] == '\0' \ + ? __strsep_3c (s, ((__const char *) (reject))[0], \ + ((__const char *) (reject))[1], \ + ((__const char *) (reject))[2]) \ + : __strsep_g (s, reject)))) \ : __strsep_g (s, reject))) __STRING_INLINE char *__strsep_1c (char **__s, char __reject); @@ -664,12 +768,68 @@ __STRING_INLINE char * __strsep_1c (char **__s, char __reject) { register char *__retval = *__s; - if (__retval == NULL || *__retval == '\0') - return NULL; - while (*__retval == __reject) - ++__retval; - if ((*__s = strchr (__retval, __reject)) != NULL) + if (__retval == NULL) + return *__s = NULL; + if (*__retval == __reject) *(*__s)++ = '\0'; + else + if ((*__s = strchr (__retval, __reject)) != NULL) + *(*__s)++ = '\0'; + else + *__s = NULL; + return __retval; +} + +__STRING_INLINE char *__strsep_2c (char **__s, char __reject1, char __reject2); +__STRING_INLINE char * +__strsep_2c (char **__s, char __reject1, char __reject2) +{ + register char *__retval = *__s; + if (__retval == NULL) + return *__s = NULL; + if (*__retval == __reject1 || *__retval == __reject2) + *(*__s)++ = '\0'; + else + { + register char *__cp = __retval; + while (*__cp != '\0' && *__cp != __reject1 && *__cp != __reject2) + ++__cp; + if (*__cp != '\0') + { + *__s = __cp; + *(*__s)++ = '\0'; + } + else + *__s = NULL; + } + return __retval; +} + +__STRING_INLINE char *__strsep_3c (char **__s, char __reject1, char __reject2, + char __reject3); +__STRING_INLINE char * +__strsep_3c (char **__s, char __reject1, char __reject2, char __reject3) +{ + register char *__retval = *__s; + if (__retval == NULL) + return *__s = NULL; + if (*__retval == __reject1 || *__retval == __reject2 + || *__retval == __reject3) + *(*__s)++ = '\0'; + else + { + register char *__cp = __retval; + while (*__cp != '\0' && *__cp != __reject1 && *__cp != __reject2 + && *__cp != __reject3) + ++__cp; + if (*__cp != '\0') + { + *__s = __cp; + *(*__s)++ = '\0'; + } + else + *__s = NULL; + } return __retval; } @@ -680,7 +840,7 @@ __strsep_g (char **__s, __const char *__reject) register char *__retval = *__s; if (__retval == NULL || *__retval == '\0') return NULL; - if ((*__s = strpbrk (__retval, __reject)) != NULL) + if ((*__s = strpbrk (__retval, __reject)) != '\0') *(*__s)++ = '\0'; return __retval; } diff --git a/string/tester.c b/string/tester.c index d74ab72..9545c28 100644 --- a/string/tester.c +++ b/string/tester.c @@ -1,5 +1,5 @@ /* Tester for string functions. - Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1995, 1996, 1997, 1998 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 @@ -479,7 +479,16 @@ test_strpbrk (void) check(strpbrk(one, "db") == one+1, 9); /* Another variant. */ (void) strcpy(one, ""); check(strpbrk(one, "bc") == NULL, 10); /* Empty string. */ - check(strpbrk(one, "") == NULL, 11); /* Both strings empty. */ + (void) strcpy(one, ""); + check(strpbrk(one, "bcd") == NULL, 11); /* Empty string. */ + (void) strcpy(one, ""); + check(strpbrk(one, "bcde") == NULL, 12); /* Empty string. */ + check(strpbrk(one, "") == NULL, 13); /* Both strings empty. */ + (void) strcpy(one, "abcabdea"); + check(strpbrk(one, "befg") == one+1, 14); /* Finding first. */ + check(strpbrk(one, "cbr") == one+1, 15); /* With multiple search. */ + check(strpbrk(one, "db") == one+1, 16); /* Another variant. */ + check(strpbrk(one, "efgh") == one+6, 17); /* And yet another. */ } void @@ -648,60 +657,86 @@ test_strsep (void) equal(strsep(&cp, ", "), "", 9); equal(strsep(&cp, ", "), "first", 10); /* Extra delims, 1 tok. */ equal(strsep(&cp, ", "), "", 11); - check(strsep(&cp, ", ") == NULL, 12); + equal(strsep(&cp, ", "), "", 12); + check(strsep(&cp, ", ") == NULL, 13); cp = strcpy(one, "1a, 1b; 2a, 2b"); - equal(strsep(&cp, ", "), "1a", 13); /* Changing delim lists. */ - equal(strsep(&cp, ", "), "", 14); - equal(strsep(&cp, "; "), "1b", 15); - equal(strsep(&cp, ", "), "", 16); - equal(strsep(&cp, ", "), "2a", 17); + equal(strsep(&cp, ", "), "1a", 14); /* Changing delim lists. */ + equal(strsep(&cp, ", "), "", 15); + equal(strsep(&cp, "; "), "1b", 16); + equal(strsep(&cp, ", "), "", 17); + equal(strsep(&cp, ", "), "2a", 18); cp = strcpy(two, "x-y"); - equal(strsep(&cp, "-"), "x", 18); /* New string before done. */ - equal(strsep(&cp, "-"), "y", 19); - check(strsep(&cp, "-") == NULL, 20); - cp = strcpy(one, "a,b, c,, ,d"); - equal(strsep(&cp, ", "), "a", 21); /* Different separators. */ - equal(strsep(&cp, ", "), "b", 22); - equal(strsep(&cp, " ,"), "", 23); - equal(strsep(&cp, " ,"), "c", 24); /* Permute list too. */ - equal(strsep(&cp, " ,"), "", 25); + equal(strsep(&cp, "-"), "x", 19); /* New string before done. */ + equal(strsep(&cp, "-"), "y", 20); + check(strsep(&cp, "-") == NULL, 21); + cp = strcpy(one, "a,b, c,, ,d "); + equal(strsep(&cp, ", "), "a", 22); /* Different separators. */ + equal(strsep(&cp, ", "), "b", 23); + equal(strsep(&cp, " ,"), "", 24); + equal(strsep(&cp, " ,"), "c", 25); /* Permute list too. */ equal(strsep(&cp, " ,"), "", 26); equal(strsep(&cp, " ,"), "", 27); - equal(strsep(&cp, " ,"), "d", 28); - check(strsep(&cp, ", ") == NULL, 29); - check(strsep(&cp, ", ") == NULL, 30); /* Persistence. */ + equal(strsep(&cp, " ,"), "", 28); + equal(strsep(&cp, " ,"), "d", 29); + equal(strsep(&cp, " ,"), "", 30); + check(strsep(&cp, ", ") == NULL, 31); + check(strsep(&cp, ", ") == NULL, 32); /* Persistence. */ cp = strcpy(one, ", "); - equal(strsep(&cp, ", "), "", 31); - equal(strsep(&cp, ", "), "", 32); - check(strsep(&cp, ", ") == NULL, 33); /* No tokens. */ + equal(strsep(&cp, ", "), "", 33); + equal(strsep(&cp, ", "), "", 34); + equal(strsep(&cp, ", "), "", 35); + check(strsep(&cp, ", ") == NULL, 36); /* No tokens. */ cp = strcpy(one, ""); - check(strsep(&cp, ", ") == NULL, 34); /* Empty string. */ + equal(strsep(&cp, ", "), "", 37); + check(strsep(&cp, ", ") == NULL, 38); /* Empty string. */ cp = strcpy(one, "abc"); - equal(strsep(&cp, ", "), "abc", 35); /* No delimiters. */ - check(strsep(&cp, ", ") == NULL, 36); + equal(strsep(&cp, ", "), "abc", 39); /* No delimiters. */ + check(strsep(&cp, ", ") == NULL, 40); cp = strcpy(one, "abc"); - equal(strsep(&cp, ""), "abc", 37); /* Empty delimiter list. */ - check(strsep(&cp, "") == NULL, 38); + equal(strsep(&cp, ""), "abc", 41); /* Empty delimiter list. */ + check(strsep(&cp, "") == NULL, 42); (void) strcpy(one, "abcdefgh"); cp = strcpy(one, "a,b,c"); - equal(strsep(&cp, ","), "a", 39); /* Basics again... */ - equal(strsep(&cp, ","), "b", 40); - equal(strsep(&cp, ","), "c", 41); - check(strsep(&cp, ",") == NULL, 42); - equal(one+6, "gh", 43); /* Stomped past end? */ - equal(one, "a", 44); /* Stomped old tokens? */ - equal(one+2, "b", 45); - equal(one+4, "c", 46); + equal(strsep(&cp, ","), "a", 43); /* Basics again... */ + equal(strsep(&cp, ","), "b", 44); + equal(strsep(&cp, ","), "c", 45); + check(strsep(&cp, ",") == NULL, 46); + equal(one+6, "gh", 47); /* Stomped past end? */ + equal(one, "a", 48); /* Stomped old tokens? */ + equal(one+2, "b", 49); + equal(one+4, "c", 50); { char text[] = "This,is,a,test"; char *list = strdupa (text); - equal (strsep (&list, ","), "This", 47); - equal (strsep (&list, ","), "is", 48); - equal (strsep (&list, ","), "a", 49); - equal (strsep (&list, ","), "test", 50); - check (strsep (&list, ",") == NULL, 51); + equal (strsep (&list, ","), "This", 51); + equal (strsep (&list, ","), "is", 52); + equal (strsep (&list, ","), "a", 53); + equal (strsep (&list, ","), "test", 54); + check (strsep (&list, ",") == NULL, 55); } + + cp = strcpy(one, "a,b, c,, ,d,"); + equal(strsep(&cp, ","), "a", 56); /* Different separators. */ + equal(strsep(&cp, ","), "b", 57); + equal(strsep(&cp, ","), " c", 58); /* Permute list too. */ + equal(strsep(&cp, ","), "", 59); + equal(strsep(&cp, ","), " ", 60); + equal(strsep(&cp, ","), "d", 61); + equal(strsep(&cp, ","), "", 62); + check(strsep(&cp, ",") == NULL, 63); + check(strsep(&cp, ",") == NULL, 64); /* Persistence. */ + + cp = strcpy(one, "a,b, c,, ,d,"); + equal(strsep(&cp, "xy,"), "a", 65); /* Different separators. */ + equal(strsep(&cp, "x,y"), "b", 66); + equal(strsep(&cp, ",xy"), " c", 67); /* Permute list too. */ + equal(strsep(&cp, "xy,"), "", 68); + equal(strsep(&cp, "x,y"), " ", 69); + equal(strsep(&cp, ",xy"), "d", 70); + equal(strsep(&cp, "xy,"), "", 71); + check(strsep(&cp, "x,y") == NULL, 72); + check(strsep(&cp, ",xy") == NULL, 73); /* Persistence. */ } void diff --git a/sysdeps/generic/strsep.c b/sysdeps/generic/strsep.c index b5ea6ea..1c20eb0 100644 --- a/sysdeps/generic/strsep.c +++ b/sysdeps/generic/strsep.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1992, 1993, 1996, 1997 Free Software Foundation, Inc. +/* Copyright (C) 1992, 1993, 1996, 1997, 1998 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 @@ -26,7 +26,7 @@ __strsep (char **stringp, const char *delim) char *begin, *end; begin = *stringp; - if (! begin || *begin == '\0') + if (begin == NULL) return NULL; /* A frequent case is when the delimiter string contains only one @@ -40,10 +40,10 @@ __strsep (char **stringp, const char *delim) end = NULL; else { - while (*begin == ch) - ++begin; - - end = strchr (begin, delim[0]); + if (*begin == ch) + end = begin; + else + end = strchr (begin, delim[0]); } } else -- 2.7.4