diff options
Diffstat (limited to 'sysdeps/generic')
-rw-r--r-- | sysdeps/generic/getenv.c | 68 |
1 files changed, 62 insertions, 6 deletions
diff --git a/sysdeps/generic/getenv.c b/sysdeps/generic/getenv.c index 990ddfd93f..b6f405df08 100644 --- a/sysdeps/generic/getenv.c +++ b/sysdeps/generic/getenv.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991, 1992, 1994, 1996 Free Software Foundation, Inc. +/* Copyright (C) 1991, 1992, 1994, 1996, 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 @@ -16,7 +16,9 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <endian.h> #include <errno.h> +#include <stdint.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -25,20 +27,74 @@ #define __environ environ #endif -/* Return the value of the environment variable NAME. */ +/* Return the value of the environment variable NAME. This implementation + is tuned a bit in that it assumes no environment variable has an empty + name which of course should always be true. We have a special case for + one character names so that for the general case we can assume at least + two characters which we can access. By doing this we can avoid using the + `strncmp' most of the time. */ char * getenv (name) const char *name; { const size_t len = strlen (name); char **ep; + uint16_t name_start; - if (__environ == NULL) + if (__environ == NULL || name[0] == '\0') return NULL; - for (ep = __environ; *ep != NULL; ++ep) - if (!strncmp (*ep, name, len) && (*ep)[len] == '=') - return &(*ep)[len + 1]; + if (name[1] == '\0') + { + /* The name of the variable consists of only one character. Therefore + the first two characters of the environment entry are this character + and a '=' character. */ +#if __BYTE_ORDER == __LITTLE_ENDIAN + name_start = ('=' << 8) | *(const unsigned char *) name; +#else +# if __BYTE_ORDER == __BIG_ENDIAN + name_start = '=' | ((*(const unsigned char *) name) << 8); +# else + #error "Funny byte order." +# endif +#endif + for (ep = __environ; *ep != NULL; ++ep) + { +#if _STRING_ARCH_unaligned + uint16_t ep_start = *(uint16_t *) *ep; +#else + uint16_t ep_start = (((unsigned char *) *ep)[0] + | (((unsigned char *) *ep)[1] << 8)); +#endif + if (name_start == ep_start) + return &(*ep)[2]; + } + } + else + { +#if _STRING_ARCH_unaligned + name_start = *(const uint16_t *) name; +#else + name_start = (((const unsigned char *) name)[0] + | (((const unsigned char *) name)[1] << 8)); +#endif + len -= 2; + name += 2; + + for (ep = __environ; *ep != NULL; ++ep) + { +#if _STRING_ARCH_unaligned + uint16_t ep_start = *(uint16_t *) *ep; +#else + uint16_t ep_start = (((unsigned char *) *ep)[0] + | (((unsigned char *) *ep)[1] << 8)); +#endif + + if (name_start == ep_start && !strncmp (*ep + 2, name, len) + && (*ep)[len + 2] == '=') + return &(*ep)[len + 3]; + } + } return NULL; } |