GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/make/str.c Lines: 133 175 76.0 %
Date: 2017-11-07 Branches: 104 173 60.1 %

Line Branch Exec Source
1
/*	$OpenBSD: str.c,v 1.31 2014/05/18 08:08:50 espie Exp $	*/
2
/*	$NetBSD: str.c,v 1.13 1996/11/06 17:59:23 christos Exp $	*/
3
4
/*-
5
 * Copyright (c) 1988, 1989, 1990, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 * Copyright (c) 1989 by Berkeley Softworks
8
 * All rights reserved.
9
 *
10
 * This code is derived from software contributed to Berkeley by
11
 * Adam de Boor.
12
 *
13
 * Redistribution and use in source and binary forms, with or without
14
 * modification, are permitted provided that the following conditions
15
 * are met:
16
 * 1. Redistributions of source code must retain the above copyright
17
 *    notice, this list of conditions and the following disclaimer.
18
 * 2. Redistributions in binary form must reproduce the above copyright
19
 *    notice, this list of conditions and the following disclaimer in the
20
 *    documentation and/or other materials provided with the distribution.
21
 * 3. Neither the name of the University nor the names of its contributors
22
 *    may be used to endorse or promote products derived from this software
23
 *    without specific prior written permission.
24
 *
25
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35
 * SUCH DAMAGE.
36
 */
37
38
#include <ctype.h>
39
#include <string.h>
40
#include "config.h"
41
#include "defines.h"
42
#include "str.h"
43
#include "memory.h"
44
#include "buf.h"
45
46
/* helpers for Str_Matchi */
47
static bool range_match(char, const char **, const char *);
48
static bool star_match(const char *, const char *, const char *, const char *);
49
50
char *
51
Str_concati(const char *s1, const char *e1, const char *s2, const char *e2,
52
    int sep)
53
{
54
	size_t len1, len2;
55
	char *result;
56
57
	/* get the length of both strings */
58
13186354
	len1 = e1 - s1;
59
6593177
	len2 = e2 - s2;
60
61
	/* space for separator */
62
6593177
	if (sep)
63
367358
		len1++;
64
6593177
	result = emalloc(len1 + len2 + 1);
65
66
	/* copy first string into place */
67
6593177
	memcpy(result, s1, len1);
68
69
	/* add separator character */
70
6593177
	if (sep)
71
367358
		result[len1-1] = sep;
72
73
	/* copy second string plus EOS into place */
74
6593177
	memcpy(result + len1, s2, len2);
75
6593177
	result[len1+len2] = '\0';
76
6593177
	return result;
77
}
78
79
/*-
80
 * brk_string --
81
 *	Fracture a string into an array of words (as delineated by tabs or
82
 *	spaces) taking quotation marks into account.  Leading tabs/spaces
83
 *	are ignored.
84
 *
85
 * returns --
86
 *	Pointer to the array of pointers to the words.	To make life easier,
87
 *	the first word is always the value of the .MAKE variable.
88
 */
