]> git.ipfire.org Git - thirdparty/bash.git/blobdiff - stringlib.c
Bash-4.3 patch 32
[thirdparty/bash.git] / stringlib.c
index 7bc8b495a0793bdc1dce4c1afb9cbb254caba2db..95092993adfa4e3a24e5da64e07aabf6d40794f6 100644 (file)
@@ -1,23 +1,22 @@
 /* stringlib.c - Miscellaneous string functions. */
 
-/* Copyright (C) 1996
-   Free Software Foundation, Inc.
+/* Copyright (C) 1996-2009 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
-   Bash 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.
+   Bash 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 3 of the License, or
+   (at your option) any later version.
 
-   Bash 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.
+   Bash 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 Bash; see the file COPYING.  If not, write to the Free Software
-   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+   You should have received a copy of the GNU General Public License
+   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
+*/
 
 #include "config.h"
 
 
 #include "bashansi.h"
 #include <stdio.h>
-#include <ctype.h>
+#include "chartypes.h"
 
 #include "shell.h"
+#include "pathexp.h"
 
-#ifndef to_upper
-#  define to_upper(c) (islower(c) ? toupper(c) : (c))
-#  define to_lower(c) (isupper(c) ? tolower(c) : (c))
-#endif
+#include <glob/glob.h>
 
-/* Convert STRING by expanding the escape sequences specified by the
-   ANSI C standard.  If SAWC is non-null, recognize `\c' and use that
-   as a string terminator.  If we see \c, set *SAWC to 1 before
-   returning.  LEN is the length of STRING. */
-char *
-ansicstr (string, len, sawc)
-     char *string;
-     int len, *sawc;
-{
-  int c;
-  char *ret, *r, *s;
-
-  if (string == 0 || *string == '\0')
-    return ((char *)NULL);
-
-  ret = xmalloc (len + 1);
-  for (r = ret, s = string; s && *s; )
-    {
-      c = *s++;
-      if (c != '\\' || *s == '\0')
-        *r++ = c;
-      else
-       {
-         switch (c = *s++)
-           {
-#if defined (__STDC__)
-           case 'a': c = '\a'; break;
-           case 'v': c = '\v'; break;
-#else
-           case 'a': c = '\007'; break;
-           case 'v': c = (int) 0x0B; break;
+#if defined (EXTENDED_GLOB)
+#  include <glob/strmatch.h>
 #endif
-           case 'b': c = '\b'; break;
-           case 'e': c = '\033'; break;        /* ESC -- non-ANSI */
-           case 'E': c = '\033'; break;        /* ESC -- non-ANSI */
-           case 'f': c = '\f'; break;
-           case 'n': c = '\n'; break;
-           case 'r': c = '\r'; break;
-           case 't': c = '\t'; break;
-           case '0': case '1': case '2': case '3':
-           case '4': case '5': case '6': case '7':
-             c -= '0';
-             if (*s >= '0' && *s <= '7')
-               c = c * 8 + (*s++ - '0');
-             if (*s >= '0' && *s <= '7')
-               c = c * 8 + (*s++ - '0');
-             break;
-           case '\\':
-           case '\'':
-             break;
-           case 'c':
-             if (sawc)
-               {
-                 *sawc = 1;
-                 *r = '\0';
-                 return ret;
-               }
-           default:  *r++ = '\\'; break;
-           }
-         *r++ = c;
-       }
-    }
-  *r = '\0';
-  return ret;
-}
 
 /* **************************************************************** */
 /*                                                                 */
@@ -110,161 +45,74 @@ ansicstr (string, len, sawc)
 /*                                                                 */
 /* **************************************************************** */
 
-/* Find NAME in ARRAY.  Return the index of NAME, or -1 if not present.
-   ARRAY should be NULL terminated. */
-int
-find_name_in_array (name, array)
-     char *name, **array;
-{
-  int i;
-
-  for (i = 0; array[i]; i++)
-    if (STREQ (name, array[i]))
-      return (i);
-
-  return (-1);
-}
-
-/* Return the length of ARRAY, a NULL terminated array of char *. */
+/* Find STRING in ALIST, a list of string key/int value pairs.  If FLAGS
+   is 1, STRING is treated as a pattern and matched using strmatch. */
 int
-array_len (array)
-     char **array;
-{
-  register int i;
-
-  for (i = 0; array[i]; i++);
-  return (i);
-}
-
-/* Free the contents of ARRAY, a NULL terminated array of char *. */
-void
-free_array_members (array)
-     char **array;
+find_string_in_alist (string, alist, flags)
+     char *string;
+     STRING_INT_ALIST *alist;
+     int flags;
 {
   register int i;
+  int r;
 
-  if (array == 0)
-    return;
-
-  for (i = 0; array[i]; i++)
-    free (array[i]);
-}
-
-void
-free_array (array)
-     char **array;
-{
-  if (array == 0)
-    return;
+  for (i = r = 0; alist[i].word; i++)
+    {
+#if defined (EXTENDED_GLOB)
+      if (flags)
+       r = strmatch (alist[i].word, string, FNM_EXTMATCH) != FNM_NOMATCH;
+      else
+#endif
+       r = STREQ (string, alist[i].word);
 
-  free_array_members (array);
-  free (array);
+      if (r)
+       return (alist[i].token);
+    }
+  return -1;
 }
 
