/* parse_utils - precision-independent pieces of parse */ #define PARSE_UTILS_VERSION "parse_utils v 1.0 11 Feb 2009" #define LIKE_MATCH_ANY '%' #define LIKE_MATCH_1 '_' #define LIKE_ESC '\\' /* See core.h for fancier defn. defining here so we do NOT have to */ /* include core.h, which requires OPTIONS, etc */ #define FALSE 0 #define TRUE 1 #include char *parse_utils_return_vers() /* Dummy routine. Exists only to force file version string into */ /* this module. Note string must not be global or we'll have con- */ /* flicts if another routine similarly includes the version string */ { static char version[] = PARSE_UTILS_VERSION; return version; } char *analyze_wilds(s) char *s; /* Given a string that starts with a "like" wildcard character */ /* Remove all but one any-chars wild and put that after */ /* any single-char wilds. (Essentially, a string of wildcards */ /* becomes "match N or more chars", where N is the number of */ /* single-char wilds). */ /* Return a pointer to the next non-wild char */ { char *strdupl(); /* from utils.c */ char *exp,*in_ptr,*out_ptr; char in_match_any_state,in_escape_state; in_match_any_state = FALSE; in_escape_state = FALSE; out_ptr = in_ptr = strdupl(&exp,s,"duplicating like expression"); while (*in_ptr != '\0') { if (in_escape_state) { /* This section copies the character after the \, including, */ /* particular, an escaped \ or match char. If the string */ /* improperly ended with \, it won't be detected here, but */ /* hopefully WILL be detected in strlike */ *out_ptr++ = *in_ptr++; in_escape_state = FALSE; } else if (*in_ptr == LIKE_MATCH_ANY) { in_ptr++; in_match_any_state = TRUE; } else if (*in_ptr == LIKE_MATCH_1) { *out_ptr++ = *in_ptr++; } else { /* This section copies an escaping \ (along w/non-match chars) */ in_escape_state = (*in_ptr == LIKE_ESC); if (in_match_any_state) { *out_ptr++ = LIKE_MATCH_ANY; in_match_any_state = FALSE; } *out_ptr++ = *in_ptr++; } } if (in_match_any_state) *out_ptr++ = LIKE_MATCH_ANY; *out_ptr = '\0'; return exp; } int strlike(s,like_exp,err) char *s,*like_exp; void (*err)(); /* Implementation of SQL "like". */ /* s is the candidate string. like_exp is a "like expression" */ /* consisting of normal characters and wildcard characters. */ /* wildcard characters are of 2 kinds; _ which represents */ /* exactly 1 character, and @ which represents 0 or more */ /* characters. (The actual characters used are compiled into */ /* this program. @ and _ are what were documented in the */ /* Oracle description). Characters can be escaped with a */ /* preceding \ (or other char compiled into program) */ /* Returns 0 if match; positive integer indicating point of */ /* non-match */ { char *s_ptr; char *exp,*exp_ptr; int ret_val; char prev_char_matched; ret_val = 0; prev_char_matched = TRUE; s_ptr = s; exp_ptr = exp = analyze_wilds(like_exp); while ((*exp_ptr != '\0') && (*s_ptr != '\0') && prev_char_matched) { switch (*exp_ptr) { case LIKE_MATCH_1: exp_ptr++; s_ptr++; break; case LIKE_MATCH_ANY: /* When s_ptr matches char after wildcard, reset to do */ /* test again through default: case, putting us back on */ /* "normal" track. */ if (*s_ptr++ == *(exp_ptr+1)) { s_ptr--; exp_ptr++; } break; case LIKE_ESC: if (*(++exp_ptr) == '\0') err ("like expression may not end w/escape. expression: ",exp); /* Deliberately fall through */ default: prev_char_matched = (*s_ptr++ == *exp_ptr++); break; } } /* Take care of case where everything matched up to a final */ /* match-any char */ if (*exp_ptr == LIKE_MATCH_ANY) exp_ptr++; ret_val = ((*exp_ptr == '\0') && (*s_ptr == '\0') && prev_char_matched) ? 0 : s_ptr - s; free (exp); return ret_val; }