/*=gfunc string_substitute * * what: multiple global replacements * general_use: * * exparg: source, string to transform * exparg: match, substring or substring list to be replaced * exparg: repl, replacement strings or substrings * * doc: @code{match} and @code{repl} may be either a single string or * a list of strings. Either way, they must have the same structure * and number of elements. For example, to replace all amphersands, * less than and greater than characters, do something like this: * * @example * (string-substitute source * (list "&" "<" ">") * (list "&" "<" ">")) * @end example =*/ SCM ag_scm_string_substitute(SCM str, SCM Match, SCM Repl) { char const * text; ssize_t len; SCM res; if (! AG_SCM_STRING_P(str)) return SCM_UNDEFINED; text = scm_i_string_chars(str); len = (ssize_t)AG_SCM_STRLEN(str); if (AG_SCM_STRING_P(Match)) do_substitution(text, len, Match, Repl, (char **)&text, &len); else do_multi_subs((char **)&text, &len, Match, Repl); res = AG_SCM_STR2SCM(text, (size_t)len); return res; }
/*=gfunc string_substitute * * what: multiple global replacements * general_use: * * exparg: source, string to transform * exparg: match, substring or substring list to be replaced * exparg: repl, replacement strings or substrings * * doc: @code{match} and @code{repl} may be either a single string or * a list of strings. Either way, they must have the same structure * and number of elements. For example, to replace all amphersands, * less than and greater than characters, do something like this: * * @example * (string-substitute source * (list "&" "<" ">") * (list "&" "<" ">")) * @end example =*/ SCM ag_scm_string_substitute(SCM Str, SCM Match, SCM Repl) { char const * pzStr; ssize_t len; SCM res; if (! AG_SCM_STRING_P(Str)) return SCM_UNDEFINED; pzStr = AG_SCM_CHARS(Str); len = AG_SCM_STRLEN(Str); if (AG_SCM_STRING_P(Match)) do_substitution(pzStr, len, Match, Repl, (char**)&pzStr, &len); else do_multi_subs((char**)&pzStr, &len, Match, Repl); res = AG_SCM_STR2SCM(pzStr, len); return res; }
/* * Recursive routine. It calls itself for list values and calls * "do_substitution" for string values. Each substitution will * be done in the order found in the tree walk of list values. * The "match" and "repl" trees *must* be identical in structure. */ LOCAL void do_multi_subs(char ** ppzStr, ssize_t * pStrLen, SCM match, SCM repl) { char * pzStr = *ppzStr; char * pzNxt = pzStr; /* * Loop for as long as our list has more entries */ while (! scm_is_null(match)) { /* * "CAR" is the current value, "CDR" is rest of list */ SCM matchCar = SCM_CAR(match); SCM replCar = SCM_CAR(repl); match = SCM_CDR(match); repl = SCM_CDR(repl); if (AG_SCM_STRING_P(matchCar)) { do_substitution(pzStr, *pStrLen, matchCar, replCar, &pzNxt, pStrLen); // coverity[use_after_free] -- invalid alias analysis pzStr = pzNxt; } else if (AG_SCM_LIST_P(matchCar)) do_multi_subs(&pzStr, pStrLen, matchCar, replCar); else /* * Whatever it is it is not part of what we would expect. Bail. */ break; } *ppzStr = pzStr; }