xref: /openbsd/usr.bin/xargs/strnsubst.c (revision 898184e3)
1 /*	$OpenBSD: strnsubst.c,v 1.5 2009/10/27 23:59:50 deraadt Exp $	*/
2 /*	$FreeBSD: strnsubst.c,v 1.6 2002/06/22 12:58:42 jmallett Exp $	*/
3 
4 /*
5  * Copyright (c) 2002 J. Mallett.  All rights reserved.
6  * You may do whatever you want with this file as long as
7  * the above copyright and this notice remain intact, along
8  * with the following statement:
9  * 	For the man who taught me vi, and who got too old, too young.
10  */
11 
12 #include <err.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 
18 void	strnsubst(char **, const char *, const char *, size_t);
19 
20 /*
21  * Replaces str with a string consisting of str with match replaced with
22  * replstr as many times as can be done before the constructed string is
23  * maxsize bytes large.  It does not free the string pointed to by str, it
24  * is up to the calling program to be sure that the original contents of
25  * str as well as the new contents are handled in an appropriate manner.
26  * If replstr is NULL, then that internally is changed to a nil-string, so
27  * that we can still pretend to do somewhat meaningful substitution.
28  * No value is returned.
29  */
30 void
31 strnsubst(char **str, const char *match, const char *replstr, size_t maxsize)
32 {
33 	char *s1, *s2, *this;
34 	size_t matchlen, repllen, s2len;
35 	int n;
36 
37 	if ((s1 = *str) == NULL)
38 		return;
39 	if ((s2 = malloc(maxsize)) == NULL)
40 		err(1, NULL);
41 
42 	if (replstr == NULL)
43 		replstr = "";
44 
45 	if (match == NULL || *match == '\0' || strlen(s1) >= maxsize) {
46 		strlcpy(s2, s1, maxsize);
47 		goto done;
48 	}
49 
50 	*s2 = '\0';
51 	s2len = 0;
52 	matchlen = strlen(match);
53 	repllen = strlen(replstr);
54 	for (;;) {
55 		if ((this = strstr(s1, match)) == NULL)
56 			break;
57 		n = snprintf(s2 + s2len, maxsize - s2len, "%.*s%s",
58 		    (int)(this - s1), s1, replstr);
59 		if (n == -1 || n + s2len + strlen(this + matchlen) >= maxsize)
60 			break;			/* out of room */
61 		s2len += n;
62 		s1 = this + matchlen;
63 	}
64 	strlcpy(s2 + s2len, s1, maxsize - s2len);
65 done:
66 	*str = s2;
67 	return;
68 }
69 
70 #ifdef TEST
71 #include <stdio.h>
72 
73 int
74 main(void)
75 {
76 	char *x, *y, *z, *za;
77 
78 	x = "{}%$";
79 	strnsubst(&x, "%$", "{} enpury!", 255);
80 	y = x;
81 	strnsubst(&y, "}{}", "ybir", 255);
82 	z = y;
83 	strnsubst(&z, "{", "v ", 255);
84 	za = z;
85 	strnsubst(&z, NULL, za, 255);
86 	if (strcmp(z, "v ybir enpury!") == 0)
87 		printf("strnsubst() seems to work!\n");
88 	else
89 		printf("strnsubst() is broken.\n");
90 	printf("%s\n", z);
91 	free(x);
92 	free(y);
93 	free(z);
94 	free(za);
95 	return 0;
96 }
97 #endif
98