/*** SEE ALSO resolve-small.c ***/ #define DBMAIN 1 #include #include #include #include #include #ifndef FALSE #define TRUE (0==0) #define FALSE (0!=0) #endif static void addch(char *s, int c) { int l = strlen(s); s[l++] = c; s[l] = '\0'; } static char *do_one_match(/* in */ char *s, char *left_text, char *right_text, /* out */ char *dest) { char *x, *debugs = s; if (strncmp(s, left_text, strlen(left_text)) == 0) { s += strlen(left_text); } else { /*fprintf(stdout, "match(%s -> (%s).*.(%s) -> * = NULL, s = %s\n", debugs,left_text,right_text, s);*/ return(NULL); } if (*right_text == '\0') { /* final case */ strcpy(dest, s); } else if ((x = strstr(s, right_text)) != NULL) { strncpy(dest, s, x-s); dest[x-s] = '\0'; s = x; } else { /*fprintf(stdout, "match(%s -> (%s).*.(%s) -> * = NULL, s = %s\n", debugs,left_text,right_text, s);*/ return(NULL); } /*fprintf(stdout, "match(%s -> (%s).*.(%s) -> * = %s, s = %s\n", debugs,left_text,right_text,dest, s);*/ return(s); } int resolve(char *s, const char *fmt, ...) { va_list arg_ptr; int c, last; char left_text[256], right_text[256], DUMMY[256], prepend[256]; char *dest; /* generic form is s -> a.("1").b.("2").c resolve(s, "%s1%s2%s", a, b, c) exceptional form is s -> ("1").b.("2") resolve(s, "%S1%s2%S", b) ie a missing first or last argument is replaced by %S. This way we implement the generic procedure only with a small tweak using a dummy arg for the missing arg when %S is given. There may be partial assignments. Assignments are carried out on the fly, one by one. May later add %255s or %*s to allow passing in a maxlength. Should accept them in fmt string for now, for future compatibility (%*s means get size from an int param following the string address) */ last = strlen(fmt)-1; assert((fmt[0] == '%') && (tolower(fmt[1]) == 's')); assert((fmt[last-1] == '%') && (tolower(fmt[last]) == 's')); *left_text = '\0'; *right_text = '\0'; va_start(arg_ptr,fmt); for (;;) { c = *fmt++; if (c == '\0') { va_end(arg_ptr); return(do_one_match(s, left_text, right_text, dest) != NULL); break; } else if (c == '%') { c = *fmt++; if (c == 't') { /* prepend next string arg to current position of 's' */ char *insert = va_arg(arg_ptr, char *); while ((c = *insert++) != '\0') addch(right_text, c); } else if (tolower(c) == 's') { /* First we handle the PREVIOUS %s, then we shift right_string into left_string and wait for the following one before we handle this one. Initial case is "" %s "right text" General case is "left text" %s "right text" Final case is "left text" %s "" All that we do for the %s itself is note its address as a destination. Or note the DUMMY address if it was %S */ if ((*left_text == '\0') && (*right_text == '\0')) { /* Leading %s - ignore for now */ } else { if ((s=do_one_match(s, left_text, right_text, dest)) == NULL) break; } if (c == 'S') { /* dummy argument - matches text but doesn't assign to an arg. Can only come first or last in a fmt string */ dest = DUMMY; } else { dest = va_arg(arg_ptr, char *); assert(dest != NULL); } strcpy(left_text, right_text); *right_text = '\0'; /* Everything between previous string and next string should be written to s. If no text follows, then to end of input string, ie string -> a.("text 1).b would assign everything after text1 to b. Similarly if there is no text before the %s, everything up to the next literal is assigned to s, ie ie string -> a.("text 1).b would assign everything before "text1" to a. The case of string -> ("text1").a.("text2") is treated as string -> X1.("text1").a.("text2").X2 with a dummy X1 and X2. */ } else if (c == '%') { addch(right_text, '%'); } else { assert(c == 's'); /* only %s allowed */ } } else { addch(right_text, c); } } va_end(arg_ptr); return(FALSE); } #ifdef DBMAIN int main(int argc, char **argv) { char s[256], a[256], b[256], c[256], var[256]; strcpy(s, "text0text1text2text3text4"); printf("\n\n"); /* %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); } printf("\n\n"); /* %if s-> ("text1").b.("text3") %then %start */ *a = *b = *c = '\0'; if (resolve(s, "%Stext1%stext3%S", b)) { fprintf(stdout, "s -> (text1).%s.(text3)\n", b); } printf("\n\n"); /* %if s-> a.("text99").b.("text3").c %then %start */ *a = *b = *c = '\0'; if (!resolve(s, "%stext99%stext3%s", a, b, c)) { fprintf(stdout, "s -> %s.(text99).%s.(text3).%s fails, as expected\n", a,b,c); } printf("\nDynamic:\n\n"); strcpy(var, "text1"); /* %if s-> a.(var).b.("text3").c %then %start */ if (resolve(s, "%s%t%stext3%s", a, var, b, c)) { fprintf(stdout, "s -> %s.(text1).%s.(text3).%s\n", a,b,c); } exit(0); } #endif