+/**
+ * simple search and replace routine
+ *
+ * \param src source string
+ * \param macro_name the name of the macro
+ * \param replacement the replacement format string
+ *
+ * In \p src, replace each occurence of \p macro_name(arg) by the string
+ * determined by the \p replacement format string. \p replacement may (but
+ * needs not) contain a single string conversion specifier (%s) which gets
+ * replaced by \p arg.
+ *
+ * \return A string in which all matches in \p src are replaced, or \p NULL if
+ * an syntax error was encountered. Caller must free the result.
+ *
+ * \sa regcomp(3)
+ */
+__must_check __malloc static char *s_a_r(const char *src, const char* macro_name,
+ const char *replacement)
+{
+ regex_t preg;
+ size_t nmatch = 1;
+ regmatch_t pmatch[1];
+ int eflags = 0;
+ char *dest = NULL;
+ const char *bufptr = src;
+
+ if (!macro_name || !replacement || !src)
+ return para_strdup(src);
+ regcomp(&preg, macro_name, 0);
+ while (regexec(&preg, bufptr, nmatch, pmatch, eflags)
+ != REG_NOMATCH) {
+ char *tmp, *arg, *o_bracket, *c_bracket;
+
+ o_bracket = strchr(bufptr + pmatch[0].rm_so, '(');
+ c_bracket = o_bracket? strchr(o_bracket, ')') : NULL;
+ if (!c_bracket)
+ goto out;
+ tmp = para_strdup(bufptr);
+ tmp[pmatch[0].rm_so] = '\0';
+ dest = para_strcat(dest, tmp);
+ free(tmp);
+
+ arg = para_strdup(o_bracket + 1);
+ arg[c_bracket - o_bracket - 1] = '\0';
+ tmp = make_message(replacement, arg);
+ free(arg);
+ dest = para_strcat(dest, tmp);
+ free(tmp);
+ bufptr = c_bracket;
+ bufptr++;
+ }
+ dest = para_strcat(dest, bufptr);
+// PARA_DEBUG_LOG("%s: returning %s\n", __func__, dest);
+out:
+ regfree(&preg);
+ return dest;
+}
+
+/**
+ * replace a string according to a list of macros
+ *
+ * \param macro_list the array containing a macro/replacement pairs.
+ * \param src the source string
+ *
+ * This function just calls s_a_r() for each element of \p macro_list.
+ *
+ * \return \p NULL if one of the underlying calls to \p s_a_r returned \p NULL.
+ * Otherwise the completely expanded version of \p src is returned.
+ */
+__must_check __malloc static char *s_a_r_list(struct para_macro *macro_list, char *src)
+{
+ struct para_macro *mp = macro_list;
+ char *ret = NULL, *tmp = para_strdup(src);
+
+ while (mp->name) {
+ ret = s_a_r(tmp, mp->name, mp->replacement);
+ free(tmp);
+ if (!ret) /* syntax error */
+ return NULL;
+ tmp = ret;
+ mp++;
+ }
+ //PARA_DEBUG_LOG("%s: returning %s\n", __func__, dest);
+ return ret;
+}
+