-/* Allocate and return a new copy of ARRAY and its contents. */
-char **
-copy_array (array)
-     char **array;
+/* Find TOKEN in ALIST, a list of string/int value pairs.  Return the
+   corresponding string.  Allocates memory for the returned
+   string.  FLAGS is currently ignored, but reserved. */
+char *
+find_token_in_alist (token, alist, flags)
+     int token;
+     STRING_INT_ALIST *alist;
+     int flags;
 {
   register int i;
-  int len;
-  char **new_array;
-
-  len = array_len (array);
 
-  new_array = (char **)xmalloc ((len + 1) * sizeof (char *));
-  for (i = 0; array[i]; i++)
-    new_array[i] = savestring (array[i]);
-  new_array[i] = (char *)NULL;
-
-  return (new_array);
+  for (i = 0; alist[i].word; i++)
+    {
+      if (alist[i].token == token)
+        return (savestring (alist[i].word));
+    }
+  return ((char *)NULL);
 }
 
-/* Comparison routine for use with qsort() on arrays of strings.  Uses
-   strcoll(3) if available, otherwise it uses strcmp(3). */
 int
-qsort_string_compare (s1, s2)
-     register char **s1, **s2;
-{
-#if defined (HAVE_STRCOLL)
-   return (strcoll (*s1, *s2));
-#else /* !HAVE_STRCOLL */
-  int result;
-
-  if ((result = **s1 - **s2) == 0)
-    result = strcmp (*s1, *s2);
-
-  return (result);
-#endif /* !HAVE_STRCOLL */
-}
-
-/* Sort ARRAY, a null terminated array of pointers to strings. */
-void
-sort_char_array (array)
-     char **array;
-{
-  qsort (array, array_len (array), sizeof (char *),
-        (Function *)qsort_string_compare);
-}
-
-/* Cons up a new array of words.  The words are taken from LIST,
-   which is a WORD_LIST *.  If COPY is true, everything is malloc'ed,
-   so you should free everything in this array when you are done.
-   The array is NULL terminated.  If IP is non-null, it gets the
-   number of words in the returned array.  STARTING_INDEX says where
-   to start filling in the returned array; it can be used to reserve
-   space at the beginning of the array. */
-char **
-word_list_to_argv (list, copy, starting_index, ip)
-     WORD_LIST *list;
-     int copy, starting_index, *ip;
-{
-  int count;
-  char **array;
-
-  count = list_length (list);
-  array = (char **)xmalloc ((1 + count + starting_index) * sizeof (char *));
-
-  for (count = 0; count < starting_index; count++)
-    array[count] = (char *)NULL;
-  for (count = starting_index; list; count++, list = list->next)
-    array[count] = copy ? savestring (list->word->word) : list->word->word;
-  array[count] = (char *)NULL;
-
-  if (ip)
-    *ip = count;
-  return (array);
-}
-
-/* Convert an array of strings into the form used internally by the shell.
-   COPY means to copy the values in ARRAY into the returned list rather
-   than allocate new storage.  STARTING_INDEX says where in ARRAY to begin. */
-WORD_LIST *
-argv_to_word_list (array, copy, starting_index)
-     char **array;
-     int copy, starting_index;
+find_index_in_alist (string, alist, flags)
+     char *string;
+     STRING_INT_ALIST *alist;
+     int flags;
 {
-  WORD_LIST *list;
-  WORD_DESC *w;
-  int i, count;
-
-  if (array == 0 || array[0] == 0)
-    return (WORD_LIST *)NULL;
-
-  for (count = 0; array[count]; count++)
-    ;
+  register int i;
+  int r;
 
-  for (i = starting_index, list = (WORD_LIST *)NULL; i < count; i++)
+  for (i = r = 0; alist[i].word; i++)
     {
-      w = make_bare_word (copy ? "" : array[i]);
-      if (copy)
-       {
-         free (w->word);
-         w->word = array[i];
-       }
-      list = make_word_list (w, list);
+#if defined (EXTENDED_GLOB)
+      if (flags)
+       r = strmatch (alist[i].word, string, FNM_EXTMATCH) != FNM_NOMATCH;
+      else
+#endif
+       r = STREQ (string, alist[i].word);
+
+      if (r)
+       return (i);
     }
-  return (REVERSE_LIST(list, WORD_LIST *));
+
+  return -1;
 }
 
 /* **************************************************************** */
@@ -273,6 +121,23 @@ argv_to_word_list (array, copy, starting_index)
 /*                                                                 */
 /* **************************************************************** */
 
+/* Cons a new string from STRING starting at START and ending at END,
+   not including END. */
+char *
+substring (string, start, end)
+     const char *string;
+     int start, end;
+{
+  register int len;
+  register char *result;
+
+  len = end - start;
+  result = (char *)xmalloc (len + 1);
+  memcpy (result, string + start, len);
+  result[len] = '\0';
+  return (result);
+}
+
 /* Replace occurrences of PAT with REP in STRING.  If GLOBAL is non-zero,
    replace all occurrences, otherwise replace only the first.
    This returns a new string; the caller should free it. */
