1/* stringlib.c - Miscellaneous string functions. */ 2 3/* Copyright (C) 1996-2002 Free Software Foundation, Inc. 4 5 This file is part of GNU Bash, the Bourne Again SHell. 6 7 Bash is free software; you can redistribute it and/or modify it under 8 the terms of the GNU General Public License as published by the Free 9 Software Foundation; either version 2, or (at your option) any later 10 version. 11 12 Bash is distributed in the hope that it will be useful, but WITHOUT ANY 13 WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 for more details. 16 17 You should have received a copy of the GNU General Public License along 18 with Bash; see the file COPYING. If not, write to the Free Software 19 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 20 21#include "config.h" 22 23#include "bashtypes.h" 24 25#if defined (HAVE_UNISTD_H) 26# include <unistd.h> 27#endif 28 29#include "bashansi.h" 30#include <stdio.h> 31#include "chartypes.h" 32 33#include "shell.h" 34#include "pathexp.h" 35 36#include <glob/glob.h> 37 38#if defined (EXTENDED_GLOB) 39# include <glob/strmatch.h> 40#endif 41 42/* **************************************************************** */ 43/* */ 44/* Functions to manage arrays of strings */ 45/* */ 46/* **************************************************************** */ 47 48/* Find STRING in ALIST, a list of string key/int value pairs. If FLAGS 49 is 1, STRING is treated as a pattern and matched using strmatch. */ 50int 51find_string_in_alist (string, alist, flags) 52 char *string; 53 STRING_INT_ALIST *alist; 54 int flags; 55{ 56 register int i; 57 int r; 58 59 for (i = r = 0; alist[i].word; i++) 60 { 61#if defined (EXTENDED_GLOB) 62 if (flags) 63 r = strmatch (alist[i].word, string, FNM_EXTMATCH) != FNM_NOMATCH; 64 else 65#endif 66 r = STREQ (string, alist[i].word); 67 68 if (r) 69 return (alist[i].token); 70 } 71 return -1; 72} 73 74/* Find TOKEN in ALIST, a list of string/int value pairs. Return the 75 corresponding string. Allocates memory for the returned 76 string. FLAGS is currently ignored, but reserved. */ 77char * 78find_token_in_alist (token, alist, flags) 79 int token; 80 STRING_INT_ALIST *alist; 81 int flags; 82{ 83 register int i; 84 85 for (i = 0; alist[i].word; i++) 86 { 87 if (alist[i].token == token) 88 return (savestring (alist[i].word)); 89 } 90 return ((char *)NULL); 91} 92 93int 94find_index_in_alist (string, alist, flags) 95 char *string; 96 STRING_INT_ALIST *alist; 97 int flags; 98{ 99 register int i; 100 int r; 101 102 for (i = r = 0; alist[i].word; i++) 103 { 104#if defined (EXTENDED_GLOB) 105 if (flags) 106 r = strmatch (alist[i].word, string, FNM_EXTMATCH) != FNM_NOMATCH; 107 else 108#endif 109 r = STREQ (string, alist[i].word); 110 111 if (r) 112 return (i); 113 } 114 115 return -1; 116} 117 118/* **************************************************************** */ 119/* */ 120/* String Management Functions */ 121/* */ 122/* **************************************************************** */ 123 124/* Cons a new string from STRING starting at START and ending at END, 125 not including END. */ 126char * 127substring (string, start, end) 128 char *string; 129 int start, end; 130{ 131 register int len; 132 register char *result; 133 134 len = end - start; 135 result = (char *)xmalloc (len + 1); 136 strncpy (result, string + start, len); 137 result[len] = '\0'; 138 return (result); 139} 140 141/* Replace occurrences of PAT with REP in STRING. If GLOBAL is non-zero, 142 replace all occurrences, otherwise replace only the first. 143 This returns a new string; the caller should free it. */ 144char * 145strsub (string, pat, rep, global) 146 char *string, *pat, *rep; 147 int global; 148{ 149 int patlen, replen, templen, tempsize, repl, i; 150 char *temp, *r; 151 152 patlen = strlen (pat); 153 replen = strlen (rep); 154 for (temp = (char *)NULL, i = templen = tempsize = 0, repl = 1; string[i]; ) 155 { 156 if (repl && STREQN (string + i, pat, patlen)) 157 { 158 if (replen) 159 RESIZE_MALLOCED_BUFFER (temp, templen, replen, tempsize, (replen * 2)); 160 161 for (r = rep; *r; ) 162 temp[templen++] = *r++; 163 164 i += patlen ? patlen : 1; /* avoid infinite recursion */ 165 repl = global != 0; 166 } 167 else 168 { 169 RESIZE_MALLOCED_BUFFER (temp, templen, 1, tempsize, 16); 170 temp[templen++] = string[i++]; 171 } 172 } 173 temp[templen] = 0; 174 return (temp); 175} 176 177/* Replace all instances of C in STRING with TEXT. TEXT may be empty or 178 NULL. If DO_GLOB is non-zero, we quote the replacement text for 179 globbing. Backslash may be used to quote C. */ 180char * 181strcreplace (string, c, text, do_glob) 182 char *string; 183 int c; 184 char *text; 185 int do_glob; 186{ 187 char *ret, *p, *r, *t; 188 int len, rlen, ind, tlen; 189 190 len = STRLEN (text); 191 rlen = len + strlen (string) + 2; 192 ret = (char *)xmalloc (rlen); 193 194 for (p = string, r = ret; p && *p; ) 195 { 196 if (*p == c) 197 { 198 if (len) 199 { 200 ind = r - ret; 201 if (do_glob && (glob_pattern_p (text) || strchr (text, '\\'))) 202 { 203 t = quote_globbing_chars (text); 204 tlen = strlen (t); 205 RESIZE_MALLOCED_BUFFER (ret, ind, tlen, rlen, rlen); 206 r = ret + ind; /* in case reallocated */ 207 strcpy (r, t); 208 r += tlen; 209 free (t); 210 } 211 else 212 { 213 RESIZE_MALLOCED_BUFFER (ret, ind, len, rlen, rlen); 214 r = ret + ind; /* in case reallocated */ 215 strcpy (r, text); 216 r += len; 217 } 218 } 219 p++; 220 continue; 221 } 222 223 if (*p == '\\' && p[1] == c) 224 p++; 225 226 ind = r - ret; 227 RESIZE_MALLOCED_BUFFER (ret, ind, 2, rlen, rlen); 228 r = ret + ind; /* in case reallocated */ 229 *r++ = *p++; 230 } 231 *r = '\0'; 232 233 return ret; 234} 235 236#ifdef INCLUDE_UNUSED 237/* Remove all leading whitespace from STRING. This includes 238 newlines. STRING should be terminated with a zero. */ 239void 240strip_leading (string) 241 char *string; 242{ 243 char *start = string; 244 245 while (*string && (whitespace (*string) || *string == '\n')) 246 string++; 247 248 if (string != start) 249 { 250 int len = strlen (string); 251 FASTCOPY (string, start, len); 252 start[len] = '\0'; 253 } 254} 255#endif 256 257/* Remove all trailing whitespace from STRING. This includes 258 newlines. If NEWLINES_ONLY is non-zero, only trailing newlines 259 are removed. STRING should be terminated with a zero. */ 260void 261strip_trailing (string, len, newlines_only) 262 char *string; 263 int len; 264 int newlines_only; 265{ 266 while (len >= 0) 267 { 268 if ((newlines_only && string[len] == '\n') || 269 (!newlines_only && whitespace (string[len]))) 270 len--; 271 else 272 break; 273 } 274 string[len + 1] = '\0'; 275} 276 277/* A wrapper for bcopy that can be prototyped in general.h */ 278void 279xbcopy (s, d, n) 280 char *s, *d; 281 int n; 282{ 283 FASTCOPY (s, d, n); 284} 285