int parse_avp_spec( str *name, int *type, int_str *avp_name) { char *p; if (name==0 || name->s==0 || name->len==0) return -1; p = (char*)memchr((void*)name->s, AVP_NAME_DELIM, name->len); if (p==NULL) { /* it's an avp alias */ return lookup_avp_galias( name, type, avp_name); } else { return parse_avp_name( name, type, avp_name); } }
int xl_parse_format(char *s, xl_elog_p *el) { char *p, c; int n = 0; xl_elog_p e, e0; struct hdr_field hdr; str name; int avp_flags, avp_index; int_str avp_name; select_t *sel; if(s==NULL || el==NULL) return -1; DBG("XLOG: xl_parse_format: parsing [%s]\n", s); p = s; *el = NULL; e = e0 = NULL; while(*p) { e0 = e; e = pkg_malloc(sizeof(xl_elog_t)); if(!e) goto error; memset(e, 0, sizeof(xl_elog_t)); n++; if(*el == NULL) *el = e; if(e0) e0->next = e; e->text.s = p; while(*p && *p!='%') p++; e->text.len = p - e->text.s; if(*p == '\0') break; p++; switch(*p) { case 'b': p++; switch(*p) { case 'r': e->itf = xl_get_branch; break; case 'R': e->itf = xl_get_branches; break; default: e->itf = xl_get_null; } break; case 'c': p++; switch(*p) { case 'i': e->itf = xl_get_callid; break; case 's': e->itf = xl_get_cseq; break; case 't': e->itf = xl_get_contact; break; default: e->itf = xl_get_null; } break; case 'C': p++; e->hparam.s = p; /* foreground */ switch(*p) { case 'x': case 's': case 'r': case 'g': case 'y': case 'b': case 'p': case 'c': case 'w': case 'S': case 'R': case 'G': case 'Y': case 'B': case 'P': case 'C': case 'W': break; default: e->itf = xl_get_empty; goto error; } p++; /* background */ switch(*p) { case 'x': case 's': case 'r': case 'g': case 'y': case 'b': case 'p': case 'c': case 'w': break; default: e->itf = xl_get_empty; goto error; } /* end */ e->hparam.len = 2; e->itf = xl_get_color; break; case 'd': p++; switch(*p) { case 's': e->itf = xl_get_dset; break; default: e->itf = xl_get_null; } break; case 'f': p++; switch(*p) { case 'u': e->itf = xl_get_from; break; case 't': e->itf = xl_get_from_tag; break; default: e->itf = xl_get_null; } break; case 'H': p++; e->itf = xl_get_host; switch(*p) { case 'n': e->hindex = XL_HOST_NAME; break; case 'd': e->hindex = XL_HOST_DOMAIN; break; case 'f': e->hindex = XL_HOST_FULL; break; case 'i': e->hindex = XL_HOST_IPADDR; break; default: e->hindex = XL_HOST_NULL; break; } break; case 'm': p++; switch(*p) { case 'b': e->itf = xl_get_msg_buf; break; case 'f': e->itf = xl_get_flags; break; case 'i': e->itf = xl_get_msgid; e->hindex = 10; break; case 'l': e->itf = xl_get_msg_len; break; case 'x': e->itf = xl_get_msgid; e->hindex = 16; break; default: e->itf = xl_get_null; } break; case 'n': p++; switch(*p) { case 'h': e->itf = xl_get_nexthop; break; default: e->itf = xl_get_null; } break; case 'p': p++; switch(*p) { case 'p': e->itf = xl_get_pid; e->hindex = 10; break; case 'x': e->itf = xl_get_pid; e->hindex = 16; break; default: e->itf = xl_get_null; } break; case 'r': p++; switch(*p) { case 'm': e->itf = xl_get_method; break; case 'u': e->itf = xl_get_ruri; break; case 's': e->itf = xl_get_status; break; case 'r': e->itf = xl_get_reason; break; case 't': e->itf = xl_get_refer_to; break; default: e->itf = xl_get_null; } break; case 'R': p++; switch(*p) { case 'i': e->itf = xl_get_rcvip; break; case 'p': e->itf = xl_get_rcvport; break; default: e->itf = xl_get_null; } break; case 's': p++; switch(*p) { case 'i': e->itf = xl_get_srcip; break; case 'p': e->itf = xl_get_srcport; break; default: e->itf = xl_get_null; } break; case 't': p++; switch(*p) { case 'u': e->itf = xl_get_to; break; case 't': e->itf = xl_get_to_tag; break; default: e->itf = xl_get_null; } break; case 'T': p++; switch(*p) { case 's': e->itf = xl_get_times; e->hindex = 10; break; case 'f': e->itf = xl_get_timef; break; case 'x': e->itf = xl_get_times; e->hindex = 16; break; default: e->itf = xl_get_null; } break; case 'u': p++; switch(*p) { case 'a': e->itf = xl_get_useragent; break; case 'q': e->itf = xl_get_unique; break; default: e->itf = xl_get_null; } break; case '{': p++; /* we expect a letter */ if((*p < 'A' || *p > 'Z') && (*p < 'a' || *p > 'z')) { LOG(L_ERR, "xlog: xl_parse_format: error parsing format" " [%s] pos [%d]\n", s, (int)(p-s)); goto error; } e->hparam.s = p; while(*p && *p!='}' && *p!='[') p++; if(*p == '\0') { LOG(L_ERR, "xlog: xl_parse_format: error parsing format" " [%s] expecting '}' after position [%d]\n", s, (int)(e->hparam.s-s)); goto error; } e->hparam.len = p - e->hparam.s; /* check if we have index */ if(*p == '[') { p++; if(*p=='-') { p++; if(*p!='1') { LOG(L_ERR, "xlog: xl_parse_format: error" " parsing format [%s] -- only -1 is accepted" " as a negative index\n", s); goto error; } e->hindex = XLOG_PRINT_LAST; p++; } else if (*p=='*') { e->hindex = XLOG_PRINT_ALL; p++; } else { while(*p>='0' && *p<='9') { e->hindex = e->hindex * 10 + *p - '0'; p++; } } if(*p != ']') { LOG(L_ERR, "xlog: xl_parse_format: error parsing format" " [%s] expecting ']' after position [%d]\n", s, (int)(e->hparam.s - s + e->hparam.len)); goto error; } p++; } if(*p != '}') { LOG(L_ERR, "xlog: xl_parse_format: error parsing format" " [%s] expecting '}' after position [%d]!\n", s, (int)(e->hparam.s-s)); goto error; } DBG("xlog: xl_parse_format: header name [%.*s] index [%d]\n", e->hparam.len, e->hparam.s, e->hindex); /* optimize for known headers -- fake header name */ c = e->hparam.s[e->hparam.len]; e->hparam.s[e->hparam.len] = ':'; e->hparam.len++; /* ugly hack for compact header names -- !!fake length!! * -- parse_hname2 expects name buffer length >= 4 */ if (parse_hname2(e->hparam.s, e->hparam.s + ((e->hparam.len<4)?4:e->hparam.len), &hdr)==0) { LOG(L_ERR,"xlog: xl_parse_format: strange error\n"); goto error; } e->hparam.len--; e->hparam.s[e->hparam.len] = c; if (hdr.type!=HDR_OTHER_T && hdr.type!=HDR_ERROR_T) { LOG(L_INFO,"INFO:xlog: xl_parse_format: using " "hdr type (%d) instead of <%.*s>\n", hdr.type, e->hparam.len, e->hparam.s); e->hparam.len = hdr.type; e->hparam.s = NULL; } e->itf = xl_get_header; break; case '<': p++; /* we expect a letter */ if((*p < 'A' || *p > 'Z') && (*p < 'a' || *p > 'z')) { LOG(L_ERR, "xlog: xl_parse_format: error parsing format" " [%s] pos [%d]\n", s, (int)(p-s)); goto error; } e->hparam.s = p; while(*p && *p!='>' && *p!='[') p++; if(*p == '\0') { LOG(L_ERR, "xlog: xl_parse_format: error parsing format" " [%s] expecting '>' after position [%d]\n", s, (int)(e->hparam.s-s)); goto error; } e->hparam.len = p - e->hparam.s; /* check if we have index */ if(*p == '[') { p++; if(*p=='-') { p++; if(*p!='1') { LOG(L_ERR, "xlog: xl_parse_format: error" " parsing format [%s] -- only -1 is accepted" " as a negative index\n", s); goto error; } e->hindex = -1; p++; } else { while(*p>='0' && *p<='9') { e->hindex = e->hindex * 10 + *p - '0'; p++; } } if(*p != ']') { LOG(L_ERR, "xlog: xl_parse_format: error parsing format" " [%s] expecting ']' after position [%d]\n", s, (int)(e->hparam.s - s + e->hparam.len)); goto error; } p++; } if(*p != '>') { LOG(L_ERR, "xlog: xl_parse_format: error parsing format" " [%s] expecting '>' after position [%d]!\n", s, (int)(e->hparam.s-s)); goto error; } DBG("xlog: xl_parse_format: AVP [%.*s] index [%d]\n", e->hparam.len, e->hparam.s, e->hindex); e->itf = xl_get_avp; break; case '$': p++; name.s=p; while ( (*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9') || (*p=='_') || (*p=='+') || (*p=='-') || (*p=='[') || (*p==']') || (*p=='.') ) p++; name.len=p-name.s; p--; if (parse_avp_name(&name, &avp_flags, &avp_name, &avp_index) < 0) { ERR("error while parsing AVP name\n"); goto error; } e->itf = xl_get_avp; e->hflags=avp_flags; e->hparam.s=name.s; e->hparam.len=name.len; e->hindex=avp_index; DBG("flags %x name %.*s index %d\n", avp_flags, avp_name.s.len, avp_name.s.s, avp_index); break; case '@': /* fill select structure and call resolve_select */ DBG("xlog: xl_parse_format: @\n"); n=parse_select(&p, &sel); if (n<0) { ERR("xlog: xl_parse_format: parse_select returned error\n"); goto error; } e->itf = xl_get_select; e->hparam.s = (char*)sel; p--; break; case '%': e->itf = xl_get_percent; break; case ' ': /* enables spaceless terminating of avp, e.g. "blah%$avp% text goes on" */ case '|': e->itf = xl_get_empty; break; default: e->itf = xl_get_null; } if(*p == '\0') break; p++; } DBG("XLOG: xl_parse_format: format parsed OK: [%d] items\n", n); return 0; error: xl_elog_free_all(*el); *el = NULL; return -1; }
/* Parse an xl-formatted string pointed by s. * el points to the resulted linked list that is allocated * in shared memory when shm==1 otherwise in pkg memory. * If parse_cb is not NULL then regular expression back references * are passed to the parse_cb function that is supposed to farther parse * the back reference and fill in the xl_elog_t structure. * * Return value: * 0: success * -1: error */ static int _xl_parse_format(char *s, xl_elog_p *el, int shm, xl_parse_cb parse_cb) { char *p, c; int n = 0; xl_elog_p e, e0; struct hdr_field hdr; str name; int avp_flags, avp_index; int_str avp_name; select_t *sel; int *range; if(s==NULL || el==NULL) return -1; DBG("XLOG: xl_parse_format: parsing [%s]\n", s); p = s; *el = NULL; e = e0 = NULL; range = NULL; while(*p) { e0 = e; if (shm) e = shm_malloc(sizeof(xl_elog_t)); else e = pkg_malloc(sizeof(xl_elog_t)); if(!e) goto error; memset(e, 0, sizeof(xl_elog_t)); n++; if(*el == NULL) *el = e; if(e0) e0->next = e; e->text.s = p; while(*p && *p!='%' && *p!='\\' && !range) p++; e->text.len = p - e->text.s; if(*p == '\0') break; if ((*p == '\\') && !range) { p++; switch(*p) { case '\\': e->itf = xl_get_special; e->hindex = '\\'; break; case 'r': e->itf = xl_get_special; e->hindex = '\r'; break; case 'n': e->itf = xl_get_special; e->hindex = '\n'; break; case 't': e->itf = xl_get_special; e->hindex = '\t'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* Regular expression back reference found */ if (!parse_cb) { /* There is no callback function, hence the * result will be written as it is. */ e->itf = xl_get_special; e->hindex = *p; break; } name.s = p; /* eat all the numeric characters */ while ((*(p+1) >= '0') && (*(p+1) <= '9')) p++; name.len = p - name.s + 1; if (parse_cb(&name, shm, e)) { ERR("xprint: xl_parse_format: failed to parse '%.*s'\n", name.len, name.s); goto error; } break; default: /* not a special character, it will be just written to the result as it is */ e->itf = xl_get_special; e->hindex = *p; } goto cont; } if (range) range = NULL; else p++; switch(*p) { case 'b': p++; switch(*p) { case 'r': e->itf = xl_get_branch; break; case 'R': e->itf = xl_get_branches; break; default: e->itf = xl_get_null; } break; case 'c': p++; switch(*p) { case 'i': e->itf = xl_get_callid; break; case 's': e->itf = xl_get_cseq; break; case 't': e->itf = xl_get_contact; break; default: e->itf = xl_get_null; } break; case 'C': p++; e->hparam.s = p; /* foreground */ switch(*p) { case 'x': case 's': case 'r': case 'g': case 'y': case 'b': case 'p': case 'c': case 'w': case 'S': case 'R': case 'G': case 'Y': case 'B': case 'P': case 'C': case 'W': break; default: e->itf = xl_get_empty; goto error; } p++; /* background */ switch(*p) { case 'x': case 's': case 'r': case 'g': case 'y': case 'b': case 'p': case 'c': case 'w': break; default: e->itf = xl_get_empty; goto error; } /* end */ e->hparam.len = 2; e->itf = xl_get_color; break; case 'd': p++; switch(*p) { case 's': e->itf = xl_get_dset; break; default: e->itf = xl_get_null; } break; case 'f': p++; switch(*p) { case 'u': e->itf = xl_get_from; break; case 't': e->itf = xl_get_from_tag; break; default: e->itf = xl_get_null; } break; case 'H': p++; e->itf = xl_get_host; switch(*p) { case 'n': e->hindex = XL_HOST_NAME; break; case 'd': e->hindex = XL_HOST_DOMAIN; break; case 'f': e->hindex = XL_HOST_FULL; break; case 'i': e->hindex = XL_HOST_IPADDR; break; default: e->hindex = XL_HOST_NULL; break; } break; case 'm': p++; switch(*p) { case 'b': e->itf = xl_get_msg_buf; break; case 'f': e->itf = xl_get_flags; break; case 'i': e->itf = xl_get_msgid; e->hindex = 10; break; case 'l': e->itf = xl_get_msg_len; break; case 'x': e->itf = xl_get_msgid; e->hindex = 16; break; default: e->itf = xl_get_null; } break; case 'n': p++; switch(*p) { case 'h': e->itf = xl_get_nexthop; break; default: e->itf = xl_get_null; } break; case 'p': p++; switch(*p) { case 'p': e->itf = xl_get_pid; e->hindex = 10; break; case 'x': e->itf = xl_get_pid; e->hindex = 16; break; default: e->itf = xl_get_null; } break; case 'r': p++; switch(*p) { case 'm': e->itf = xl_get_method; break; case 'u': e->itf = xl_get_ruri; break; case 's': e->itf = xl_get_status; break; case 'r': e->itf = xl_get_reason; break; case 't': e->itf = xl_get_refer_to; break; default: e->itf = xl_get_null; } break; case 'R': p++; switch(*p) { case 'i': e->itf = xl_get_rcvip; break; case 'p': e->itf = xl_get_rcvport; break; default: e->itf = xl_get_null; } break; case 's': p++; switch(*p) { case 'i': e->itf = xl_get_srcip; break; case 'p': e->itf = xl_get_srcport; break; default: e->itf = xl_get_null; } break; case 't': p++; switch(*p) { case 'u': e->itf = xl_get_to; break; case 't': e->itf = xl_get_to_tag; break; default: e->itf = xl_get_null; } break; case 'T': p++; switch(*p) { case 's': e->itf = xl_get_times; e->hindex = 10; break; case 'f': e->itf = xl_get_timef; break; case 'x': e->itf = xl_get_times; e->hindex = 16; break; default: e->itf = xl_get_null; } break; case 'u': p++; switch(*p) { case 'a': e->itf = xl_get_useragent; break; case 'q': e->itf = xl_get_unique; break; default: e->itf = xl_get_null; } break; case '{': p++; /* we expect a letter */ if((*p < 'A' || *p > 'Z') && (*p < 'a' || *p > 'z')) { LOG(L_ERR, "xprint: xl_parse_format: error parsing format" " [%s] pos [%d]\n", s, (int)(p-s)); goto error; } e->hparam.s = p; while(*p && *p!='}' && *p!='[') p++; if(*p == '\0') { LOG(L_ERR, "xprint: xl_parse_format: error parsing format" " [%s] expecting '}' after position [%d]\n", s, (int)(e->hparam.s-s)); goto error; } e->hparam.len = p - e->hparam.s; /* check if we have index */ if(*p == '[') { p++; if(*p=='-') { p++; if(*p!='1') { LOG(L_ERR, "xprint: xl_parse_format: error" " parsing format [%s] -- only -1 is accepted" " as a negative index\n", s); goto error; } e->hindex = XLOG_PRINT_LAST; p++; } else if (*p=='*') { e->hindex = XLOG_PRINT_ALL; p++; } else { while(*p>='0' && *p<='9') { e->hindex = e->hindex * 10 + *p - '0'; p++; } } if(*p != ']') { LOG(L_ERR, "xprint: xl_parse_format: error parsing format" " [%s] expecting ']' after position [%d]\n", s, (int)(e->hparam.s - s + e->hparam.len)); goto error; } p++; } if(*p != '}') { LOG(L_ERR, "xprint: xl_parse_format: error parsing format" " [%s] expecting '}' after position [%d]!\n", s, (int)(e->hparam.s-s)); goto error; } DBG("xprint: xl_parse_format: header name [%.*s] index [%d]\n", e->hparam.len, e->hparam.s, e->hindex); /* optimize for known headers -- fake header name */ c = e->hparam.s[e->hparam.len]; e->hparam.s[e->hparam.len] = ':'; e->hparam.len++; /* ugly hack for compact header names -- !!fake length!! * -- parse_hname2 expects name buffer length >= 4 */ if (parse_hname2(e->hparam.s, e->hparam.s + ((e->hparam.len<4)?4:e->hparam.len), &hdr)==0) { LOG(L_ERR,"xprint: xl_parse_format: strange error\n"); goto error; } e->hparam.len--; e->hparam.s[e->hparam.len] = c; if (hdr.type!=HDR_OTHER_T && hdr.type!=HDR_ERROR_T) { LOG(L_INFO,"INFO:xprint: xl_parse_format: using " "hdr type (%d) instead of <%.*s>\n", hdr.type, e->hparam.len, e->hparam.s); e->hparam.len = hdr.type; e->hparam.s = NULL; } e->itf = xl_get_header; break; case '<': p++; /* we expect a letter */ if((*p < 'A' || *p > 'Z') && (*p < 'a' || *p > 'z')) { LOG(L_ERR, "xprint: xl_parse_format: error parsing format" " [%s] pos [%d]\n", s, (int)(p-s)); goto error; } e->hparam.s = p; while(*p && *p!='>' && *p!='[') p++; if(*p == '\0') { LOG(L_ERR, "xprint: xl_parse_format: error parsing format" " [%s] expecting '>' after position [%d]\n", s, (int)(e->hparam.s-s)); goto error; } e->hparam.len = p - e->hparam.s; /* check if we have index */ if(*p == '[') { p++; if(*p=='-') { p++; if(*p!='1') { LOG(L_ERR, "xprint: xl_parse_format: error" " parsing format [%s] -- only -1 is accepted" " as a negative index\n", s); goto error; } e->hindex = -1; p++; } else { while(*p>='0' && *p<='9') { e->hindex = e->hindex * 10 + *p - '0'; p++; } } if(*p != ']') { LOG(L_ERR, "xprint: xl_parse_format: error parsing format" " [%s] expecting ']' after position [%d]\n", s, (int)(e->hparam.s - s + e->hparam.len)); goto error; } p++; } if(*p != '>') { LOG(L_ERR, "xprint: xl_parse_format: error parsing format" " [%s] expecting '>' after position [%d]!\n", s, (int)(e->hparam.s-s)); goto error; } DBG("xprint: xl_parse_format: AVP [%.*s] index [%d]\n", e->hparam.len, e->hparam.s, e->hindex); e->itf = xl_get_avp; break; case '$': p++; name.s=p; while ( (*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9') || (*p=='_') || (*p=='+') || (*p=='-') || (*p=='[') || (*p==']') || (*p=='.') ) p++; name.len=p-name.s; p--; if (parse_avp_name(&name, &avp_flags, &avp_name, &avp_index) < 0) { ERR("error while parsing AVP name\n"); goto error; } e->itf = xl_get_avp; e->hflags=avp_flags; e->hparam.s=name.s; e->hparam.len=name.len; e->hindex=avp_index; DBG("flags %x name %.*s index %d\n", avp_flags, avp_name.s.len, avp_name.s.s, avp_index); break; case '@': /* fill select structure and call resolve_select */ DBG("xprint: xl_parse_format: @\n"); if (shm) n=shm_parse_select(&p, &sel); else n=parse_select(&p, &sel); if (n<0) { ERR("xprint: xl_parse_format: parse_select returned error\n"); goto error; } e->itf = xl_get_select; e->hparam.s = (char*)sel; e->free_f = (shm) ? xl_shm_free_select : xl_free_select; p--; break; case '%': e->itf = xl_get_percent; break; case ' ': /* enables spaceless terminating of avp, e.g. "blah%$avp% text goes on" */ case '|': e->itf = xl_get_empty; break; case '[': range = &e->hindex; e->itf = xl_get_range; while (1) { p++; if (((*p) >= '0') && ((*p) <= '9')) { (*range) *= 10; (*range) += (*p) - '0'; } else if ((*p) == '-') { if (range == &e->hindex) { range = &e->hflags; } else { ERR("xprint: xl_parse_format: syntax error in the range specification\n"); goto error; } } else if ((*p) == ']') { if (range == &e->hindex) { /* no range, only a single number */ e->hflags = e->hindex; } else if (e->hflags == 0) { /* only the left side is defined */ e->hflags = -1; } else if (e->hindex > e->hflags) { ERR("xprint: xl_parse_format: syntax error in the range specification\n"); goto error; } break; } else { ERR("xprint: xl_parse_format: syntax error in the range specification\n"); goto error; } } break; default: e->itf = xl_get_null; } cont: if(*p == '\0') break; p++; } DBG("XLOG: xl_parse_format: format parsed OK: [%d] items\n", n); return 0; error: _xl_elog_free_all(*el, shm); *el = NULL; return -1; }
int add_avp_galias_str(char *alias_definition) { int_str avp_name; char *s; str name; str alias; int type; s = alias_definition; while(*s && isspace((int)*s)) s++; while (*s) { /* parse alias name */ alias.s = s; while(*s && *s!=';' && !isspace((int)*s) && *s!='=') s++; if (alias.s==s || *s==0 || *s==';') goto parse_error; alias.len = s-alias.s; while(*s && isspace((int)*s)) s++; /* equal sign */ if (*s!='=') goto parse_error; s++; while(*s && isspace((int)*s)) s++; /* avp name */ name.s = s; while(*s && *s!=';' && !isspace((int)*s)) s++; if (name.s==s) goto parse_error; name.len = s-name.s; while(*s && isspace((int)*s)) s++; /* check end */ if (*s!=0 && *s!=';') goto parse_error; if (*s==';') { for( s++ ; *s && isspace((int)*s) ; s++ ); if (*s==0) goto parse_error; } if (parse_avp_name( &name, &type, &avp_name)!=0) { LM_ERR("<%.*s> not a valid AVP name\n", name.len, name.s); goto error; } if (add_avp_galias( &alias, type, avp_name)!=0) { LM_ERR("add global alias failed\n"); goto error; } } /*end while*/ return 0; parse_error: LM_ERR("parse error in <%s> around pos %ld\n", alias_definition, (long)(s-alias_definition)); error: return -1; }