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 #include <err.h> 13 #include <stdbool.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <unistd.h> 17 18 bool 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 * 29 * Returns true if truncation was needed to do the replacement, false if 30 * truncation was not required. 31 */ 32 bool 33 strnsubst(char **str, const char *match, const char *replstr, size_t maxsize) 34 { 35 char *s1, *s2, *this; 36 bool error = false; 37 38 s1 = *str; 39 if (s1 == NULL) 40 return false; 41 /* 42 * If maxsize is 0 then set it to the length of s1, because we have 43 * to duplicate s1. XXX we maybe should double-check whether the match 44 * appears in s1. If it doesn't, then we also have to set the length 45 * to the length of s1, to avoid modifying the argument. It may make 46 * sense to check if maxsize is <= strlen(s1), because in that case we 47 * want to return the unmodified string, too. 48 */ 49 if (maxsize == 0) { 50 match = NULL; 51 maxsize = strlen(s1) + 1; 52 } 53 s2 = calloc(1, maxsize); 54 if (s2 == NULL) 55 err(1, "calloc"); 56 57 if (replstr == NULL) 58 replstr = ""; 59 60 if (match == NULL || replstr == NULL || maxsize == strlen(s1)) { 61 strlcpy(s2, s1, maxsize); 62 goto done; 63 } 64 65 for (;;) { 66 this = strstr(s1, match); 67 if (this == NULL) 68 break; 69 if ((strlen(s2) + strlen(s1) + strlen(replstr) - 70 strlen(match) + 1) > maxsize) { 71 strlcat(s2, s1, maxsize); 72 error = true; 73 goto done; 74 } 75 strncat(s2, s1, (uintptr_t)this - (uintptr_t)s1); 76 strcat(s2, replstr); 77 s1 = this + strlen(match); 78 } 79 strcat(s2, s1); 80 done: 81 *str = s2; 82 return error; 83 } 84 85 #ifdef TEST 86 #include <stdio.h> 87 88 int 89 main(void) 90 { 91 char *x, *y, *z, *za; 92 93 x = "{}%$"; 94 strnsubst(&x, "%$", "{} enpury!", 255); 95 y = x; 96 strnsubst(&y, "}{}", "ybir", 255); 97 z = y; 98 strnsubst(&z, "{", "v ", 255); 99 za = z; 100 strnsubst(&z, NULL, za, 255); 101 if (strcmp(z, "v ybir enpury!") == 0) 102 printf("strnsubst() seems to work!\n"); 103 else 104 printf("strnsubst() is broken.\n"); 105 printf("%s\n", z); 106 free(x); 107 free(y); 108 free(z); 109 free(za); 110 return 0; 111 } 112 #endif 113