1 /*****************************************************************************\
2  *  $Id$
3  *****************************************************************************
4  *  Copyright (C) 2001-2006 The Regents of the University of California.
5  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
6  *  Written by Jim Garlick <garlick@llnl.gov>.
7  *  UCRL-CODE-2003-005.
8  *
9  *  This file is part of Pdsh, a parallel remote shell program.
10  *  For details, see <http://www.llnl.gov/linux/pdsh/>.
11  *
12  *  Pdsh is free software; you can redistribute it and/or modify it under
13  *  the terms of the GNU General Public License as published by the Free
14  *  Software Foundation; either version 2 of the License, or (at your option)
15  *  any later version.
16  *
17  *  Pdsh is distributed in the hope that it will be useful, but WITHOUT ANY
18  *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19  *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
20  *  details.
21  *
22  *  You should have received a copy of the GNU General Public License along
23  *  with Pdsh; if not, write to the Free Software Foundation, Inc.,
24  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
25 \*****************************************************************************/
26 
27 /*
28  * Heap-oriented string functions.
29  */
30 
31 #if     HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 
35 #include <string.h>
36 #if 	HAVE_STRERROR_R && !HAVE_DECL_STRERROR_R
37 char *strerror_r(int, char *, int);
38 #endif
39 #include <errno.h>
40 #if	HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 #include <assert.h>
44 
45 #include "xmalloc.h"
46 #include "xstring.h"
47 
48 #define SPACES "\n\t "
49 
50 #define XFGETS_CHUNKSIZE 32
51 
52 /*
53  * Zap leading and trailing occurrences of characters in 'verboten'.
54  *   str (IN/OUT)	string
55  *   verboten (IN)	list of characters to be zapped (if NULL, zap spaces)
56  */
xstrcln(char * str,char * verboten)57 void xstrcln(char *str, char *verboten)
58 {
59     char *p;
60     char *base = str;
61 
62     if (verboten == NULL)
63         verboten = SPACES;
64 
65     /* move pointer past initial 'verboten' characters */
66     while (str != NULL && *str != '\0' && strchr(verboten, *str) != NULL)
67         str++;
68 
69     /* overwrite trailing 'verboten' characters with nulls */
70     if (str != NULL && strlen(str) > 0) {
71         p = str + strlen(str) - 1;
72         while (p > str && *p != '\0' && strchr(verboten, *p) != NULL)
73             *p-- = '\0';
74     }
75 
76     /* move string */
77     assert(str >= base);
78     memmove(base, str, strlen(str));
79     while (str-- > base)
80         base[strlen(base) - 1] = '\0';
81 }
82 
83 /*
84  * Ensure that a string has enough space to add 'needed' characters.
85  * If the string is uninitialized, it should be NULL.
86  */
_makespace(char ** str,int needed)87 static void _makespace(char **str, int needed)
88 {
89     int used;
90 
91     if (*str == NULL)
92         *str = Malloc(needed + 1);
93     else {
94         used = strlen(*str) + 1;
95         while (used + needed > Size(*str)) {
96             int newsize = Size(*str) + XFGETS_CHUNKSIZE;
97 
98             Realloc((void **) str, newsize);
99             assert(Size(*str) == newsize);
100         }
101     }
102 }
103 
104 /*
105  * Concatenate str2 onto str1, expanding str1 as needed.
106  *   str1 (IN/OUT)	target string (pointer to in case of expansion)
107  *   str2 (IN)		source string
108  */
xstrcat(char ** str1,char * str2)109 void xstrcat(char **str1, char *str2)
110 {
111     _makespace(str1, strlen(str2));
112     strcat(*str1, str2);
113 }
114 
115 /*
116  * Copy str2 to str1, expanding str1 as needed.
117  *   str1 (IN/OUT)	target string (pointer to in case of expansion)
118  *   str2 (IN)		source string
119  */
xstrcpy(char ** str1,char * str2)120 void xstrcpy(char **str1, char *str2)
121 {
122     _makespace(str1, strlen(str2));
123     strcpy(*str1, str2);
124 }
125 
_strcatchar(char * str,char c)126 static void _strcatchar(char *str, char c)
127 {
128     int len = strlen(str);
129 
130     str[len++] = c;
131     str[len] = '\0';
132 }
133 
134 /*
135  * Add a character to str, expanding str1 as needed.
136  *   str1 (IN/OUT)	target string (pointer to in case of expansion)
137  *   size (IN/OUT)	size of str1 (pointer to in case of expansion)
138  *   c (IN)		character to add
139  */
xstrcatchar(char ** str,char c)140 void xstrcatchar(char **str, char c)
141 {
142     _makespace(str, 1);
143     _strcatchar(*str, c);
144 }
145 
xstrerrorcat(char ** buf)146 void xstrerrorcat(char **buf)
147 {
148 #if HAVE_STRERROR_R
149 #  if HAVE_WORKING_STRERROR_R || STRERROR_R_CHAR_P
150     char errbuf[64];
151     char *err = strerror_r(errno, errbuf, 64);
152 #  else
153     char err[64];
154     int e = errno;
155     if (strerror_r(e, err, 64) < 0) {
156         if (errno == EINVAL)
157 	    snprintf (err, 64, "Unknown error %d", e);
158 	err[63] = '\0';
159     }
160 #  endif
161 #elif HAVE_STRERROR
162     char *err = strerror(errno);
163 #else
164     extern char *sys_errlist[];
165     char *err = sys_errlist[errno];
166 #endif
167     xstrcat(buf, err);
168 }
169 
170 
171 /*
172  * Replacement for libc basename
173  *   path (IN)		path possibly containing '/' characters
174  *   RETURN		last component of path
175  */
xbasename(char * path)176 char *xbasename(char *path)
177 {
178     char *p;
179 
180     p = strrchr(path, '/');
181     return (p ? (p + 1) : path);
182 }
183 
184 
185 /*
186  * vi:tabstop=4 shiftwidth=4 expandtab
187  */
188