xref: /openbsd-src/usr.bin/xargs/strnsubst.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: strnsubst.c,v 1.2 2003/06/12 03:23:22 millert 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 #ifndef lint
13 static const char rcsid[] = "$OpenBSD: strnsubst.c,v 1.2 2003/06/12 03:23:22 millert Exp $";
14 #endif /* not lint */
15 
16 #include <err.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 
22 void	strnsubst(char **, const char *, const char *, size_t);
23 
24 /*
25  * Replaces str with a string consisting of str with match replaced with
26  * replstr as many times as can be done before the constructed string is
27  * maxsize bytes large.  It does not free the string pointed to by str, it
28  * is up to the calling program to be sure that the original contents of
29  * str as well as the new contents are handled in an appropriate manner.
30  * If replstr is NULL, then that internally is changed to a nil-string, so
31  * that we can still pretend to do somewhat meaningful substitution.
32  * No value is returned.
33  */
34 void
35 strnsubst(char **str, const char *match, const char *replstr, size_t maxsize)
36 {
37 	char *s1, *s2, *this;
38 	size_t matchlen, repllen, s2len, n;
39 
40 	if ((s1 = *str) == NULL)
41 		return;
42 	if ((s2 = malloc(maxsize)) == NULL)
43 		err(1, NULL);
44 
45 	if (replstr == NULL)
46 		replstr = "";
47 
48 	if (match == NULL || *match == '\0' || strlen(s1) >= maxsize) {
49 		strlcpy(s2, s1, maxsize);
50 		goto done;
51 	}
52 
53 	*s2 = '\0';
54 	s2len = 0;
55 	matchlen = strlen(match);
56 	repllen = strlen(replstr);
57 	for (;;) {
58 		if ((this = strstr(s1, match)) == NULL)
59 			break;
60 		n = snprintf(s2 + s2len, maxsize - s2len, "%.*s%s",
61 		    (int)(this - s1), s1, replstr);
62 		if (n == -1 || n + s2len + strlen(this + matchlen) >= maxsize)
63 			break;			/* out of room */
64 		s2len += n;
65 		s1 = this + matchlen;
66 	}
67 	strlcpy(s2 + s2len, s1, maxsize - s2len);
68 done:
69 	*str = s2;
70 	return;
71 }
72 
73 #ifdef TEST
74 #include <stdio.h>
75 
76 int
77 main(void)
78 {
79 	char *x, *y, *z, *za;
80 
81 	x = "{}%$";
82 	strnsubst(&x, "%$", "{} enpury!", 255);
83 	y = x;
84 	strnsubst(&y, "}{}", "ybir", 255);
85 	z = y;
86 	strnsubst(&z, "{", "v ", 255);
87 	za = z;
88 	strnsubst(&z, NULL, za, 255);
89 	if (strcmp(z, "v ybir enpury!") == 0)
90 		printf("strnsubst() seems to work!\n");
91 	else
92 		printf("strnsubst() is broken.\n");
93 	printf("%s\n", z);
94 	free(x);
95 	free(y);
96 	free(z);
97 	free(za);
98 	return 0;
99 }
100 #endif
101