@@ -281,32 +146,97 @@ strsub (string, pat, rep, global)
      char *string, *pat, *rep;
      int global;
 {
-  int patlen, templen, tempsize, repl, i;
+  int patlen, replen, templen, tempsize, repl, i;
   char *temp, *r;
 
   patlen = strlen (pat);
+  replen = strlen (rep);
   for (temp = (char *)NULL, i = templen = tempsize = 0, repl = 1; string[i]; )
     {
       if (repl && STREQN (string + i, pat, patlen))
-        {
-          RESIZE_MALLOCED_BUFFER (temp, templen, patlen, tempsize, (patlen * 2));
+       {
+         if (replen)
+           RESIZE_MALLOCED_BUFFER (temp, templen, replen, tempsize, (replen * 2));
 
-         for (r = rep; *r; )
+         for (r = rep; *r; )   /* can rep == "" */
            temp[templen++] = *r++;
 
-         i += patlen;
+         i += patlen ? patlen : 1;     /* avoid infinite recursion */
          repl = global != 0;
-        }
+       }
       else
        {
          RESIZE_MALLOCED_BUFFER (temp, templen, 1, tempsize, 16);
          temp[templen++] = string[i++];
        }
     }
-  temp[templen] = 0;
+  if (temp)
+    temp[templen] = 0;
+  else
+    temp = savestring (string);
   return (temp);
 }
 
+/* Replace all instances of C in STRING with TEXT.  TEXT may be empty or
+   NULL.  If DO_GLOB is non-zero, we quote the replacement text for
+   globbing.  Backslash may be used to quote C. */
+char *
+strcreplace (string, c, text, do_glob)
+     char *string;
+     int c;
+     char *text;
+     int do_glob;
+{
+  char *ret, *p, *r, *t;
+  int len, rlen, ind, tlen;
+
+  len = STRLEN (text);
+  rlen = len + strlen (string) + 2;
+  ret = (char *)xmalloc (rlen);
+
+  for (p = string, r = ret; p && *p; )
+    {
+      if (*p == c)
+       {
+         if (len)
+           {
+             ind = r - ret;
+             if (do_glob && (glob_pattern_p (text) || strchr (text, '\\')))
+               {
+                 t = quote_globbing_chars (text);
+                 tlen = strlen (t);
+                 RESIZE_MALLOCED_BUFFER (ret, ind, tlen, rlen, rlen);
+                 r = ret + ind;        /* in case reallocated */
+                 strcpy (r, t);
+                 r += tlen;
+                 free (t);
+               }
+             else
+               {
+                 RESIZE_MALLOCED_BUFFER (ret, ind, len, rlen, rlen);
+                 r = ret + ind;        /* in case reallocated */
+                 strcpy (r, text);
+                 r += len;
+               }
+           }
+         p++;
+         continue;
+       }
+
+      if (*p == '\\' && p[1] == c)
+       p++;
+
+      ind = r - ret;
+      RESIZE_MALLOCED_BUFFER (ret, ind, 2, rlen, rlen);
+      r = ret + ind;                   /* in case reallocated */
+      *r++ = *p++;
+    }
+  *r = '\0';
+
+  return ret;
+}
+
+#ifdef INCLUDE_UNUSED
 /* Remove all leading whitespace from STRING.  This includes
    newlines.  STRING should be terminated with a zero. */
 void
@@ -325,44 +255,28 @@ strip_leading (string)
       start[len] = '\0';
     }
 }
+#endif
 
 /* Remove all trailing whitespace from STRING.  This includes
    newlines.  If NEWLINES_ONLY is non-zero, only trailing newlines
    are removed.  STRING should be terminated with a zero. */
 void
-strip_trailing (string, newlines_only)
+strip_trailing (string, len, newlines_only)
      char *string;
+     int len;
      int newlines_only;
 {
-  int len = strlen (string) - 1;
-
   while (len >= 0)
     {
       if ((newlines_only && string[len] == '\n') ||
-          (!newlines_only && whitespace (string[len])))
-        len--;
+         (!newlines_only && whitespace (string[len])))
+       len--;
       else
-        break;
+       break;
     }
   string[len + 1] = '\0';
 }
 
-/* Determine if s2 occurs in s1.  If so, return a pointer to the
-   match in s1.  The compare is case insensitive.  This is a
-   case-insensitive strstr(3). */
-char *
-strindex (s1, s2)
-     char *s1, *s2;
-{
-  register int i, l, len, c;
-
-  c = to_upper (s2[0]);
-  for (i = 0, len = strlen (s1), l = strlen (s2); (len - i) >= l; i++)
-    if ((to_upper (s1[i]) == c) && (strncasecmp (s1 + i, s2, l) == 0))
-      return (s1 + i);
-  return ((char *)NULL);
-}
-
 /* A wrapper for bcopy that can be prototyped in general.h */
 void
 xbcopy (s, d, n)