1 /* $OpenBSD: strnsubst.c,v 1.8 2023/04/19 12:58:16 jsg 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
strnsubst(char ** str,const char * match,const char * replstr,size_t maxsize)31 strnsubst(char **str, const char *match, const char *replstr, size_t maxsize)
32 {
33 char *s1, *s2, *this;
34 size_t matchlen, 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 for (;;) {
54 if ((this = strstr(s1, match)) == NULL)
55 break;
56 n = snprintf(s2 + s2len, maxsize - s2len, "%.*s%s",
57 (int)(this - s1), s1, replstr);
58 if (n < 0 || n + s2len + strlen(this + matchlen) >= maxsize)
59 break; /* out of room */
60 s2len += n;
61 s1 = this + matchlen;
62 }
63 strlcpy(s2 + s2len, s1, maxsize - s2len);
64 done:
65 *str = s2;
66 return;
67 }
68
69 #ifdef TEST
70
71 int
main(void)72 main(void)
73 {
74 char *x, *y, *z, *za;
75
76 x = "{}%$";
77 strnsubst(&x, "%$", "{} enpury!", 255);
78 y = x;
79 strnsubst(&y, "}{}", "ybir", 255);
80 z = y;
81 strnsubst(&z, "{", "v ", 255);
82 za = z;
83 strnsubst(&z, NULL, za, 255);
84 if (strcmp(z, "v ybir enpury!") == 0)
85 printf("strnsubst() seems to work!\n");
86 else
87 printf("strnsubst() is broken.\n");
88 printf("%s\n", z);
89 free(x);
90 free(y);
91 free(z);
92 free(za);
93 return 0;
94 }
95 #endif
96