text.c revision 275988
1/* Copyright (c) 2008 The NetBSD Foundation, Inc.
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */
25
26#include "atf-c/detail/text.h"
27
28#include <errno.h>
29#include <limits.h>
30#include <string.h>
31#include <stdlib.h>
32
33#include "atf-c/detail/dynstr.h"
34#include "atf-c/detail/sanity.h"
35#include "atf-c/error.h"
36
37atf_error_t
38atf_text_for_each_word(const char *instr, const char *sep,
39                       atf_error_t (*func)(const char *, void *),
40                       void *data)
41{
42    atf_error_t err;
43    char *str, *str2, *last;
44
45    str = strdup(instr);
46    if (str == NULL) {
47        err = atf_no_memory_error();
48        goto out;
49    }
50
51    err = atf_no_error();
52    str2 = strtok_r(str, sep, &last);
53    while (str2 != NULL && !atf_is_error(err)) {
54        err = func(str2, data);
55        str2 = strtok_r(NULL, sep, &last);
56    }
57
58    free(str);
59out:
60    return err;
61}
62
63atf_error_t
64atf_text_format(char **dest, const char *fmt, ...)
65{
66    atf_error_t err;
67    va_list ap;
68
69    va_start(ap, fmt);
70    err = atf_text_format_ap(dest, fmt, ap);
71    va_end(ap);
72
73    return err;
74}
75
76atf_error_t
77atf_text_format_ap(char **dest, const char *fmt, va_list ap)
78{
79    atf_error_t err;
80    atf_dynstr_t tmp;
81    va_list ap2;
82
83    va_copy(ap2, ap);
84    err = atf_dynstr_init_ap(&tmp, fmt, ap2);
85    va_end(ap2);
86    if (!atf_is_error(err))
87        *dest = atf_dynstr_fini_disown(&tmp);
88
89    return err;
90}
91
92atf_error_t
93atf_text_split(const char *str, const char *delim, atf_list_t *words)
94{
95    atf_error_t err;
96    const char *end;
97    const char *iter;
98
99    err = atf_list_init(words);
100    if (atf_is_error(err))
101        goto err;
102
103    end = str + strlen(str);
104    INV(*end == '\0');
105    iter = str;
106    while (iter < end) {
107        const char *ptr;
108
109        INV(iter != NULL);
110        ptr = strstr(iter, delim);
111        if (ptr == NULL)
112            ptr = end;
113
114        INV(ptr >= iter);
115        if (ptr > iter) {
116            atf_dynstr_t word;
117
118            err = atf_dynstr_init_raw(&word, iter, ptr - iter);
119            if (atf_is_error(err))
120                goto err_list;
121
122            err = atf_list_append(words, atf_dynstr_fini_disown(&word), true);
123            if (atf_is_error(err))
124                goto err_list;
125        }
126
127        iter = ptr + strlen(delim);
128    }
129
130    INV(!atf_is_error(err));
131    return err;
132
133err_list:
134    atf_list_fini(words);
135err:
136    return err;
137}
138
139atf_error_t
140atf_text_to_bool(const char *str, bool *b)
141{
142    atf_error_t err;
143
144    if (strcasecmp(str, "yes") == 0 ||
145        strcasecmp(str, "true") == 0) {
146        *b = true;
147        err = atf_no_error();
148    } else if (strcasecmp(str, "no") == 0 ||
149               strcasecmp(str, "false") == 0) {
150        *b = false;
151        err = atf_no_error();
152    } else {
153        /* XXX Not really a libc error. */
154        err = atf_libc_error(EINVAL, "Cannot convert string '%s' "
155                             "to boolean", str);
156    }
157
158    return err;
159}
160
161atf_error_t
162atf_text_to_long(const char *str, long *l)
163{
164    atf_error_t err;
165    char *endptr;
166    long tmp;
167
168    errno = 0;
169    tmp = strtol(str, &endptr, 10);
170    if (str[0] == '\0' || *endptr != '\0')
171        err = atf_libc_error(EINVAL, "'%s' is not a number", str);
172    else if (errno == ERANGE || (tmp == LONG_MAX || tmp == LONG_MIN))
173        err = atf_libc_error(ERANGE, "'%s' is out of range", str);
174    else {
175        *l = tmp;
176        err = atf_no_error();
177    }
178
179    return err;
180}
181