89
char **
90
brk_string(const char *str, int *store_argc, char **buffer)
91
{
92
	int argc;
93
	char ch;
94
	char inquote;
95
	const char *p;
96
	char *start, *t;
97
	size_t len;
98
	int argmax = 50;
99
	size_t curlen = 0;
100
63954
	char **argv = ereallocarray(NULL, argmax + 1, sizeof(char *));
101
102
	/* skip leading space chars. */
103

95931
	for (; *str == ' ' || *str == '\t'; ++str)
104
		continue;
105
106
	/* allocate room for a copy of the string */
107
31977
	if ((len = strlen(str) + 1) > curlen)
108
31977
		*buffer = emalloc(curlen = len);
109
110
	/*
111
	 * copy the string; at the same time, parse backslashes,
112
	 * quotes and build the argument list.
113
	 */
114
	argc = 0;
115
	inquote = '\0';
116
1709534
	for (p = str, start = t = *buffer;; ++p) {
117


1831784
		switch (ch = *p) {
118
		case '"':
119
		case '\'':
120
			if (inquote) {
121
				if (inquote == ch)
122
					inquote = '\0';
123
				else
124
					break;
125
			} else {
126
				inquote = ch;
127
				/* Don't miss "" or '' */
128
				if (start == NULL && p[1] == inquote) {
129
					start = t + 1;
130
					break;
131
				}
132
			}
133
			continue;
134
		case ' ':
135
		case '\t':
136
		case '\n':
137
122250
			if (inquote)
138
				break;
139
122250
			if (!start)
140
				continue;
141
			/* FALLTHROUGH */
142
		case '\0':
143
			/*
144
			 * end of a token -- make sure there's enough argv
145
			 * space and save off a pointer.
146
			 */
147
154227
			if (!start)
148
				goto done;
149
150
122250
			*t++ = '\0';
151
122250
			if (argc == argmax) {
152
				argmax *= 2;	/* ramp up fast */
153
				argv = ereallocarray(argv,
154
				    (argmax + 1), sizeof(char *));
155
			}
156
122250
			argv[argc++] = start;
157
			start = NULL;
158

244500
			if (ch == '\n' || ch == '\0')
159
				goto done;
160
			continue;
161
		case '\\':
162


4089
			switch (ch = *++p) {
163
			case '\0':
164
			case '\n':
165
				/* hmmm; fix it up as best we can */
166
				ch = '\\';
167
				--p;
168
				break;
169
			case 'b':
170
				ch = '\b';
171
				break;
172
			case 'f':
173
				ch = '\f';
174
				break;
175
			case 'n':
176
				ch = '\n';
177
				break;
178
			case 'r':
179
				ch = '\r';
180
				break;
181
			case 't':
182
				ch = '\t';
183
				break;
184
			}
185
			    break;
186
		}
187
1555307
		if (!start)
188
90273
			start = t;
189
1555307
		*t++ = ch;
190
1555307
	}
191
    done:
192
31977
	    argv[argc] = NULL;
193
31977
	    *store_argc = argc;
194
31977
	    return argv;
195
}
196
197
198
const char *
199
iterate_words(const char **end)
200
{
201
	const char	*start, *p;
202
	char	state = 0;
203
193302432
	start = *end;
204
205
264030618
	while (ISSPACE(*start))
206
35364093
		start++;
207
96651216
	if (*start == '\0')
208
33854807
		return NULL;
209
210
1730674579
	for (p = start;; p++)
211

1765639735
	    switch(*p) {
212
	    case '\\':
213
		    if (p[1] != '\0')
214
			    p++;
215
		    break;
216
	    case '\'':
217
	    case '"':
218
744
		    if (state == *p)
219
204
			    state = 0;
220
540
		    else if (state == 0)
221
204
			    state = *p;
222
		    break;
223
	    case ' ':
224
	    case '\t':
225
34964412
		    if (state != 0)
226
			    break;
227
		    /* FALLTHROUGH */
228
	    case '\0':
229
62796409
		    *end = p;
230
62796409
		    return start;
231
	    default:
232
		    break;
233
	    }
234
96651216
}
235
236
static bool
237
star_match(const char *string, const char *estring,
238
    const char *pattern, const char *epattern)
239
{
240
	/* '*' matches any substring.  We handle this by calling ourselves
241
	 * recursively for each postfix of string, until either we match or
242
	 * we reach the end of the string.  */
243
10715586
	pattern++;
244
	/* Skip over contiguous  sequences of `?*', so that
245
	 * recursive calls only occur on `real' characters.  */
246

16073379
	while (pattern != epattern &&
247
10037762
		(*pattern == '?' || *pattern == '*')) {
248
		if (*pattern == '?') {
249
			if (string == estring)
250
				return false;
251
			else
252
				string++;
253
		}
254
		pattern++;
255
	}
256
5357793
	if (pattern == epattern)
257
338912
		return true;
258
232521637
	for (; string != estring; string++)
259
113915124
		if (Str_Matchi(string, estring, pattern,
260
		    epattern))
261
163746
			return true;
262
4855135
	return false;
263
5357793
}
264
265
static bool
266
range_match(char c, const char **ppat, const char *epattern)
267
{
268
300916
	if (*ppat == epattern) {
269
		if (c == '[')
270
			return true;
271
		else
272
			return false;
273
	}
274

300916
	if (**ppat == '!' || **ppat == '^') {
275
		(*ppat)++;
276
		return !range_match(c, ppat, epattern);
277
	}
278
	for (;;) {
279
375835
		if (**ppat == '\\') {
280
			if (++(*ppat) == epattern)
281
				return false;
282
		}
283
375835
		if (**ppat == c)
284
			break;
285
336043
		if ((*ppat)[1] == '-') {
286
2863
			if (*ppat + 2 == epattern)
287
				return false;
288

5698
			if (**ppat < c && c <= (*ppat)[2])
289
				break;
290

2996
			if ((*ppat)[2] <= c && c < **ppat)
291
				break;
292
1512
			*ppat += 3;
293
1512
		} else
294
333180
			(*ppat)++;
295
		/* The test for ']' is done at the end
296
		 * so that ']' can be used at the
297
		 * start of the range without '\' */
298

669384
		if (*ppat == epattern || **ppat == ']')
299
109315
			return false;
300
	}
301
	/* Found matching character, skip over rest
302
	 * of class.  */
303
172471
	while (**ppat != ']') {
304
65664
		if (**ppat == '\\')
305
			(*ppat)++;
306
		/* A non-terminated character class
307
		 * is ok. */
308
65664
		if (*ppat == epattern)
309
			break;
310
65664
		(*ppat)++;
311
	}
312
41143
	return true;
313
150458
}
314
315
bool
316
Str_Matchi(const char *string, const char *estring,
317
    const char *pattern, const char *epattern)
