void _logdebuginfo(server_info_t info, int level, const char *ctl, ...) { va_list va; char *str = NULL; int ipstrpad; if (level <= debug_level) { va_start(va, ctl); vasprintf(&str, ctl, va); if (str) { if (info->ipstr == NULL || strcmp(info->target, info->ipstr) == 0) { _logdebug(level, "%s: %s", info->target, str); } else { if ((ipstrpad = 15 - strlen(info->ipstr)) < 0) ipstrpad = 0; _logdebug(level, "%s %*.*s(%s): %s", info->target, ipstrpad, ipstrpad, "", info->ipstr, str); } free(str); } va_end(va); } }
static int utl_pmx_get_limits(const char *pat, const char *pat_end, const char *txt, int braced, int32_t *c_beg_ptr, int32_t *c_end_ptr, int32_t *c_esc_ptr) { int32_t c_beg = '('; int32_t c_end = ')'; int32_t c_esc = '\0'; int32_t ch; _logdebug("BRACE: [%.*s]",pat_end-pat,pat); if (pat < pat_end) { /* <B()\> <Q""\>*/ pat += utl_pmx_nextch(pat,&c_esc); if (pat < pat_end) { c_beg = c_esc; c_esc = '\0'; pat += utl_pmx_nextch(pat,&c_end); } if (pat < pat_end) { pat += utl_pmx_nextch(pat,&c_esc); } } else { /* Just <B> or <Q>, try to infer the braces */ c_beg = '\0'; (void)utl_pmx_nextch(txt,&ch); if (braced) { if (ch == '(') {c_beg=ch; c_end=')';} else if (ch == '[') {c_beg=ch; c_end=']';} else if (ch == '{') {c_beg=ch; c_end='}';} else if (ch == '<') {c_beg=ch; c_end='>';} } else { // Quoted string c_esc = '\\'; if (ch == '"') {c_beg=ch; c_end=ch;} else if (ch == '\'') {c_beg=ch; c_end=ch;} else if (ch == '`') {c_beg=ch; c_end=ch;} else if (ch == 0x91) {c_beg=ch; c_end=0x92;} /* ANSI single quotes */ else if (ch == 0x93) {c_beg=ch; c_end=0x94;} /* ANSI double quotes */ else if (ch == 0x2018) {c_beg=ch; c_end=0x2019;} /* Unicode single quotes */ else if (ch == 0x201C) {c_beg=ch; c_end=0x201D;} /* Unicode double quotes */ } if (c_beg=='\0') { /* Valid both as quoted string or braces */ if (ch == '\xAB') {c_beg=ch; c_end='\xBB';} /* Unicode and ISO-8859-1 "<<" and ">>" */ else if (ch == '\x8B') {c_beg=ch; c_end='\x9B';} /* Unicode and ISO-8859-1 "<" and ">" */ else if (ch == 0x2039) {c_beg=ch; c_end=0x203A;} /* Unicode Single pointing Angle Quotation */ else if (ch == 0x2329) {c_beg=ch; c_end=0x232A;} /* Unicode ANGLE BRACKETS */ else if (ch == 0x27E8) {c_beg=ch; c_end=0x27E9;} /* Unicode MATHEMATICAL ANGLE BRACKETS */ else if (ch == 0x27EA) {c_beg=ch; c_end=0x27EB;} /* Unicode MATHEMATICAL DOUBLE ANGLE BRACKETS */ else return 0; } } _logdebug("open:'%d' close:'%d' esc:'%d'",c_beg,c_end,c_esc); *c_beg_ptr = c_beg; *c_end_ptr = c_end; *c_esc_ptr = c_esc; return 1; }
static int utl_pmx_get_delimited(const char *pat, const char *txt,int32_t c_beg, int32_t c_end, int32_t c_esc) { int n; const char *s; int cnt; int32_t ch; s = txt; n = utl_pmx_nextch(s,&ch); if (n == 0 || ch != c_beg) return 0; cnt = 0; do { s += n; n = utl_pmx_nextch(s,&ch); if (ch == '\0') return 0; _logdebug("BRACE: '%c' cnt:%d",ch,cnt); if (ch == c_end) { if (cnt == 0) return (s+n)-txt; else cnt--; } else if (ch == c_beg) { cnt++; } else if (ch == c_esc) { s += n; n = utl_pmx_nextch(s,&ch); } } while (ch); utl_pmx_set_paterror(pat); return s-txt; }
static const char *utl_pmx_alt(const char *pat, const char **txt_ptr) { int paren=0; utl_pmx_state_s *state; int inv; const char *ret = utl_emptystring; while (*pat) { _logdebug("ALT: %s (%d)",pat,utl_pmx_stack_ptr); switch (*pat++) { case '%': if (*pat) pat++; /* works for utf8 as well */ break; case '(': paren++; utl_pmx_newcap(NULL); break; case ')': if (paren > 0) { paren--; break; } if (utl_pmx_stack_ptr < 2) { utl_pmx_set_paterror(pat); break; } // {{ If we are here, we have NOT matched what is in the (...) state = utl_pmx_state_top(); inv = state->inv; ret = pat; if (inv) { /* It's ok, we WANTED to fail */ *txt_ptr = pmxstart(state->cap); utl_pmx_state_pop(); return ret; } if (state->n >= state->min_n) { /* It's ok, we matched enough times */ utl_pmx_capt[state->cap][0] = state->txt; utl_pmx_capt[state->cap][1] = *txt_ptr; utl_pmx_state_pop(); return ret; } // }} break; case '<': while (*pat && *pat != '>') pat++; while (*pat == '>') pat++; break; case '|': if (paren == 0) { state = utl_pmx_state_top(); *txt_ptr = pmxstart(state->cap); return pat; } break; } } return utl_emptystring; }
const char *utl_pmx_search(const char *pat, const char *txt, int fromstart) { const char *ret=NULL; utl_pmx_error = NULL; utl_pmx_case = 1; if (strncmp(pat,"<utf>",5) == 0) {pat+=5; utl_pmx_utf8=1;} else if (strncmp(pat,"<iso>",5) == 0) {pat+=5; utl_pmx_utf8=0;} if (*pat == '^') ret = utl_pmx_match(pat+1,txt); else while (!(ret = utl_pmx_match(pat,txt)) && *txt && !fromstart) { txt += utl_pmx_utf8 ? utl_pmx_get_utf8(txt, NULL) : 1; } _logdebug("ret: %p",ret); return ret; }
static int32_t utl_pmx_iscapt(const char *pat, const char *txt) { int32_t len = 0; uint8_t capnum = 0; const char *cap; if ('1' <= *pat && *pat <= '9') { capnum = *pat - '0'; _logdebug("capt: %d %d",capnum,utl_pmx_capnum); if (capnum < utl_pmx_capnum) { cap = pmxstart(capnum); while (cap < pmxend(capnum) && *cap && (*cap == *txt)) { len++; txt++; cap++; } if (cap < pmxend(capnum)) len = 0; } } return len; }
static const char *utl_pmx_match(const char *pat, const char *txt) { int32_t len; int32_t ch; int32_t c1; int16_t inv =0; utl_pmx_state_s *state; utl_pmx_state_reset(); utl_pmx_state_push(pat,txt,1,1,0); while (*pat) { _logdebug("[MATCH] %d [%s] [%s]",pmxcount(),pat,txt); c1 = 0; switch (*pat) { case '(' : pat++; if (*pat == '|') {inv = 1; pat++;} if (!utl_pmx_state_push(pat,txt,1,1,inv)) utl_pmx_set_paterror(pat); break; case '|' : pat = utl_pmx_alt_skip(pat); break; case ')' : pat++; _logdebug(")->%d",utl_pmx_stack_ptr); if (utl_pmx_stack_ptr < 2) { utl_pmx_set_paterror(pat-1); break; } /* If we are here, we have matched what is in the (...) */ state = utl_pmx_state_top(); inv = state->inv; if (inv) { /* we shouldn't have matched it :( */ utl_pmx_state_pop(); utl_pmx_FAIL; } utl_pmx_capt[state->cap][1] = txt; state->n++; _logdebug("match #%d min:%d max:%d",state->n,state->min_n, state->max_n); if (state->n < state->max_n) { utl_pmx_capt[state->cap][0] = txt; pat = state->pat; /* try to match once more */ } else { utl_pmx_capt[state->cap][0] = state->txt; utl_pmx_state_pop(); } break; case '<' : if (!utl_pmx_class(&pat,&txt)) utl_pmx_FAIL; break; case '%' : if (pat[1]) len = utl_pmx_nextch(++pat, &c1); default : if (c1 == 0) len = utl_pmx_nextch(pat, &c1); len = utl_pmx_nextch(txt, &ch); if (!utl_pmx_case) { ch = utl_pmx_fold(ch); c1 = utl_pmx_fold(c1); } if (ch != c1) { _logdebug("FAIL: %d %d",c1,ch); utl_pmx_FAIL; } txt += len; pat += len; break; fail : pat = utl_pmx_alt(pat, &txt) ; /* search for an alternative */ if (*pat == '\0') utl_pmx_capnum = 0; break; } } utl_pmx_capt[0][1] = txt; for (len = utl_pmx_capnum; len < utl_pmx_MAXCAPT; len++) { utl_pmx_capt[len][0] = utl_pmx_capt[len][1] = NULL; } _logdebug("res: %p - %p",utl_pmx_capt[0][0],utl_pmx_capt[0][1]); return utl_pmx_capt[0][0]; }
static int utl_pmx_class(const char **pat_ptr, const char **txt_ptr) { int inv = 0; const char *pat = *pat_ptr; const char *txt = *txt_ptr; const char *pat_end; int32_t len = 0; int32_t n = 0; int32_t min_n = 0; int32_t max_n = 0; int32_t ch; _logdebug("class:[%s][%s]",pat,txt); pat++; /* skip the '<' */ // {{ Find the end of the pattern pat_end=pat; while (*pat_end && *pat_end != '>') pat_end++; if (pat_end[1] == '>') pat_end++; /* allow just one '>' at the end of a pattern */ //}} // {{ Get how many times the match has to occur. // Examples: <2-4l> matches 2,3 or 4 lower case letters // <-4d> matches from 0 to 4 decimal digits // <2-s> matches at 2 spaces or more // <3u> matches exactly 3 upper case letters while ('0' <= *pat && *pat <= '9') min_n = (min_n*10) + (*pat++ - '0'); if (*pat == '-') { pat++; while ('0'<=*pat && *pat <= '9') max_n = (max_n*10) + (*pat++ - '0'); if (max_n == 0) max_n = INT32_MAX; } if (max_n < min_n) max_n = min_n; if (max_n == 0) { switch (*pat) { case '*' : min_n = 0; max_n = INT32_MAX; pat++; break; case '+' : min_n = 1; max_n = INT32_MAX; pat++; break; case '?' : min_n = 0; max_n = 1; pat++; break; default : min_n = 1; max_n = 1; break; } } // }} if (*pat == '!') {inv = 1; pat++;} // {{ This is for handling repetition of patterns between parenthesis: // Example: '<*>(\\'|<!='>)' <-- single quoted string (\' as escaped) // <3>(xa|pt) <-- "ptptpt" or "ptxaxa" or "xaxapt" or ... if (pat[0] == '>' && pat[1] == '(') { pat += 2; if (!utl_pmx_state_push(pat,txt,min_n,max_n,inv)) utl_pmx_set_paterror(pat); *pat_ptr = pat; return 1; } // }} // {{ Matches a pattern n times #define utl_W(tst) while ((len = utl_pmx_nextch(txt,&ch)) && ((!tst) == inv) && (n<max_n)) {n++; txt+=len;} switch (*pat) { case 'a' : utl_W(( utl_isalpha(ch) )); break; case 's' : utl_W(( utl_isspace(ch) )); break; case 'u' : utl_W(( utl_isupper(ch) )); break; case 'l' : utl_W(( utl_islower(ch) )); break; case 'd' : utl_W(( utl_isdigit(ch) )); break; case 'k' : utl_W(( utl_isblank(ch) )); break; case 'x' : utl_W(( utl_isxdigit(ch))); break; case 'w' : utl_W(( utl_isalnum(ch) )); break; case 'c' : utl_W(( utl_iscntrl(ch) )); break; case 'g' : utl_W(( utl_isgraph(ch) )); break; case 'p' : utl_W(( utl_ispunct(ch) )); break; case 'r' : utl_W(( utl_isprint(ch) )); break; case 'i' : utl_W((ch < 0x80)) ; break; case '.' : utl_W((ch !='\0' && ch !='\n')) ; break; case '=' : utl_W(utl_pmx_isin_chars(pat+1,pat_end,ch)) ; break; case '#' : utl_W(utl_pmx_isin_codes(pat+1,pat_end,ch)) ; break; case 'N' : utl_W((txt[0]=='\r' ? (txt[1] == '\n'? (len++) : 1) : (txt[0] == '\n'? 1 : 0) )) ; break; case 'Q' : utl_W((len=utl_pmx_delimited(pat+1,pat_end,txt, UTL_PMX_QUOTED))); break; case 'B' : utl_W((len=utl_pmx_delimited(pat+1,pat_end,txt, UTL_PMX_BRACED))); break; case 'I' : utl_pmx_case = 0; n=min_n; break; case 'C' : utl_pmx_case = 1; n=min_n; break; case '$' : if (*txt == '\0') n=min_n; break; case '>' : utl_pmx_set_paterror(pat); return 0; case '^' : if (inv) utl_pmx_set_paterror(pat); inv = 0; utl_W((len=utl_pmx_iscapt(pat+1,txt))); break; case ':' : if (utl_pmx_ext) utl_W((len=utl_pmx_ext(pat+1,txt,len,ch))); break; default : ; //utl_pmx_set_paterror(pat); } #undef utl_W // }} // {{ Advance pattern while (*pat_end == '>') pat_end++; *pat_ptr=pat_end; // }} /* Not enough matches */ if (n < min_n) return 0; // {{ Advance matched text *txt_ptr = txt; // }} return 1; }
static int utl_pmx_get_utf8(const char *txt, int32_t *ch) { int len; uint8_t *s = (uint8_t *)txt; uint8_t first = *s; int32_t val; _logdebug("About to get UTF8: %s in %p",txt,ch); fsm { fsmSTART { if (*s <= 0xC1) { val = *s; len = (*s > 0); fsmGOTO(end); } if (*s <= 0xDF) { val = *s & 0x1F; len = 2; fsmGOTO(len2); } if (*s == 0xE0) { val = *s & 0x0F; len = 3; fsmGOTO(len3_0); } if (*s <= 0xEC) { val = *s & 0x0F; len = 3; fsmGOTO(len3_1); } if (*s == 0xED) { val = *s & 0x0F; len = 3; fsmGOTO(len3_2); } if (*s <= 0xEF) { val = *s & 0x0F; len = 3; fsmGOTO(len3_1); } if (*s == 0xF0) { val = *s & 0x07; len = 4; fsmGOTO(len4_0); } if (*s <= 0xF3) { val = *s & 0x07; len = 4; fsmGOTO(len4_1); } if (*s == 0xF4) { val = *s & 0x07; len = 4; fsmGOTO(len4_2); } fsmGOTO(invalid); } fsmSTATE(len4_0) { s++; if ( *s < 0x90 || 0xbf < *s) fsmGOTO(invalid); val = (val << 6) | (*s & 0x3F); fsmGOTO(len3_1); } fsmSTATE(len4_1) { s++; if ( *s < 0x80 || 0xbf < *s) fsmGOTO(invalid); val = (val << 6) | (*s & 0x3F); fsmGOTO(len3_1); } fsmSTATE(len4_2) { s++; if ( *s < 0x80 || 0x8f < *s) fsmGOTO(invalid); val = (val << 6) | (*s & 0x3F); fsmGOTO(len3_1); } fsmSTATE(len3_0) { s++; if ( *s < 0xA0 || 0xbf < *s) fsmGOTO(invalid); val = (val << 6) | (*s & 0x3F); fsmGOTO(len2); } fsmSTATE(len3_1) { s++; if ( *s < 0x80 || 0xbf < *s) fsmGOTO(invalid); val = (val << 6) | (*s & 0x3F); fsmGOTO(len2); } fsmSTATE(len3_2) { s++; if ( *s < 0x80 || 0x9f < *s) fsmGOTO(invalid); val = (val << 6) | (*s & 0x3F); fsmGOTO(len2); } fsmSTATE(len2) { s++; if ( *s < 0x80 || 0xbf < *s) fsmGOTO(invalid); val = (val << 6) | (*s & 0x3F); fsmGOTO(end); } fsmSTATE(invalid) {val = first; len = 1;} fsmSTATE(end) { } } if (ch) *ch = val; return len; }