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