xref: /freebsd/contrib/atf/atf-c/detail/text.c (revision 8f0ea33f2bbf3a6aa80235f0a02fa5f2780c2b17)
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 
37 atf_error_t
atf_text_for_each_word(const char * instr,const char * sep,atf_error_t (* func)(const char *,void *),void * data)38 atf_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);
59 out:
60     return err;
61 }
62 
63 atf_error_t
atf_text_format(char ** dest,const char * fmt,...)64 atf_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 
76 atf_error_t
atf_text_format_ap(char ** dest,const char * fmt,va_list ap)77 atf_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 
92 atf_error_t
atf_text_split(const char * str,const char * delim,atf_list_t * words)93 atf_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 
133 err_list:
134     atf_list_fini(words);
135 err:
136     return err;
137 }
138 
139 atf_error_t
atf_text_to_bool(const char * str,bool * b)140 atf_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 
161 atf_error_t
atf_text_to_long(const char * str,long * l)162 atf_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