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