/* mass string substituter Intended for efficient implementation of things like the jivering Takes as input: A string, an integer mode value, and a list of alternating source, destination values. It replaces all occurences of each source value with each destination value, _in order_, so that they can replace on top of each other--that is, it substitutes all occurences of the first pattern, and then takes the result of that and applies the second, etc. The mode value is used to control boundary conditions: 0 substitute on any match 1 substitute only at beginning of word 2 substitute only at end of word 3 substitute only exactly this word */ #include <stdio.h> #include <ctype.h> #include "lint.h" #include "interpret.h" char *strstr(); #ifndef __ANSI__ #ifdef NO_STRSTR /* If they don't have a strstr, do our own... may not be most efficient way without a host strstr. */ char *strstr(src, pattern) char *src; char *pattern; { for(;*src;++src) if (*src == *pattern) if (!strcmp(src, pattern)) return src; return (char *) 0; } #endif #endif #define ok(c) (!isalnum(c)) char *strsub(src, arr, mode) char *src; struct vector *arr; int mode; { extern char *malloc(), *realloc(); char *result, *find, *tmp; int nlen, mlen; int i,offset, len; char *subsrc, *subdest; int ssrclen, sdestlen, delta; len = arr->size; if (len % 2) error("Odd length array given to strsub.\n"); for (i=0; i < arr->size; ++i) if (arr->item[i].type != T_STRING) error("Invalid type in array, given to strsub.\n"); nlen = strlen(src); result = malloc(mlen = (3*nlen+1)); if (!result) return NULL; strcpy(result, src); for (i=0; i+1<len; i+=2) { subsrc = arr->item[i].u.string; subdest = arr->item[i+1].u.string; ssrclen = strlen(subsrc); sdestlen = strlen(subdest); delta = sdestlen - ssrclen; if (!ssrclen) break; offset = 0; /* place to start looking */ while (offset + ssrclen <= nlen) { find = strstr(result + offset, subsrc); if (!find) break; /* calc next place to check */ offset = find - result + 1; /* check boundary conditions */ if (mode == 1 && ((find > result && !ok(find[-1])) || ok(find[ssrclen]))) continue; if (mode == 2 && (find == result || ok(find[-1]) || !ok(find[ssrclen]))) continue; if (mode == 3 && ((find > result && !ok(find[-1])) || !ok(find[ssrclen]))) continue; /* make room for copy */ if (nlen + delta >= mlen) { mlen *= 2; if (nlen + delta >= mlen) mlen += delta + 1; result = realloc(result, mlen+2); if (!result) return NULL; } /* * Bcopy handles overlapping string correctly. On systems without * bcopy, memmove is used (lint.h #defines it correctly). */ bcopy(find + ssrclen, find + sdestlen, nlen - (offset + ssrclen) + 2); memcpy(find, subdest, sdestlen); nlen += delta; offset += sdestlen-1; } } result = realloc(result, nlen + 4); return result; /* Checks for null in the caller */ }