318
{
319
325722438
	while (pattern != epattern) {
320
		/* Check for a "*" as the next pattern character.  */
321
162341880
		if (*pattern == '*')
322
5357793
			return star_match(string, estring, pattern, epattern);
323
156984087
		else if (string == estring)
324
117815
			return false;
325
		/* Check for a "[" as the next pattern character.  It is
326
		 * followed by a list of characters that are acceptable, or
327
		 * by a range (two characters separated by "-").  */
328
156866272
		else if (*pattern == '[') {
329
150458
			pattern++;
330
150458
			if (!range_match(*string, &pattern, epattern))
331
109315
				return false;
332
333
		}
334
		/* '?' matches any single character, so shunt test.  */
335
156715814
		else if (*pattern != '?') {
336
			/* If the next pattern character is '\', just strip
337
			 * off the '\' so we do exact matching on the
338
			 * character that follows.  */
339
156715814
			if (*pattern == '\\') {
340
				if (++pattern == epattern)
341
					return false;
342
			}
343
			/* There's no special character.  Just make sure that
344
			 * the next characters of each string match.  */
345
156715814
			if (*pattern != *string)
346
127515132
				return false;
347
		}
348
29241825
		pattern++;
349
29241825
		string++;
350
	}
351
519339
	if (string == estring)
352
511107
		return true;
353
	else
354
8232
		return false;
355
133619394
}
356
357
358
/*-
359
 *-----------------------------------------------------------------------
360
 * Str_SYSVMatch --
361
 *	Check word against pattern for a match (% is wild),
362
 *
363
 * Results:
364
 *	Returns the beginning position of a match or null. The number
365
 *	of characters matched is returned in len.
366
 *-----------------------------------------------------------------------
367
 */
368
const char *
369
Str_SYSVMatch(const char *word, const char *pattern, size_t *len)
370
{
371
	const char *p = pattern;
372
	const char *w = word;
373
	const char *m;
374
375
1630728
	if (*p == '\0') {
376
		/* Null pattern is the whole string.  */
377
9148
		*len = strlen(w);
378
9148
		return w;
379
	}
380
381
806216
	if ((m = strchr(p, '%')) != NULL) {
382
		/* Check that the prefix matches.  */
383

8086
		for (; p != m && *w && *w == *p; w++, p++)
384
			 continue;
385
386
8086
		if (p != m)
387
			return NULL;	/* No match.  */
388
389
8086
		if (*++p == '\0') {
390
			/* No more pattern, return the rest of the string. */
391
8086
			*len = strlen(w);
392
8086
			return w;
393
		}
394
	}
395
396
	m = w;
397
398
	/* Find a matching tail.  */
399
798130
	do {
400
6973879
		if (strcmp(p, w) == 0) {
401
798130
			*len = w - m;
402
798130
			return m;
403
		}
404
6175749
	} while (*w++ != '\0');
405
406
	return NULL;
407
815364
}
408
409
410
/*-
411
 *-----------------------------------------------------------------------
412
 * Str_SYSVSubst --
413
 *	Substitute '%' in the pattern with len characters from src.
414
 *	If the pattern does not contain a '%' prepend len characters
415
 *	from src.
416
 *
417
 * Side Effects:
418
 *	Adds result to buf
419
 *-----------------------------------------------------------------------
420
 */
421
void
422
Str_SYSVSubst(Buffer buf, const char *pat, const char *src, size_t len)
423
{
424
	const char *m;
425
426
1630728
	if ((m = strchr(pat, '%')) != NULL) {
427
		/* Copy the prefix.  */
428
8086
		Buf_Addi(buf, pat, m);
429
		/* Skip the %.	*/
430
8086
		pat = m + 1;
431
8086
	}
432
433
	/* Copy the pattern.  */
434
815364
	Buf_AddChars(buf, len, src);
435
436
	/* Append the rest.  */
437
815364
	Buf_AddString(buf, pat);
438
815364
}
439
440
char *
441
Str_dupi(const char *begin, const char *end)
442
{
443
	char *s;
444
445
10064424
	s = emalloc(end - begin + 1);
446
5032212
	memcpy(s, begin, end - begin);
447
5032212
	s[end-begin] = '\0';
448
5032212
	return s;
449
}
450
451
char *
452
escape_dupi(const char *begin, const char *end, const char *set)
453
{
454
	char *s, *t;
455
456
48523864
	t = s = emalloc(end - begin + 1);
457
1280035412
	while (begin != end) {
458
615755774
		if (*begin == '\\') {
459
			begin++;
460
			if (begin == end) {
461
				*t++ = '\\';
462
				break;
463
			}
464
			if (strchr(set, *begin) == NULL)
465
				*t++ = '\\';
466
		}
467
615755774
		*t++ = *begin++;
468
	}
469
24261932
	*t++ = '\0';
470
24261932
	return s;
471
}
472
473
char *
474
Str_rchri(const char *begin, const char *end, int c)
475
{
476
16677690
	if (begin != end)
477
		do {
478
75122652
			if (*--end == c)
479
6677290
				return (char *)end;
480
68445362
		} while (end != begin);
481
1661555
	return NULL;
482
8338845
}