#include #include #define addch(s, c) { int l = strlen(s); s[l++] = c; s[l] = '\0'; } static char *do_one_match(char *s, char *left_text, char *right_text, char *dest) {char *x; if (strncmp(s, left_text, strlen(left_text)) != 0) return(NULL); else s += strlen(left_text); if (*right_text == '\0') strcpy(dest, s); else if ((x = strstr(s, right_text)) == NULL) return(NULL); else { strncpy(dest, s, x-s); dest[x-s] = '\0'; s = x; } return(s); } int resolve(char *s, const char *fmt, ...) { va_list arg_ptr; char left_text[256], right_text[256], DUMMY[256], *dest; int c; *left_text = '\0'; *right_text = '\0'; va_start(arg_ptr,fmt); for (;;) { if ((c = *fmt++) == '\0') { va_end(arg_ptr); return(do_one_match(s, left_text, right_text, dest) != NULL); } else if (c != '%') addch(right_text, c) else { if ((c = *fmt++) == 't') { char *insert = va_arg(arg_ptr, char *); while ((c = *insert++) != '\0') addch(right_text, c) } else if ((c == 's') || (c == 'S')) { if (((*left_text != '\0') || (*right_text != '\0')) && (!(s=do_one_match(s, left_text, right_text, dest)))) break; *(dest = (c == 'S' ? DUMMY : va_arg(arg_ptr, char *))) = '\0'; strcpy(left_text, right_text); *right_text = '\0'; } else if (c == '%') addch(right_text, '%') } } va_end(arg_ptr); return(0); } #include int main(int argc, char **argv) { char s[256], a[256], b[256], c[256], dyn[256]; strcpy(s, "text0text1text2text3text4"); /* Examples of mapping imp string resolution to a single C function call. We trust the compiler to generate the correct format string and make no error checks here. A long and commented version with full error checks is available on request. */ /* %if s-> a.("text1").b.("text3").c %then %start */ if (resolve(s, "%stext1%stext3%s", a, b, c)) { fprintf(stdout, "s -> %s.(text1).%s.(text3).%s\n", a,b,c); } /* Use %S instead of %s for first/last args if missing */ /* %if s-> ("text1").b.("text3") %then %start */ if (resolve(s, "%Stext1%stext3%S", b)) { fprintf(stdout, "s -> (text1).%s.(text3)\n", b); } /* %unless s-> a.("text99").b.("text3").c %then %start */ if (!resolve(s, "%stext99%stext3%s", a, b, c)) { fprintf(stdout, "s -> %s.(text99).%s.(text3).%s fails, as expected\n", a,b,c); } /* try a dynamic one */ strcpy(dyn, "text1"); /* %if s-> a.(dyn).b.("text3").c %then %start */ if (resolve(s, "%s%t%stext3%s", a, dyn, b, c)) { fprintf(stdout, "s -> %s.(%s).%s.(text3).%s\n", a,dyn,b,c); } /* awkward case - what is the spec here? */ strcpy(dyn, ""); /* %if s-> a.(dyn).b.("text3").c %then %start */ if (resolve(s, "%s%t%stext3%s", a, dyn, b, c)) { fprintf(stdout, "s -> %s.(%s).%s.(text3).%s\n", a,dyn,b,c); } /* ERRONEOUS OUTPUT IS: s -> text0.().text0text1text2.(text3).text4 */ /* No... it's correct when you initialise all the target params to "" s -> .().text0text1text2.(text3).text4 */ return(0); }