Commit | Line | Data |
---|---|---|
081e6815 | 1 | /* -*-c-*- |
2 | * | |
081e6815 | 3 | * Functions for hacking with strings |
4 | * | |
5 | * (c) 1999 Straylight/Edgeware | |
6 | */ | |
7 | ||
d4efbcd9 | 8 | /*----- Licensing notice --------------------------------------------------* |
081e6815 | 9 | * |
10 | * This file is part of the mLib utilities library. | |
11 | * | |
12 | * mLib is free software; you can redistribute it and/or modify | |
13 | * it under the terms of the GNU Library General Public License as | |
14 | * published by the Free Software Foundation; either version 2 of the | |
15 | * License, or (at your option) any later version. | |
d4efbcd9 | 16 | * |
081e6815 | 17 | * mLib is distributed in the hope that it will be useful, |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | * GNU Library General Public License for more details. | |
d4efbcd9 | 21 | * |
081e6815 | 22 | * You should have received a copy of the GNU Library General Public |
23 | * License along with mLib; if not, write to the Free | |
24 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |
25 | * MA 02111-1307, USA. | |
26 | */ | |
27 | ||
081e6815 | 28 | /*----- Header files ------------------------------------------------------*/ |
29 | ||
30 | #include <ctype.h> | |
31 | #include <stdio.h> | |
32 | #include <stdlib.h> | |
33 | #include <string.h> | |
34 | ||
35 | #include "str.h" | |
36 | ||
37 | /*----- Main code ---------------------------------------------------------*/ | |
38 | ||
efae42a6 | 39 | /* --- @str_qword@ --- * |
081e6815 | 40 | * |
41 | * Arguments: @char **pp@ = address of pointer into string | |
efae42a6 | 42 | * @unsigned f@ = various flags |
081e6815 | 43 | * |
efae42a6 | 44 | * Returns: Pointer to the next space-separated possibly-quoted word from |
45 | * the string, or null. | |
081e6815 | 46 | * |
efae42a6 | 47 | * Use: Fetches the next word from a string. If the flag |
48 | * @STRF_QUOTE@ is set, the `\' character acts as an escape, and | |
49 | * single and double quotes protect whitespace. | |
081e6815 | 50 | */ |
51 | ||
efae42a6 | 52 | char *str_qword(char **pp, unsigned f) |
081e6815 | 53 | { |
efae42a6 | 54 | char *p = *pp, *q, *qq; |
55 | int st = 0, pst = 0; | |
56 | ||
57 | /* --- Preliminaries --- */ | |
081e6815 | 58 | |
59 | if (!p) | |
60 | return (0); | |
081e6815 | 61 | while (isspace((unsigned char)*p)) |
62 | p++; | |
efae42a6 | 63 | if (!*p) { |
64 | *pp = 0; | |
65 | return (0); | |
66 | } | |
67 | ||
68 | /* --- Main work --- */ | |
081e6815 | 69 | |
efae42a6 | 70 | for (q = qq = p; *q; q++) { |
71 | switch (st) { | |
72 | case '\\': | |
73 | *qq++ = *q; | |
74 | st = pst; | |
75 | break; | |
76 | case '\'': | |
77 | case '\"': | |
78 | if (*q == st) | |
79 | st = pst = 0; | |
80 | else if (*q == '\\') | |
81 | st = '\\'; | |
82 | else | |
83 | *qq++ = *q; | |
84 | break; | |
85 | default: | |
86 | if (isspace((unsigned char)*q)) { | |
87 | do q++; while (*q && isspace((unsigned char)*q)); | |
88 | goto done; | |
89 | } else if (!(f & STRF_QUOTE)) | |
90 | goto stdchar; | |
91 | switch (*q) { | |
92 | case '\\': | |
93 | st = '\\'; | |
94 | break; | |
95 | case '\'': | |
96 | case '\"': | |
97 | st = pst = *q; | |
98 | break; | |
99 | default: | |
100 | stdchar: | |
101 | *qq++ = *q; | |
102 | break; | |
103 | } | |
081e6815 | 104 | } |
105 | } | |
106 | ||
efae42a6 | 107 | /* --- Finished --- */ |
108 | ||
109 | done: | |
110 | *pp = *q ? q : 0; | |
111 | *qq++ = 0; | |
081e6815 | 112 | return (p); |
113 | } | |
114 | ||
efae42a6 | 115 | /* --- @str_qsplit@ --- * |
081e6815 | 116 | * |
117 | * Arguments: @char *p@ = pointer to string | |
118 | * @char *v[]@ = pointer to array to fill in | |
119 | * @size_t c@ = count of strings to fill in | |
f3a542e8 | 120 | * @char **rest@ = where to store the remainder of the string |
efae42a6 | 121 | * @unsigned f@ = flags for @str_qword@ |
081e6815 | 122 | * |
123 | * Returns: Number of strings filled in. | |
124 | * | |
125 | * Use: Fills an array with pointers to the individual words of a | |
126 | * string. The string is modified in place to contain zero | |
127 | * bytes at the word boundaries, and the words have leading | |
128 | * and trailing space stripped off. No more than @c@ words | |
129 | * are read; the actual number is returned as the value of the | |
130 | * function. Unused slots in the array are populated with | |
f3a542e8 | 131 | * null bytes. If there's any string left, the address of the |
132 | * remainder is stored in @rest@ (if it's non-null); otherwise | |
133 | * @rest@ is set to a null pointer. | |
081e6815 | 134 | */ |
135 | ||
efae42a6 | 136 | size_t str_qsplit(char *p, char *v[], size_t c, char **rest, unsigned f) |
081e6815 | 137 | { |
138 | size_t n = 0; | |
139 | char *q; | |
140 | ||
efae42a6 | 141 | while (c && (q = str_qword(&p, f)) != 0) { |
081e6815 | 142 | *v++ = q; |
143 | c--; | |
144 | n++; | |
145 | } | |
081e6815 | 146 | while (c) { |
147 | *v++ = 0; | |
148 | c--; | |
149 | } | |
48d198f1 | 150 | if (rest) |
151 | *rest = p; | |
081e6815 | 152 | return (n); |
153 | } | |
154 | ||
efae42a6 | 155 | /* --- @str_getword@ --- * |
156 | * | |
157 | * Arguments: @char **pp@ = address of pointer into string | |
158 | * | |
159 | * Returns: Pointer to the next space-separated word from the string, | |
160 | * or null. | |
161 | * | |
162 | * Use: Parses off space-separated words from a string. This is a | |
163 | * compatibility veneer over @str_qword@. | |
164 | */ | |
165 | ||
d45be1af | 166 | char *str_getword(char **pp) { return (str_qword(pp, 0)); } |
efae42a6 | 167 | |
168 | /* --- @str_split@ --- * | |
169 | * | |
170 | * Arguments: @char *p@ = pointer to string | |
171 | * @char *v[]@ = pointer to array to fill in | |
172 | * @size_t c@ = count of strings to fill in | |
173 | * @char **rest@ = where to store the remainder of the string | |
174 | * | |
175 | * Returns: Number of strings filled in. | |
176 | * | |
177 | * Use: Fills an array with pointers to the individual words of a | |
178 | * string. This is a compatibility veneer over @str_qsplit@. | |
179 | */ | |
180 | ||
181 | size_t str_split(char *p, char *v[], size_t c, char **rest) | |
d45be1af | 182 | { return (str_qsplit(p, v, c, rest, 0)); } |
efae42a6 | 183 | |
26f325c0 | 184 | /* --- @str_matchx@ --- * |
efae42a6 | 185 | * |
186 | * Arguments: @const char *p@ = pointer to pattern string | |
187 | * @const char *s@ = string to compare with | |
26f325c0 | 188 | * @unsigned f@ = various flags |
efae42a6 | 189 | * |
190 | * Returns: Nonzero if the pattern matches the string. | |
191 | * | |
192 | * Use: Does simple wildcard matching. This is quite nasty and more | |
193 | * than a little slow. Supports metacharacters `*', `?' and | |
194 | * '['. | |
195 | */ | |
196 | ||
26f325c0 | 197 | int str_matchx(const char *p, const char *s, unsigned f) |
efae42a6 | 198 | { |
199 | for (;;) { | |
200 | char pch = *p++, pche, sch; | |
201 | int sense; | |
202 | ||
26f325c0 MW |
203 | if ((f & STRF_PREFIX) && !*s) |
204 | return (1); | |
efae42a6 | 205 | switch (pch) { |
206 | case '?': | |
207 | if (!*s) | |
208 | return (0); | |
209 | s++; | |
210 | break; | |
211 | case '*': | |
26f325c0 | 212 | if (!*p || (f & STRF_PREFIX)) |
efae42a6 | 213 | return (1); |
214 | while (*s) { | |
215 | if (str_match(p, s)) | |
216 | return (1); | |
217 | s++; | |
218 | } | |
219 | return (0); | |
220 | case '[': | |
221 | if (!*s) | |
222 | return (0); | |
223 | sch = *s++; | |
224 | pch = *p++; | |
225 | sense = 1; | |
226 | if (pch == '^' || pch == '!') { | |
227 | sense = !sense; | |
228 | pch = *p++; | |
229 | } | |
230 | if (pch == ']') { | |
231 | if (*p == '-' && p[1] && p[1] != ']') { | |
232 | pche = p[1]; | |
233 | p += 2; | |
234 | if (pch <= sch && sch <= pche) | |
235 | goto class_match; | |
236 | } else if (pch == sch) | |
237 | goto class_match; | |
238 | pch = *p++; | |
239 | } | |
240 | for (;; pch = *p++) { | |
241 | if (!pch || pch == ']') | |
242 | goto class_nomatch; | |
243 | if (*p == '-' && p[1] && p[1] != ']') { | |
244 | pche = p[1]; | |
245 | p += 2; | |
246 | if (pch <= sch && sch <= pche) | |
247 | goto class_match; | |
248 | } else if (pch == sch) | |
249 | goto class_match; | |
250 | } | |
251 | class_match: | |
252 | if (!sense) | |
253 | return (0); | |
254 | for (;;) { | |
255 | pch = *p++; | |
256 | if (!pch) | |
257 | return (0); | |
258 | if (pch == ']') | |
259 | break; | |
260 | if (*p == '-' && p[1] && p[1] != ']') | |
261 | p += 2; | |
262 | } | |
263 | break; | |
264 | class_nomatch: | |
265 | if (sense) | |
266 | return (0); | |
267 | break; | |
268 | case '\\': | |
269 | pch = *p++; | |
270 | default: | |
271 | if (pch != *s) | |
272 | return (0); | |
273 | if (!pch) | |
274 | return (1); | |
275 | s++; | |
276 | break; | |
277 | } | |
278 | } | |
279 | } | |
280 | ||
26f325c0 MW |
281 | /* --- @str_match@ --- * |
282 | * | |
283 | * Arguments: @const char *p@ = pointer to pattern string | |
284 | * @const char *s@ = string to compare with | |
285 | * | |
286 | * Returns: Nonzero if the pattern matches the string. | |
287 | * | |
288 | * Use: Does simple wildcard matching. Equivalent to @str_matchx@ | |
289 | * with zero flags word. | |
290 | */ | |
291 | ||
292 | int str_match(const char *p, const char *s) | |
293 | { return (str_matchx(p, s, 0)); } | |
294 | ||
081e6815 | 295 | /* --- @str_sanitize@ --- * |
296 | * | |
297 | * Arguments: @char *d@ = destination buffer | |
298 | * @const char *p@ = pointer to source string | |
299 | * @size_t sz@ = size of destination buffer | |
300 | * | |
301 | * Returns: --- | |
302 | * | |
303 | * Use: Writes a string into a buffer, being careful not to overflow | |
304 | * the buffer, to null terminate the result, and to prevent | |
305 | * nasty nonprintable characters ending up in the buffer. | |
306 | */ | |
307 | ||
308 | void str_sanitize(char *d, const char *p, size_t sz) | |
309 | { | |
310 | if (!sz) | |
311 | return; | |
312 | sz--; | |
313 | while (*p && sz) { | |
314 | int ch = *p++; | |
315 | if (!isgraph((unsigned char)ch)) | |
316 | ch = '_'; | |
317 | *d++ = ch; | |
318 | sz--; | |
319 | } | |
320 | *d++ = 0; | |
321 | } | |
322 | ||
323 | /*----- That's all, folks -------------------------------------------------*/ |