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