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