1273929Sjmmv/* Copyright (c) 2008 The NetBSD Foundation, Inc.
2240116Smarcel * All rights reserved.
3240116Smarcel *
4240116Smarcel * Redistribution and use in source and binary forms, with or without
5240116Smarcel * modification, are permitted provided that the following conditions
6240116Smarcel * are met:
7240116Smarcel * 1. Redistributions of source code must retain the above copyright
8240116Smarcel *    notice, this list of conditions and the following disclaimer.
9240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright
10240116Smarcel *    notice, this list of conditions and the following disclaimer in the
11240116Smarcel *    documentation and/or other materials provided with the distribution.
12240116Smarcel *
13240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14240116Smarcel * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15240116Smarcel * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16240116Smarcel * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17240116Smarcel * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18240116Smarcel * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19240116Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20240116Smarcel * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21240116Smarcel * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22240116Smarcel * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23240116Smarcel * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24273929Sjmmv * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */
25240116Smarcel
26273929Sjmmv#include "atf-c/detail/text.h"
27273929Sjmmv
28240116Smarcel#include <errno.h>
29240116Smarcel#include <limits.h>
30240116Smarcel#include <string.h>
31240116Smarcel#include <stdlib.h>
32240116Smarcel
33273929Sjmmv#include "atf-c/detail/dynstr.h"
34273929Sjmmv#include "atf-c/detail/sanity.h"
35240116Smarcel#include "atf-c/error.h"
36240116Smarcel
37240116Smarcelatf_error_t
38240116Smarcelatf_text_for_each_word(const char *instr, const char *sep,
39240116Smarcel                       atf_error_t (*func)(const char *, void *),
40240116Smarcel                       void *data)
41240116Smarcel{
42240116Smarcel    atf_error_t err;
43240116Smarcel    char *str, *str2, *last;
44240116Smarcel
45240116Smarcel    str = strdup(instr);
46240116Smarcel    if (str == NULL) {
47240116Smarcel        err = atf_no_memory_error();
48240116Smarcel        goto out;
49240116Smarcel    }
50240116Smarcel
51240116Smarcel    err = atf_no_error();
52240116Smarcel    str2 = strtok_r(str, sep, &last);
53240116Smarcel    while (str2 != NULL && !atf_is_error(err)) {
54240116Smarcel        err = func(str2, data);
55240116Smarcel        str2 = strtok_r(NULL, sep, &last);
56240116Smarcel    }
57240116Smarcel
58240116Smarcel    free(str);
59240116Smarcelout:
60240116Smarcel    return err;
61240116Smarcel}
62240116Smarcel
63240116Smarcelatf_error_t
64240116Smarcelatf_text_format(char **dest, const char *fmt, ...)
65240116Smarcel{
66240116Smarcel    atf_error_t err;
67240116Smarcel    va_list ap;
68240116Smarcel
69240116Smarcel    va_start(ap, fmt);
70240116Smarcel    err = atf_text_format_ap(dest, fmt, ap);
71240116Smarcel    va_end(ap);
72240116Smarcel
73240116Smarcel    return err;
74240116Smarcel}
75240116Smarcel
76240116Smarcelatf_error_t
77240116Smarcelatf_text_format_ap(char **dest, const char *fmt, va_list ap)
78240116Smarcel{
79240116Smarcel    atf_error_t err;
80240116Smarcel    atf_dynstr_t tmp;
81240116Smarcel    va_list ap2;
82240116Smarcel
83240116Smarcel    va_copy(ap2, ap);
84240116Smarcel    err = atf_dynstr_init_ap(&tmp, fmt, ap2);
85240116Smarcel    va_end(ap2);
86240116Smarcel    if (!atf_is_error(err))
87240116Smarcel        *dest = atf_dynstr_fini_disown(&tmp);
88240116Smarcel
89240116Smarcel    return err;
90240116Smarcel}
91240116Smarcel
92240116Smarcelatf_error_t
93240116Smarcelatf_text_split(const char *str, const char *delim, atf_list_t *words)
94240116Smarcel{
95240116Smarcel    atf_error_t err;
96240116Smarcel    const char *end;
97240116Smarcel    const char *iter;
98240116Smarcel
99240116Smarcel    err = atf_list_init(words);
100240116Smarcel    if (atf_is_error(err))
101240116Smarcel        goto err;
102240116Smarcel
103240116Smarcel    end = str + strlen(str);
104240116Smarcel    INV(*end == '\0');
105240116Smarcel    iter = str;
106240116Smarcel    while (iter < end) {
107240116Smarcel        const char *ptr;
108240116Smarcel
109240116Smarcel        INV(iter != NULL);
110240116Smarcel        ptr = strstr(iter, delim);
111240116Smarcel        if (ptr == NULL)
112240116Smarcel            ptr = end;
113240116Smarcel
114240116Smarcel        INV(ptr >= iter);
115240116Smarcel        if (ptr > iter) {
116240116Smarcel            atf_dynstr_t word;
117240116Smarcel
118240116Smarcel            err = atf_dynstr_init_raw(&word, iter, ptr - iter);
119240116Smarcel            if (atf_is_error(err))
120240116Smarcel                goto err_list;
121240116Smarcel
122240116Smarcel            err = atf_list_append(words, atf_dynstr_fini_disown(&word), true);
123240116Smarcel            if (atf_is_error(err))
124240116Smarcel                goto err_list;
125240116Smarcel        }
126240116Smarcel
127240116Smarcel        iter = ptr + strlen(delim);
128240116Smarcel    }
129240116Smarcel
130240116Smarcel    INV(!atf_is_error(err));
131240116Smarcel    return err;
132240116Smarcel
133240116Smarcelerr_list:
134240116Smarcel    atf_list_fini(words);
135240116Smarcelerr:
136240116Smarcel    return err;
137240116Smarcel}
138240116Smarcel
139240116Smarcelatf_error_t
140240116Smarcelatf_text_to_bool(const char *str, bool *b)
141240116Smarcel{
142240116Smarcel    atf_error_t err;
143240116Smarcel
144240116Smarcel    if (strcasecmp(str, "yes") == 0 ||
145240116Smarcel        strcasecmp(str, "true") == 0) {
146240116Smarcel        *b = true;
147240116Smarcel        err = atf_no_error();
148240116Smarcel    } else if (strcasecmp(str, "no") == 0 ||
149240116Smarcel               strcasecmp(str, "false") == 0) {
150240116Smarcel        *b = false;
151240116Smarcel        err = atf_no_error();
152240116Smarcel    } else {
153240116Smarcel        /* XXX Not really a libc error. */
154240116Smarcel        err = atf_libc_error(EINVAL, "Cannot convert string '%s' "
155240116Smarcel                             "to boolean", str);
156240116Smarcel    }
157240116Smarcel
158240116Smarcel    return err;
159240116Smarcel}
160240116Smarcel
161240116Smarcelatf_error_t
162240116Smarcelatf_text_to_long(const char *str, long *l)
163240116Smarcel{
164240116Smarcel    atf_error_t err;
165240116Smarcel    char *endptr;
166240116Smarcel    long tmp;
167240116Smarcel
168240116Smarcel    errno = 0;
169240116Smarcel    tmp = strtol(str, &endptr, 10);
170240116Smarcel    if (str[0] == '\0' || *endptr != '\0')
171240116Smarcel        err = atf_libc_error(EINVAL, "'%s' is not a number", str);
172240116Smarcel    else if (errno == ERANGE || (tmp == LONG_MAX || tmp == LONG_MIN))
173240116Smarcel        err = atf_libc_error(ERANGE, "'%s' is out of range", str);
174240116Smarcel    else {
175240116Smarcel        *l = tmp;
176240116Smarcel        err = atf_no_error();
177240116Smarcel    }
178240116Smarcel
179240116Smarcel    return err;
180240116Smarcel}
181