1fc17b349SJuli Mallett /* $xMach: strnsubst.c,v 1.3 2002/02/23 02:10:24 jmallett Exp $ */ 2fc17b349SJuli Mallett 3fc17b349SJuli Mallett /* 4fc17b349SJuli Mallett * Copyright (c) 2002 J. Mallett. All rights reserved. 5fc17b349SJuli Mallett * You may do whatever you want with this file as long as 6fc17b349SJuli Mallett * the above copyright and this notice remain intact, along 7fc17b349SJuli Mallett * with the following statement: 8fc17b349SJuli Mallett * For the man who taught me vi, and who got too old, too young. 9fc17b349SJuli Mallett */ 10fc17b349SJuli Mallett 11fc17b349SJuli Mallett #include <sys/cdefs.h> 12fc17b349SJuli Mallett __FBSDID("$FreeBSD$"); 13fc17b349SJuli Mallett 14fc17b349SJuli Mallett #include <err.h> 15fc17b349SJuli Mallett #include <stdlib.h> 16fc17b349SJuli Mallett #include <string.h> 17fc17b349SJuli Mallett #include <unistd.h> 18fc17b349SJuli Mallett 19fc17b349SJuli Mallett void strnsubst(char **, const char *, const char *, size_t); 20fc17b349SJuli Mallett 21fc17b349SJuli Mallett /* 22fc17b349SJuli Mallett * Replaces str with a string consisting of str with match replaced with 23fc17b349SJuli Mallett * replstr as many times as can be done before the constructed string is 24fc17b349SJuli Mallett * maxsize bytes large. It does not free the string pointed to by str, it 25fc17b349SJuli Mallett * is up to the calling program to be sure that the original contents of 26fc17b349SJuli Mallett * str as well as the new contents are handled in an appropriate manner. 27986d829bSJuli Mallett * If replstr is NULL, then that internally is changed to a nil-string, so 28986d829bSJuli Mallett * that we can still pretend to do somewhat meaningful substitution. 29fc17b349SJuli Mallett * No value is returned. 30fc17b349SJuli Mallett */ 31fc17b349SJuli Mallett void 32fc17b349SJuli Mallett strnsubst(char **str, const char *match, const char *replstr, size_t maxsize) 33fc17b349SJuli Mallett { 34299ea75aSJuli Mallett char *s1, *s2, *this; 35fc17b349SJuli Mallett 36fc17b349SJuli Mallett s1 = *str; 37fc17b349SJuli Mallett if (s1 == NULL) 38fc17b349SJuli Mallett return; 3938e62c69SJuli Mallett /* 40*dae3a64fSEitan Adler * If maxsize is 0 then set it to the length of s1, because we have 4138e62c69SJuli Mallett * to duplicate s1. XXX we maybe should double-check whether the match 4238e62c69SJuli Mallett * appears in s1. If it doesn't, then we also have to set the length 4338e62c69SJuli Mallett * to the length of s1, to avoid modifying the argument. It may make 4438e62c69SJuli Mallett * sense to check if maxsize is <= strlen(s1), because in that case we 4538e62c69SJuli Mallett * want to return the unmodified string, too. 4638e62c69SJuli Mallett */ 4738e62c69SJuli Mallett if (maxsize == 0) { 4838e62c69SJuli Mallett match = NULL; 4938e62c69SJuli Mallett maxsize = strlen(s1) + 1; 5038e62c69SJuli Mallett } 51df4110b6SXin LI s2 = calloc(1, maxsize); 52fc17b349SJuli Mallett if (s2 == NULL) 53fc17b349SJuli Mallett err(1, "calloc"); 54fc17b349SJuli Mallett 55986d829bSJuli Mallett if (replstr == NULL) 56986d829bSJuli Mallett replstr = ""; 57986d829bSJuli Mallett 58299ea75aSJuli Mallett if (match == NULL || replstr == NULL || maxsize == strlen(s1)) { 590fa5e8dcSJuli Mallett strlcpy(s2, s1, maxsize); 600fa5e8dcSJuli Mallett goto done; 610fa5e8dcSJuli Mallett } 620fa5e8dcSJuli Mallett 63fc17b349SJuli Mallett for (;;) { 64fc17b349SJuli Mallett this = strstr(s1, match); 65fc17b349SJuli Mallett if (this == NULL) 66fc17b349SJuli Mallett break; 675578bd8cSColin Percival if ((strlen(s2) + strlen(s1) + strlen(replstr) - 685578bd8cSColin Percival strlen(match) + 1) > maxsize) { 69fc17b349SJuli Mallett strlcat(s2, s1, maxsize); 70fc17b349SJuli Mallett goto done; 71fc17b349SJuli Mallett } 72fc17b349SJuli Mallett strncat(s2, s1, (uintptr_t)this - (uintptr_t)s1); 73fc17b349SJuli Mallett strcat(s2, replstr); 74fc17b349SJuli Mallett s1 = this + strlen(match); 75fc17b349SJuli Mallett } 76fc17b349SJuli Mallett strcat(s2, s1); 77fc17b349SJuli Mallett done: 78fc17b349SJuli Mallett *str = s2; 79fc17b349SJuli Mallett return; 80fc17b349SJuli Mallett } 81fc17b349SJuli Mallett 82fc17b349SJuli Mallett #ifdef TEST 83fc17b349SJuli Mallett #include <stdio.h> 84fc17b349SJuli Mallett 85fc17b349SJuli Mallett int 86fc17b349SJuli Mallett main(void) 87fc17b349SJuli Mallett { 885058dcb4SJuli Mallett char *x, *y, *z, *za; 89fc17b349SJuli Mallett 905058dcb4SJuli Mallett x = "{}%$"; 915058dcb4SJuli Mallett strnsubst(&x, "%$", "{} enpury!", 255); 925058dcb4SJuli Mallett y = x; 935058dcb4SJuli Mallett strnsubst(&y, "}{}", "ybir", 255); 945058dcb4SJuli Mallett z = y; 955058dcb4SJuli Mallett strnsubst(&z, "{", "v ", 255); 965058dcb4SJuli Mallett za = z; 975058dcb4SJuli Mallett strnsubst(&z, NULL, za, 255); 985058dcb4SJuli Mallett if (strcmp(z, "v ybir enpury!") == 0) 995058dcb4SJuli Mallett printf("strnsubst() seems to work!\n"); 1005058dcb4SJuli Mallett else 1015058dcb4SJuli Mallett printf("strnsubst() is broken.\n"); 1025058dcb4SJuli Mallett printf("%s\n", z); 103fc17b349SJuli Mallett free(x); 1045058dcb4SJuli Mallett free(y); 1055058dcb4SJuli Mallett free(z); 1065058dcb4SJuli Mallett free(za); 107fc17b349SJuli Mallett return 0; 108fc17b349SJuli Mallett } 109fc17b349SJuli Mallett #endif 110