1174294Sobrien/*
2174294Sobrien * Copyright (c) 1997-2006 Erez Zadok
3174294Sobrien * Copyright (c) 1990 Jan-Simon Pendry
4174294Sobrien * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5174294Sobrien * Copyright (c) 1990 The Regents of the University of California.
6174294Sobrien * All rights reserved.
7174294Sobrien *
8174294Sobrien * This code is derived from software contributed to Berkeley by
9174294Sobrien * Jan-Simon Pendry at Imperial College, London.
10174294Sobrien *
11174294Sobrien * Redistribution and use in source and binary forms, with or without
12174294Sobrien * modification, are permitted provided that the following conditions
13174294Sobrien * are met:
14174294Sobrien * 1. Redistributions of source code must retain the above copyright
15174294Sobrien *    notice, this list of conditions and the following disclaimer.
16174294Sobrien * 2. Redistributions in binary form must reproduce the above copyright
17174294Sobrien *    notice, this list of conditions and the following disclaimer in the
18174294Sobrien *    documentation and/or other materials provided with the distribution.
19174294Sobrien * 3. All advertising materials mentioning features or use of this software
20174294Sobrien *    must display the following acknowledgment:
21174294Sobrien *      This product includes software developed by the University of
22174294Sobrien *      California, Berkeley and its contributors.
23174294Sobrien * 4. Neither the name of the University nor the names of its contributors
24174294Sobrien *    may be used to endorse or promote products derived from this software
25174294Sobrien *    without specific prior written permission.
26174294Sobrien *
27174294Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28174294Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29174294Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30174294Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31174294Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32174294Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33174294Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34174294Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35174294Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36174294Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37174294Sobrien * SUCH DAMAGE.
38174294Sobrien *
39174294Sobrien *
40174294Sobrien * File: am-utils/libamu/strutil.c
41174294Sobrien *
42174294Sobrien */
43174294Sobrien
44174294Sobrien/*
45174294Sobrien * String Utilities.
46174294Sobrien */
47174294Sobrien
48174294Sobrien#ifdef HAVE_CONFIG_H
49174294Sobrien# include <config.h>
50174294Sobrien#endif /* HAVE_CONFIG_H */
51174294Sobrien#include <am_defs.h>
52174294Sobrien#include <amu.h>
53174294Sobrien
54174294Sobrien
55174294Sobrienchar *
56174294Sobrienstrnsave(const char *str, int len)
57174294Sobrien{
58174294Sobrien  char *sp = (char *) xmalloc(len + 1);
59174294Sobrien  memmove(sp, str, len);
60174294Sobrien  sp[len] = '\0';
61174294Sobrien
62174294Sobrien  return sp;
63174294Sobrien}
64174294Sobrien
65174294Sobrien
66174294Sobrien/*
67174294Sobrien * Concatenate three strings and store the result in the buffer pointed to
68174294Sobrien * by p, making p large enough to hold the strings
69174294Sobrien */
70174294Sobrienchar *
71174294Sobrienstr3cat(char *p, char *s1, char *s2, char *s3)
72174294Sobrien{
73174294Sobrien  int l1 = strlen(s1);
74174294Sobrien  int l2 = strlen(s2);
75174294Sobrien  int l3 = strlen(s3);
76174294Sobrien
77174294Sobrien  p = (char *) xrealloc(p, l1 + l2 + l3 + 1);
78174294Sobrien  memmove(p, s1, l1);
79174294Sobrien  memmove(p + l1, s2, l2);
80174294Sobrien  memmove(p + l1 + l2, s3, l3 + 1);
81174294Sobrien  return p;
82174294Sobrien}
83174294Sobrien
84174294Sobrien
85174294Sobrien/*
86174294Sobrien * Split s using ch as delimiter and qc as quote character
87174294Sobrien */
88174294Sobrienchar **
89174294Sobrienstrsplit(char *s, int ch, int qc)
90174294Sobrien{
91174294Sobrien  char **ivec;
92174294Sobrien  int ic = 0;
93174294Sobrien  int done = 0;
94174294Sobrien
95174294Sobrien  ivec = (char **) xmalloc((ic + 1) * sizeof(char *));
96174294Sobrien
97174294Sobrien  while (!done) {
98174294Sobrien    char *v;
99174294Sobrien
100174294Sobrien    /*
101174294Sobrien     * skip to split char
102174294Sobrien     */
103174294Sobrien    while (*s && (ch == ' ' ? (isascii((unsigned char)*s) && isspace((unsigned char)*s)) : *s == ch))
104174294Sobrien      *s++ = '\0';
105174294Sobrien
106174294Sobrien    /*
107174294Sobrien     * End of string?
108174294Sobrien     */
109174294Sobrien    if (!*s)
110174294Sobrien      break;
111174294Sobrien
112174294Sobrien    /*
113174294Sobrien     * remember start of string
114174294Sobrien     */
115174294Sobrien    v = s;
116174294Sobrien
117174294Sobrien    /*
118174294Sobrien     * skip to split char
119174294Sobrien     */
120174294Sobrien    while (*s && !(ch == ' ' ? (isascii((unsigned char)*s) && isspace((unsigned char)*s)) : *s == ch)) {
121174294Sobrien      if (*s++ == qc) {
122174294Sobrien	/*
123174294Sobrien	 * Skip past string.
124174294Sobrien	 */
125174294Sobrien	s++;
126174294Sobrien	while (*s && *s != qc)
127174294Sobrien	  s++;
128174294Sobrien	if (*s == qc)
129174294Sobrien	  s++;
130174294Sobrien      }
131174294Sobrien    }
132174294Sobrien
133174294Sobrien    if (!*s)
134174294Sobrien      done = 1;
135174294Sobrien    *s++ = '\0';
136174294Sobrien
137174294Sobrien    /*
138174294Sobrien     * save string in new ivec slot
139174294Sobrien     */
140174294Sobrien    ivec[ic++] = v;
141174294Sobrien    ivec = (char **) xrealloc((voidp) ivec, (ic + 1) * sizeof(char *));
142174294Sobrien    if (amuDebug(D_STR))
143174294Sobrien      plog(XLOG_DEBUG, "strsplit saved \"%s\"", v);
144174294Sobrien  }
145174294Sobrien
146174294Sobrien  if (amuDebug(D_STR))
147174294Sobrien    plog(XLOG_DEBUG, "strsplit saved a total of %d strings", ic);
148174294Sobrien
149174294Sobrien  ivec[ic] = NULL;
150174294Sobrien
151174294Sobrien  return ivec;
152174294Sobrien}
153174294Sobrien
154174294Sobrien
155174294Sobrien/*
156174294Sobrien * Use generic strlcpy to copy a string more carefully, null-terminating it
157174294Sobrien * as needed.  However, if the copied string was truncated due to lack of
158174294Sobrien * space, then warn us.
159174294Sobrien *
160174294Sobrien * For now, xstrlcpy returns VOID because it doesn't look like anywhere in
161174294Sobrien * the Amd code do we actually use the return value of strncpy/strlcpy.
162174294Sobrien */
163174294Sobrienvoid
164174294Sobrien#ifdef DEBUG
165174294Sobrien_xstrlcpy(const char *filename, int lineno, char *dst, const char *src, size_t len)
166174294Sobrien#else /* not DEBUG */
167174294Sobrienxstrlcpy(char *dst, const char *src, size_t len)
168174294Sobrien#endif /* not DEBUG */
169174294Sobrien{
170174294Sobrien  if (len == 0)
171174294Sobrien    return;
172174294Sobrien  if (strlcpy(dst, src, len) >= len)
173174294Sobrien#ifdef DEBUG
174174294Sobrien    plog(XLOG_ERROR, "xstrlcpy(%s:%d): string \"%s\" truncated to \"%s\"",
175174294Sobrien	 filename, lineno, src, dst);
176174294Sobrien#else /* not DEBUG */
177174294Sobrien    plog(XLOG_ERROR, "xstrlcpy: string \"%s\" truncated to \"%s\"", src, dst);
178174294Sobrien#endif /* not DEBUG */
179174294Sobrien}
180174294Sobrien
181174294Sobrien
182174294Sobrien/*
183174294Sobrien * Use generic strlcat to concatenate a string more carefully,
184174294Sobrien * null-terminating it as needed.  However, if the copied string was
185174294Sobrien * truncated due to lack of space, then warn us.
186174294Sobrien *
187174294Sobrien * For now, xstrlcat returns VOID because it doesn't look like anywhere in
188174294Sobrien * the Amd code do we actually use the return value of strncat/strlcat.
189174294Sobrien */
190174294Sobrienvoid
191174294Sobrien#ifdef DEBUG
192174294Sobrien_xstrlcat(const char *filename, int lineno, char *dst, const char *src, size_t len)
193174294Sobrien#else /* not DEBUG */
194174294Sobrienxstrlcat(char *dst, const char *src, size_t len)
195174294Sobrien#endif /* not DEBUG */
196174294Sobrien{
197174294Sobrien  if (len == 0)
198174294Sobrien    return;
199174294Sobrien  if (strlcat(dst, src, len) >= len) {
200174294Sobrien    /* strlcat does not null terminate if the size of src is equal to len. */
201174294Sobrien    dst[strlen(dst) - 1] = '\0';
202174294Sobrien#ifdef DEBUG
203174294Sobrien    plog(XLOG_ERROR, "xstrlcat(%s:%d): string \"%s\" truncated to \"%s\"",
204174294Sobrien	 filename, lineno, src, dst);
205174294Sobrien#else /* not DEBUG */
206174294Sobrien    plog(XLOG_ERROR, "xstrlcat: string \"%s\" truncated to \"%s\"", src, dst);
207174294Sobrien#endif /* not DEBUG */
208174294Sobrien  }
209174294Sobrien}
210174294Sobrien
211174294Sobrien
212174294Sobrien/* our version of snprintf */
213174294Sobrienint
214174294Sobrien#if defined(DEBUG) && (defined(HAVE_C99_VARARGS_MACROS) || defined(HAVE_GCC_VARARGS_MACROS))
215174294Sobrien_xsnprintf(const char *filename, int lineno, char *str, size_t size, const char *format, ...)
216174294Sobrien#else /* not DEBUG or no C99/GCC-style vararg cpp macros supported */
217174294Sobrienxsnprintf(char *str, size_t size, const char *format, ...)
218174294Sobrien#endif /* not DEBUG or no C99/GCC-style vararg cpp macros supported */
219174294Sobrien{
220174294Sobrien  va_list ap;
221174294Sobrien  int ret = 0;
222174294Sobrien
223174294Sobrien  va_start(ap, format);
224174294Sobrien#if defined(DEBUG) && (defined(HAVE_C99_VARARGS_MACROS) || defined(HAVE_GCC_VARARGS_MACROS))
225174294Sobrien  ret = _xvsnprintf(filename, lineno, str, size, format, ap);
226174294Sobrien#else /* not DEBUG or no C99/GCC-style vararg cpp macros supported */
227174294Sobrien  ret = xvsnprintf(str, size, format, ap);
228174294Sobrien#endif /* not DEBUG or no C99/GCC-style vararg cpp macros supported */
229174294Sobrien  va_end(ap);
230174294Sobrien
231174294Sobrien  return ret;
232174294Sobrien}
233174294Sobrien
234174294Sobrien
235174294Sobrien/* our version of vsnprintf */
236174294Sobrienint
237174294Sobrien#if defined(DEBUG) && (defined(HAVE_C99_VARARGS_MACROS) || defined(HAVE_GCC_VARARGS_MACROS))
238174294Sobrien_xvsnprintf(const char *filename, int lineno, char *str, size_t size, const char *format, va_list ap)
239174294Sobrien#else /* not DEBUG or no C99/GCC-style vararg cpp macros supported */
240174294Sobrienxvsnprintf(char *str, size_t size, const char *format, va_list ap)
241174294Sobrien#endif /* not DEBUG or no C99/GCC-style vararg cpp macros supported */
242174294Sobrien{
243174294Sobrien  int ret = 0;
244174294Sobrien
245174294Sobrien#ifdef HAVE_VSNPRINTF
246174294Sobrien  ret = vsnprintf(str, size, format, ap);
247174294Sobrien#else /* not HAVE_VSNPRINTF */
248174294Sobrien  ret = vsprintf(str, format, ap); /* less secure version */
249174294Sobrien#endif /* not HAVE_VSNPRINTF */
250174294Sobrien  /*
251174294Sobrien   * If error or truncation, plog error.
252174294Sobrien   *
253174294Sobrien   * WARNING: we use the static 'maxtrunc' variable below to break out any
254174294Sobrien   * possible infinite recursion between plog() and xvsnprintf().  If it
255174294Sobrien   * ever happens, it'd indicate a bug in Amd.
256174294Sobrien   */
257174294Sobrien  if (ret < 0 || (size_t) ret >= size) { /* error or truncation occured */
258174294Sobrien    static int maxtrunc;        /* hack to avoid inifinite loop */
259174294Sobrien    if (++maxtrunc > 10)
260174294Sobrien#if defined(DEBUG) && (defined(HAVE_C99_VARARGS_MACROS) || defined(HAVE_GCC_VARARGS_MACROS))
261174294Sobrien      plog(XLOG_ERROR, "xvsnprintf(%s:%d): string %p truncated (ret=%d, format=\"%s\")",
262174294Sobrien           filename, lineno, str, ret, format);
263174294Sobrien#else /* not DEBUG or no C99/GCC-style vararg cpp macros supported */
264174294Sobrien      plog(XLOG_ERROR, "xvsnprintf: string %p truncated (ret=%d, format=\"%s\")",
265174294Sobrien           str, ret, format);
266174294Sobrien#endif /* not DEBUG or no C99/GCC-style vararg cpp macros supported */
267174294Sobrien  }
268174294Sobrien
269174294Sobrien  return ret;
270174294Sobrien}
271