1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <string.h>
30#include <limits.h>
31#include <stdlib.h>
32#include <sys/types.h>
33
34#include <inj.h>
35#include <inj_err.h>
36#include <inj_string.h>
37
38char *
39inj_strdup(const char *s)
40{
41	char *s1 = inj_alloc(strlen(s) + 1);
42
43	(void) strcpy(s1, s);
44	return (s1);
45}
46
47char *
48inj_strndup(const char *s, size_t n)
49{
50	char *s2 = inj_alloc(n + 1);
51
52	(void) strncpy(s2, s, n + 1);
53	s2[n] = '\0';
54	return (s2);
55}
56
57void
58inj_strfree(const char *s)
59{
60	inj_free((void *)s, strlen(s) + 1);
61}
62
63typedef struct type_desc {
64	int64_t td_min;
65	uint64_t td_max;
66} type_desc_t;
67
68static const type_desc_t signed_types[] = {
69	{ 0, 0 },
70	{ INT8_MIN, INT8_MAX },
71	{ INT16_MIN, INT16_MAX },
72	{ 0, 0 },
73	{ INT32_MIN, INT32_MAX },
74	{ 0, 0 },
75	{ 0, 0 },
76	{ 0, 0 },
77	{ INT64_MIN, INT64_MAX }
78};
79
80static const type_desc_t unsigned_types[] = {
81	{ 0, 0 },
82	{ 0, UINT8_MAX },
83	{ 0, UINT16_MAX },
84	{ 0, 0 },
85	{ 0, UINT32_MAX },
86	{ 0, 0 },
87	{ 0, 0 },
88	{ 0, 0 },
89	{ 0, UINT64_MAX }
90};
91
92int
93inj_strtoll(const char *str, int width, longlong_t *valp)
94{
95	const type_desc_t *desc;
96	longlong_t val;
97	char *c;
98
99	if (width != 0) {
100		assert(width / 8 < (sizeof (signed_types) /
101		    sizeof (signed_types[0])));
102		desc = &signed_types[width / 8];
103		assert(desc->td_max != 0);
104	}
105
106	errno = 0;
107	val = strtoll(str, &c, 0);
108	if (*c != '\0' || errno == EINVAL)
109		return (inj_set_errno(EINVAL));
110
111	if (errno == ERANGE || (width != 0 && (val < desc->td_min ||
112	    val > (longlong_t)desc->td_max)))
113		return (inj_set_errno(ERANGE));
114
115	if (valp != NULL)
116		*valp = val;
117
118	return (0);
119}
120
121int
122inj_strtoull(const char *str, int width, u_longlong_t *valp)
123{
124	const type_desc_t *desc;
125	u_longlong_t val;
126	char *c;
127
128	if (width != 0) {
129		assert(width / 8 < (sizeof (unsigned_types) /
130		    sizeof (unsigned_types[0])));
131		desc = &unsigned_types[width / 8];
132		assert(desc->td_max != 0);
133	}
134
135	errno = 0;
136	val = strtoull(str, &c, 0);
137	if (*c != '\0' || errno == EINVAL)
138		return (inj_set_errno(EINVAL));
139
140	if (errno == ERANGE || (width != 0 && val > desc->td_max))
141		return (inj_set_errno(ERANGE));
142
143	if (valp != NULL)
144		*valp = val;
145
146	return (0);
147}
148
149int
150inj_strtime(hrtime_t *nsp, const char *units)
151{
152	static const struct {
153		const char *name;
154		hrtime_t mul;
155	} suffix[] = {
156		{ "ns", 	NANOSEC / NANOSEC },
157		{ "nsec",	NANOSEC / NANOSEC },
158		{ "us",		NANOSEC / MICROSEC },
159		{ "usec",	NANOSEC / MICROSEC },
160		{ "ms",		NANOSEC / MILLISEC },
161		{ "msec",	NANOSEC / MILLISEC },
162		{ "s",		NANOSEC / SEC },
163		{ "sec",	NANOSEC / SEC },
164		{ "m",		NANOSEC * (hrtime_t)60 },
165		{ "min",	NANOSEC * (hrtime_t)60 },
166		{ "h",		NANOSEC * (hrtime_t)(60 * 60) },
167		{ "hour",	NANOSEC * (hrtime_t)(60 * 60) },
168		{ "d",		NANOSEC * (hrtime_t)(24 * 60 * 60) },
169		{ "day",	NANOSEC * (hrtime_t)(24 * 60 * 60) },
170		{ "hz",		0 },
171		{ NULL }
172	};
173
174	hrtime_t val = *nsp, mul = 1;
175	int i;
176
177	for (i = 0; suffix[i].name != NULL; i++) {
178		if (strcasecmp(suffix[i].name, units) == 0) {
179			mul = suffix[i].mul;
180			break;
181		}
182	}
183
184	if (suffix[i].name == NULL && *units != '\0')
185		return (inj_set_errno(EINVAL));
186
187	if (mul == 0) {
188		if (val != 0)
189			val = NANOSEC / val; /* compute val as value per sec */
190	} else
191		val *= mul;
192
193	*nsp = val;
194	return (0);
195}
196
197static ulong_t
198inj_hashfn_string(void *key)
199{
200	size_t g, h = 0;
201	char *p;
202
203	assert(key != NULL);
204
205	for (p = key; *p != '\0'; p++) {
206		h = (h << 4) + *p;
207
208		if ((g = (h & 0xf0000000)) != 0) {
209			h ^= (g >> 24);
210			h ^= g;
211		}
212	}
213
214	return (h);
215}
216
217static int
218inj_hashcmp_string(void *k1, void *k2)
219{
220	return (strcmp(k1, k2));
221}
222
223/*ARGSUSED*/
224static void
225inj_hashfree_string(inj_var_t *v, void *arg)
226{
227	inj_strfree(inj_hash_get_key(v));
228}
229
230void
231inj_strhash_create(inj_hash_t *h)
232{
233	inj_hash_create(h, inj_hashfn_string, inj_hashcmp_string);
234}
235
236int
237inj_strhash_insert(inj_hash_t *h, const char *str, uintmax_t value)
238{
239	return (inj_hash_insert(h, (void *)inj_strdup(str), value));
240}
241
242inj_var_t *
243inj_strhash_lookup(inj_hash_t *h, const char *str)
244{
245	return (inj_hash_lookup(h, (void *)str));
246}
247
248void
249inj_strhash_destroy(inj_hash_t *h)
250{
251	inj_hash_destroy(h, inj_hashfree_string, NULL);
252}
253