string.c revision 258945
1258945Sroberto/*
2258945Sroberto * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
3258945Sroberto * Copyright (C) 1999-2001, 2003  Internet Software Consortium.
4258945Sroberto *
5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any
6258945Sroberto * purpose with or without fee is hereby granted, provided that the above
7258945Sroberto * copyright notice and this permission notice appear in all copies.
8258945Sroberto *
9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11258945Sroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15258945Sroberto * PERFORMANCE OF THIS SOFTWARE.
16258945Sroberto */
17258945Sroberto
18258945Sroberto/* $Id: string.c,v 1.20 2007/06/19 23:47:17 tbox Exp $ */
19258945Sroberto
20258945Sroberto/*! \file */
21258945Sroberto
22258945Sroberto#include <config.h>
23258945Sroberto
24258945Sroberto#include <ctype.h>
25258945Sroberto
26258945Sroberto#include <isc/mem.h>
27258945Sroberto#include <isc/print.h>
28258945Sroberto#include <isc/region.h>
29258945Sroberto#include <isc/string.h>
30258945Sroberto#include <isc/util.h>
31258945Sroberto
32258945Srobertostatic char digits[] = "0123456789abcdefghijklmnoprstuvwxyz";
33258945Sroberto
34258945Srobertoisc_uint64_t
35258945Srobertoisc_string_touint64(char *source, char **end, int base) {
36258945Sroberto	isc_uint64_t tmp;
37258945Sroberto	isc_uint64_t overflow;
38258945Sroberto	char *s = source;
39258945Sroberto	char *o;
40258945Sroberto	char c;
41258945Sroberto
42258945Sroberto	if ((base < 0) || (base == 1) || (base > 36)) {
43258945Sroberto		*end = source;
44258945Sroberto		return (0);
45258945Sroberto	}
46258945Sroberto
47258945Sroberto	while (*s != 0 && isascii(*s&0xff) && isspace(*s&0xff))
48258945Sroberto		s++;
49258945Sroberto	if (*s == '+' /* || *s == '-' */)
50258945Sroberto		s++;
51258945Sroberto	if (base == 0) {
52258945Sroberto		if (*s == '0' && (*(s+1) == 'X' || *(s+1) == 'x')) {
53258945Sroberto			s += 2;
54258945Sroberto			base = 16;
55258945Sroberto		} else if (*s == '0')
56258945Sroberto			base = 8;
57258945Sroberto		else
58258945Sroberto			base = 10;
59258945Sroberto	}
60258945Sroberto	if (*s == 0) {
61258945Sroberto		*end = source;
62258945Sroberto		return (0);
63258945Sroberto	}
64258945Sroberto	overflow = ~0;
65258945Sroberto	overflow /= base;
66258945Sroberto	tmp = 0;
67258945Sroberto
68258945Sroberto	while ((c = *s) != 0) {
69258945Sroberto		c = tolower(c&0xff);
70258945Sroberto		/* end ? */
71258945Sroberto		if ((o = strchr(digits, c)) == NULL) {
72258945Sroberto			*end = s;
73258945Sroberto			return (tmp);
74258945Sroberto		}
75258945Sroberto		/* end ? */
76258945Sroberto		if ((o - digits) >= base) {
77258945Sroberto			*end = s;
78258945Sroberto			return (tmp);
79258945Sroberto		}
80258945Sroberto		/* overflow ? */
81258945Sroberto		if (tmp > overflow) {
82258945Sroberto			*end = source;
83258945Sroberto			return (0);
84258945Sroberto		}
85258945Sroberto		tmp *= base;
86258945Sroberto		/* overflow ? */
87258945Sroberto		if ((tmp + (o - digits)) < tmp) {
88258945Sroberto			*end = source;
89258945Sroberto			return (0);
90258945Sroberto		}
91258945Sroberto		tmp += o - digits;
92258945Sroberto		s++;
93258945Sroberto	}
94258945Sroberto	*end = s;
95258945Sroberto	return (tmp);
96258945Sroberto}
97258945Sroberto
98258945Srobertoisc_result_t
99258945Srobertoisc_string_copy(char *target, size_t size, const char *source) {
100258945Sroberto	REQUIRE(size > 0U);
101258945Sroberto
102258945Sroberto	if (strlcpy(target, source, size) >= size) {
103258945Sroberto		memset(target, ISC_STRING_MAGIC, size);
104258945Sroberto		return (ISC_R_NOSPACE);
105258945Sroberto	}
106258945Sroberto
107258945Sroberto	ENSURE(strlen(target) < size);
108258945Sroberto
109258945Sroberto	return (ISC_R_SUCCESS);
110258945Sroberto}
111258945Sroberto
112258945Srobertovoid
113258945Srobertoisc_string_copy_truncate(char *target, size_t size, const char *source) {
114258945Sroberto	REQUIRE(size > 0U);
115258945Sroberto
116258945Sroberto	strlcpy(target, source, size);
117258945Sroberto
118258945Sroberto	ENSURE(strlen(target) < size);
119258945Sroberto}
120258945Sroberto
121258945Srobertoisc_result_t
122258945Srobertoisc_string_append(char *target, size_t size, const char *source) {
123258945Sroberto	REQUIRE(size > 0U);
124258945Sroberto	REQUIRE(strlen(target) < size);
125258945Sroberto
126258945Sroberto	if (strlcat(target, source, size) >= size) {
127258945Sroberto		memset(target, ISC_STRING_MAGIC, size);
128258945Sroberto		return (ISC_R_NOSPACE);
129258945Sroberto	}
130258945Sroberto
131258945Sroberto	ENSURE(strlen(target) < size);
132258945Sroberto
133258945Sroberto	return (ISC_R_SUCCESS);
134258945Sroberto}
135258945Sroberto
136258945Srobertovoid
137258945Srobertoisc_string_append_truncate(char *target, size_t size, const char *source) {
138258945Sroberto	REQUIRE(size > 0U);
139258945Sroberto	REQUIRE(strlen(target) < size);
140258945Sroberto
141258945Sroberto	strlcat(target, source, size);
142258945Sroberto
143258945Sroberto	ENSURE(strlen(target) < size);
144258945Sroberto}
145258945Sroberto
146258945Srobertoisc_result_t
147258945Srobertoisc_string_printf(char *target, size_t size, const char *format, ...) {
148258945Sroberto	va_list args;
149258945Sroberto	size_t n;
150258945Sroberto
151258945Sroberto	REQUIRE(size > 0U);
152258945Sroberto
153258945Sroberto	va_start(args, format);
154258945Sroberto	n = vsnprintf(target, size, format, args);
155258945Sroberto	va_end(args);
156258945Sroberto
157258945Sroberto	if (n >= size) {
158258945Sroberto		memset(target, ISC_STRING_MAGIC, size);
159258945Sroberto		return (ISC_R_NOSPACE);
160258945Sroberto	}
161258945Sroberto
162258945Sroberto	ENSURE(strlen(target) < size);
163258945Sroberto
164258945Sroberto	return (ISC_R_SUCCESS);
165258945Sroberto}
166258945Sroberto
167258945Srobertovoid
168258945Srobertoisc_string_printf_truncate(char *target, size_t size, const char *format, ...) {
169258945Sroberto	va_list args;
170258945Sroberto	size_t n;
171258945Sroberto
172258945Sroberto	REQUIRE(size > 0U);
173258945Sroberto
174258945Sroberto	va_start(args, format);
175258945Sroberto	n = vsnprintf(target, size, format, args);
176258945Sroberto	va_end(args);
177258945Sroberto
178258945Sroberto	ENSURE(strlen(target) < size);
179258945Sroberto}
180258945Sroberto
181258945Srobertochar *
182258945Srobertoisc_string_regiondup(isc_mem_t *mctx, const isc_region_t *source) {
183258945Sroberto	char *target;
184258945Sroberto
185258945Sroberto	REQUIRE(mctx != NULL);
186258945Sroberto	REQUIRE(source != NULL);
187258945Sroberto
188258945Sroberto	target = (char *) isc_mem_allocate(mctx, source->length + 1);
189258945Sroberto	if (target != NULL) {
190258945Sroberto		memcpy(source->base, target, source->length);
191258945Sroberto		target[source->length] = '\0';
192258945Sroberto	}
193258945Sroberto
194258945Sroberto	return (target);
195258945Sroberto}
196258945Sroberto
197258945Srobertochar *
198258945Srobertoisc_string_separate(char **stringp, const char *delim) {
199258945Sroberto	char *string = *stringp;
200258945Sroberto	char *s;
201258945Sroberto	const char *d;
202258945Sroberto	char sc, dc;
203258945Sroberto
204258945Sroberto	if (string == NULL)
205258945Sroberto		return (NULL);
206258945Sroberto
207258945Sroberto	for (s = string; (sc = *s) != '\0'; s++)
208258945Sroberto		for (d = delim; (dc = *d) != '\0'; d++)
209258945Sroberto			if (sc == dc) {
210258945Sroberto				*s++ = '\0';
211258945Sroberto				*stringp = s;
212258945Sroberto				return (string);
213258945Sroberto			}
214258945Sroberto	*stringp = NULL;
215258945Sroberto	return (string);
216258945Sroberto}
217258945Sroberto
218258945Srobertosize_t
219258945Srobertoisc_string_strlcpy(char *dst, const char *src, size_t size)
220258945Sroberto{
221258945Sroberto	char *d = dst;
222258945Sroberto	const char *s = src;
223258945Sroberto	size_t n = size;
224258945Sroberto
225258945Sroberto	/* Copy as many bytes as will fit */
226258945Sroberto	if (n != 0U && --n != 0U) {
227258945Sroberto		do {
228258945Sroberto			if ((*d++ = *s++) == 0)
229258945Sroberto				break;
230258945Sroberto		} while (--n != 0U);
231258945Sroberto	}
232258945Sroberto
233258945Sroberto	/* Not enough room in dst, add NUL and traverse rest of src */
234258945Sroberto	if (n == 0U) {
235258945Sroberto		if (size != 0U)
236258945Sroberto			*d = '\0';		/* NUL-terminate dst */
237258945Sroberto		while (*s++)
238258945Sroberto			;
239258945Sroberto	}
240258945Sroberto
241258945Sroberto	return(s - src - 1);	/* count does not include NUL */
242258945Sroberto}
243258945Sroberto
244258945Srobertosize_t
245258945Srobertoisc_string_strlcat(char *dst, const char *src, size_t size)
246258945Sroberto{
247258945Sroberto	char *d = dst;
248258945Sroberto	const char *s = src;
249258945Sroberto	size_t n = size;
250258945Sroberto	size_t dlen;
251258945Sroberto
252258945Sroberto	/* Find the end of dst and adjust bytes left but don't go past end */
253258945Sroberto	while (n-- != 0U && *d != '\0')
254258945Sroberto		d++;
255258945Sroberto	dlen = d - dst;
256258945Sroberto	n = size - dlen;
257258945Sroberto
258258945Sroberto	if (n == 0U)
259258945Sroberto		return(dlen + strlen(s));
260258945Sroberto	while (*s != '\0') {
261258945Sroberto		if (n != 1U) {
262258945Sroberto			*d++ = *s;
263258945Sroberto			n--;
264258945Sroberto		}
265258945Sroberto		s++;
266258945Sroberto	}
267258945Sroberto	*d = '\0';
268258945Sroberto
269258945Sroberto	return(dlen + (s - src));	/* count does not include NUL */
270258945Sroberto}
271