/* * Parse comma separated list of methods pointed by _body and assign their * enum bits to _methods. Returns 1 on success and 0 on failure. */ int parse_methods(str* _body, unsigned int* _methods) { str next; unsigned int method; method=0; /* fixes silly gcc 4.x warning */ if (!_body || !_methods) { LOG(L_ERR, "parse_methods: Invalid parameter value\n"); return 0; } next.len = _body->len; next.s = _body->s; trim_leading(&next); if (next.len == 0) { LOG(L_ERR, "ERROR: parse_methods: Empty body\n"); return 0; } *_methods = 0; while (1) { if (parse_method(&next, &method)) { *_methods |= method; } else { LOG(L_ERR, "ERROR: parse_methods: Invalid method\n"); return 0; } trim_leading(&next); if (next.len) { if (next.s[0] == ',') { next.len--; next.s++; trim_leading(&next); if (next.len == 0) { LOG(L_ERR, "ERROR: parse_methods: Method expected\n"); return 0; } } else { LOG(L_ERR, "ERROR: parse_methods: Comma expected\n"); return 0; } } else { break; } } return 1; }
static inline int contact_parser(char* _s, int _l, contact_body_t* _c) { str tmp; tmp.s = _s; tmp.len = _l; trim_leading(&tmp); if (tmp.len == 0) { LM_ERR("empty body\n"); return -1; } if (tmp.s[0] == '*') { _c->star = 1; if (tmp.len!=1) { LM_ERR("invalid START Contact header (more than START only)\n"); return -2; } } else { if (parse_contacts(&tmp, &(_c->contacts)) < 0) { LM_ERR("failed to parse contacts\n"); return -3; } } return 0; }
static inline int contact_parser(char* _s, int _l, contact_body_t* _c) { str tmp; tmp.s = _s; tmp.len = _l; trim_leading(&tmp); if (tmp.len == 0) { LOG(L_ERR, "contact_parser(): Empty body\n"); return -1; } if (tmp.s[0] == '*') { _c->star = 1; } else { if (parse_contacts(&tmp, &(_c->contacts)) < 0) { LOG(L_ERR, "contact_parser(): Error while parsing contacts\n"); return -2; } } return 0; }
void xhttp_rpc_get_next_arg(rpc_ctx_t* ctx, str *arg) { int i; trim_leading(&ctx->arg2scan); if (ctx->arg2scan.len<=0) { *arg = XHTTP_RPC_NULL_ARG; return; } if (ctx->arg2scan.len==1 && ctx->arg2scan.s[0]=='\0') { *arg = XHTTP_RPC_NULL_ARG; return; } else { *arg = ctx->arg2scan; for(i=1; i<arg->len-1; i++) { if(arg->s[i]==' '||arg->s[i]=='\t'|| arg->s[i]=='\r'||arg->s[i]=='\n') break; } arg->len = i; arg->s[i] = '\0'; i++; ctx->arg2scan.s += i; ctx->arg2scan.len -= i; } return; }
/* * Parse comma separated list of methods pointed by _body and assign their * enum bits to _methods. Returns 0 on success and -1 on failure. */ int parse_methods(str* _body, unsigned int* _methods) { str next; char *p; char *p0; unsigned int method; if (!_body || !_methods) { LM_ERR("invalid parameter value\n"); return -1; } next.len = _body->len; next.s = _body->s; trim_leading(&next); *_methods = 0; if (next.len == 0) { goto done; } method = 0; p = next.s; while (p<next.s+next.len) { if((p0=parse_method(p, next.s+next.len, &method))!=NULL) { *_methods |= method; p = p0; } else { LM_ERR("invalid method [%.*s]\n", next.len, next.s); return -1; } while(p<next.s+next.len && (*p==' ' || *p=='\t' || *p=='\r' || *p=='\n')) p++; if(p>=next.s+next.len || *p == '\0') goto done; if (*p == ',') { p++; while(p<next.s+next.len && (*p==' ' || *p=='\t' || *p=='\r' || *p=='\n')) p++; if(p>=next.s+next.len) goto done; } else { LM_ERR("comma expected\n"); return -1; } } done: LM_DBG("methods 0x%X\n", *_methods); return 0; }
int read_float(FILE *f, char *config_path, float *result) { /* * Reads the given float from config. * * Returns -1 if the value could not be found, 0 on success * and a positive integer on failure. */ int success; uint8_t temp; success = seek_definition(f, config_path); if (success != 0) return success; temp = fgetc(f); if (temp != 1) return 1; temp = fgetc(f); while (fgetc(f) != 0); if (temp == 2) { // Convert integer to float int32_t int_value; fread(&int_value, 4, 1, f); *result = (float)int_value; } else if (temp == 0) { // Try to parse "rad X" strings char string_value[512]; char *endptr; long fp; fp = ftell(f); if (fgets(string_value, sizeof(string_value), f) == NULL) return 2; fseek(f, fp + strlen(string_value) + 1, SEEK_SET); trim_leading(string_value, sizeof(string_value)); lower_case(string_value); if (strncmp(string_value, "rad ", 4) != 0) return 3; *result = strtof(string_value + 4, &endptr); if (strlen(endptr) > 0) return 4; *result *= RAD2DEG; } else { fread(result, 4, 1, f); } return 0; }
/* * We support Digest authentication only * * Returns: * 0 - if everything is OK * -1 - Error while parsing * 1 - Unknown scheme */ int parse_digest_cred(str* _s, dig_cred_t* _c) { str tmp; /* Make a temporary copy, we are * going to modify it */ tmp.s = _s->s; tmp.len = _s->len; /* Remove any leading spaces, tabs, \r and \n */ trim_leading(&tmp); /* Check the string length */ if (tmp.len < (DIG_LEN + 1)) return 1; /* Too short, unknown scheme */ /* Now test, if it is digest scheme, since it is the only * scheme we are able to parse here */ if (!strncasecmp(tmp.s, DIGEST_SCHEME, DIG_LEN) && ((tmp.s[DIG_LEN] == ' ') || /* Test for one of LWS chars */ (tmp.s[DIG_LEN] == '\r') || (tmp.s[DIG_LEN] == 'n') || (tmp.s[DIG_LEN] == '\t') || (tmp.s[DIG_LEN] == ','))) { /* Scheme is Digest */ tmp.s += DIG_LEN + 1; tmp.len -= DIG_LEN + 1; /* Again, skip all white-spaces */ trim_leading(&tmp); /* And parse digest parameters */ if (parse_digest_params(&tmp, _c) < 0) { return -2; /* We must not return -1 in this function ! */ } else { return 0; } } else { return 1; /* Unknown scheme */ } }
/* * Parse a digest parameter */ static inline int parse_digest_param(str* _s, dig_cred_t* _c) { dig_par_t t; str* ptr; str dummy; /* Get type of the parameter */ if (parse_param_name(_s, &t) < 0) { return -1; } _s->s++; /* skip = */ _s->len--; /* Find the begining of body */ trim_leading(_s); if (_s->len == 0) { return -2; } /* Decide in which attribute the * body content will be stored */ switch(t) { case PAR_USERNAME: ptr = &_c->username.whole; break; case PAR_REALM: ptr = &_c->realm; break; case PAR_NONCE: ptr = &_c->nonce; break; case PAR_URI: ptr = &_c->uri; break; case PAR_RESPONSE: ptr = &_c->response; break; case PAR_CNONCE: ptr = &_c->cnonce; break; case PAR_OPAQUE: ptr = &_c->opaque; break; case PAR_QOP: ptr = &_c->qop.qop_str; break; case PAR_NC: ptr = &_c->nc; break; case PAR_ALGORITHM: ptr = &_c->alg.alg_str; break; case PAR_OTHER: ptr = &dummy; break; default: ptr = &dummy; break; } /* If the first character is quote, it is * a quoted string, otherwise it is a token */ if (_s->s[0] == '\"') { if (parse_quoted(_s, ptr) < 0) { return -3; } } else { if (parse_token(_s, ptr) < 0) { return -4; } } return 0; }
/** initializes a net structure from a string. * @param dst - net structure that will be filled * @param s - string of the form "ip", "ip/mask_len" or "ip/ip_mak". * @return -1 on error, 0 on succes */ int mk_net_str(struct net* dst, str* s) { struct ip_addr* t; char* p; struct ip_addr ip; str addr; str mask; unsigned int bitlen; /* test for ip only */ t = str2ip(s); if (unlikely(t == 0)) t = str2ip6(s); if (likely(t)) return mk_net_bitlen(dst, t, t->len*8); /* not a simple ip, maybe an ip/netmask pair */ p = q_memchr(s->s, '/', s->len); if (likely(p)) { addr.s = s->s; addr.len = (int)(long)(p - s->s); mask.s = p + 1; mask.len = s->len - (addr.len + 1); /* allow '/' enclosed by whitespace */ trim_trailing(&addr); trim_leading(&mask); t = str2ip(&addr); if (likely(t)) { /* it can be a number */ if (str2int(&mask, &bitlen) == 0) return mk_net_bitlen(dst, t, bitlen); ip = *t; t = str2ip(&mask); if (likely(t)) return mk_net(dst, &ip, t); /* error */ return -1; } else { t = str2ip6(&addr); if (likely(t)) { /* it can be a number */ if (str2int(&mask, &bitlen) == 0) return mk_net_bitlen(dst, t, bitlen); ip = *t; t = str2ip6(&mask); if (likely(t)) return mk_net(dst, &ip, t); /* error */ return -1; } } } return -1; }
int seek_definition(FILE *f, char *config_path) { /* * Finds the definition of the given value, even if it is defined in a * parent class. * * Returns 0 on success, a positive integer on failure. */ int success; // Try the direct way first fseek(f, 16, SEEK_SET); success = seek_config_path(f, config_path); if (success >= 0) return success; // No containing class if (strchr(config_path, '>') == NULL) return 1; // Try to find the definition int i; char containing[2048]; char parent[2048]; char value[2048]; strncpy(containing, config_path, sizeof(containing)); *(strrchr(containing, '>') - 1) = 0; for (i = strlen(containing) - 1; i >= 0 && containing[i] == ' '; i--) containing[i] = 0; fseek(f, 16, SEEK_SET); success = seek_config_path(f, containing); // Containing class doesn't even exist if (success < 0) return success; // Find parent of the containing class success = find_parent(f, containing, parent, sizeof(parent)); if (success) { return success; } strncpy(value, strrchr(config_path, '>') + 1, sizeof(value)); trim_leading(value, sizeof(value)); strcat(parent, " >> "); strcat(parent, value); return seek_definition(f, parent); }
static int check_ftag(struct sip_msg* msg, str* uri) { param_hooks_t hooks; param_t* params; char* semi; struct to_body* from; str t; t = *uri; params = 0; semi = q_memchr(t.s, ';', t.len); if (!semi) { DBG("No ftag parameter found\n"); return -1; } t.len -= semi - uri->s + 1; t.s = semi + 1; trim_leading(&t); if (parse_params(&t, CLASS_URI, &hooks, ¶ms) < 0) { ERR("Error while parsing parameters\n"); return -1; } if (!hooks.uri.ftag) { DBG("No ftag parameter found\n"); goto err; } from = get_from(msg); if (!from || !from->tag_value.len || !from->tag_value.s) { DBG("No from tag parameter found\n"); goto err; } if (from->tag_value.len == hooks.uri.ftag->body.len && !strncmp(from->tag_value.s, hooks.uri.ftag->body.s, hooks.uri.ftag->body.len)) { DBG("Route ftag and From tag are same\n"); free_params(params); return 0; } else { DBG("Route ftag and From tag are NOT same\n"); free_params(params); return 1; } err: if (params) free_params(params); return -1; }
static inline void parse_word(str* _s, str* word) { trim_leading(_s); word->len = 0; word->s = _s->s; for(; _s->len > 0; _s->len--, _s->s++) { switch(*(_s->s)) { case ' ': case '\t': case '\r': case '\n': return; default: word->len++; break; } } }
int etag_parser(char *_s, int _l, str *_e) { char* end; _e->s = _s; _e->len = _l; trim_leading(_e); if (_e->len == 0) { LOG(L_ERR, "etag_parser(): Empty body\n"); return -1; } end = skip_token(_e->s, _e->len); _e->len = end - _e->s; return 0; }
/* * Get CSeq number * Does not parse headers !! */ static inline int get_cseq_value(struct sip_msg* _m, unsigned int* _cs) { str num; if (_m->cseq == 0) { LOG(L_ERR, "get_cseq_value(): CSeq header not found\n"); return -1; } num.s = get_cseq(_m)->number.s; num.len = get_cseq(_m)->number.len; trim_leading(&num); if (str2int(&num, _cs) < 0) { LOG(L_ERR, "get_cseq_value(): Error while converting cseq number\n"); return -2; } return 0; }
int parse_param_name(str* _s, dig_par_t* _type) { register char* p; register int val; char* end; end = _s->s + _s->len; p = _s->s; val = READ(p); if (_s->len < 4) { goto other; } switch(LOWER_DWORD(val)) { FIRST_QUATERNIONS; default: PARSE_SHORT; goto other; } end: _s->len -= p - _s->s; _s->s = p; trim_leading(_s); if (_s->s[0] == '=') { return 0; } other: p = q_memchr(p, '=', end - p); if (!p) { return -1; /* Parse error */ } else { *_type = PAR_OTHER; _s->len -= p - _s->s; _s->s = p; return 0; } }
/* * Parse Digest credentials parameter, one by one */ static inline int parse_digest_params(str* _s, dig_cred_t* _c) { char* comma; do { /* Parse the first parameter */ if (parse_digest_param(_s, _c) < 0) { return -1; } /* Try to find the next parameter */ comma = q_memchr(_s->s, ',', _s->len); if (comma) { /* Yes, there is another, * remove any leading white-spaces * and let _s point to the next * parameter name */ _s->len -= comma - _s->s + 1; _s->s = comma + 1; trim_leading(_s); } } while(comma); /* Repeat while there are next parameters */ /* Parse QOP body if the parameter was present */ if (_c->qop.qop_str.s != 0) { parse_qop(&_c->qop); } /* Parse algorithm body if the parameter was present */ if (_c->alg.alg_str.s != 0) { parse_algorithm(&_c->alg); } if (_c->username.whole.s != 0) { parse_username(&_c->username); } return 0; }
int str_find_token(str *text, str *result, char delim) { int i; if(text==NULL || result==NULL) return -1; if(text->s[0] == delim) { text->s += 1; text->len -= 1; } trim_leading(text); result->s = text->s; result->len = 0; for (i=0; i<text->len; i++) { if(result->s[i]==delim || result->s[i]=='\0' || result->s[i]=='\r' || result->s[i]=='\n') return 0; result->len++; } return 0; }
static int scan_int(const char **in, int base, int width, int *res) { int neg = 0; int dst = 0; int ch; int i; int not_empty = 0; if (EOF == (ch = trim_leading(in))) { return EOF; } if ((ch == '-') || (ch == '+')) { neg = (ch == '-'); scanchar(in); } else { dst = 0; } for (i = 0; (ch = (int) scanchar(in)) != EOF; i++) { if (!(base == 10 ? isdigit(ch) : isxdigit(ch)) || (0 == width)) { unscanchar(in, ch); /*end conversion*/ break; } not_empty = 1; dst = base * dst + ch_to_digit(ch, base); } if (!not_empty) { return -1; } if (neg) dst = -dst; *res = dst; return 0; }
/* * Parse Route and Record-Route header fields */ int parse_rr(struct hdr_field* _h) { rr_t* r, *last; str s; param_hooks_t hooks; if (!_h) { LOG(L_ERR, "parse_rr(): Invalid parameter value\n"); return -1; } if (_h->parsed) { /* Already parsed, return */ return 0; } /* Make a temporary copy of the string pointer */ s.s = _h->body.s; s.len = _h->body.len; trim_leading(&s); last = 0; while(1) { /* Allocate and clear rr stucture */ r = (rr_t*)pkg_malloc(sizeof(rr_t)); if (!r) { LOG(L_ERR, "parse_rr(): No memory left\n"); goto error; } memset(r, 0, sizeof(rr_t)); /* Parse name-addr part of the header */ if (parse_nameaddr(&s, &r->nameaddr) < 0) { LOG(L_ERR, "parse_rr(): Error while parsing name-addr\n"); goto error; } r->len = r->nameaddr.len; /* Shift just behind the closing > */ s.s = r->nameaddr.name.s + r->nameaddr.len; /* Point just behind > */ s.len -= r->nameaddr.len; trim_leading(&s); /* Skip any whitechars */ /* Nothing left, finish */ if (s.len == 0) goto ok; if (s.s[0] == ';') { /* Contact parameter found */ s.s++; s.len--; trim_leading(&s); if (s.len == 0) { LOG(L_ERR, "parse_rr(): Error while parsing params\n"); goto error; } /* Parse all parameters */ if (parse_params(&s, CLASS_ANY, &hooks, &r->params) < 0) { LOG(L_ERR, "parse_rr(): Error while parsing params\n"); goto error; } r->len = r->params->name.s + r->params->len - r->nameaddr.name.s; /* Copy hooks */ /*r->r2 = hooks.rr.r2; */ trim_leading(&s); if (s.len == 0) goto ok; } if (s.s[0] != ',') { LOG(L_ERR, "parse_rr(): Invalid character '%c', comma expected\n", s.s[0]); goto error; } /* Next character is comma or end of header*/ s.s++; s.len--; trim_leading(&s); if (s.len == 0) { LOG(L_ERR, "parse_rr(): Text after comma missing\n"); goto error; } /* Append the structure as last parameter of the linked list */ if (!_h->parsed) _h->parsed = (void*)r; if (last) last->next = r; last = r; } error: if (r) pkg_free(r); free_rr((rr_t**)&_h->parsed); /* Free any contacts created so far */ return -1; ok: if (!_h->parsed) _h->parsed = (void*)r; if (last) last->next = r; return 0; }
int event_parser(char* s, int len, event_t* e) { int i; str tmp; char* end; param_hooks_t* phooks = NULL; enum pclass pclass = CLASS_ANY; if (e == NULL) { ERR("event_parser: Invalid parameter value\n"); return -1; } tmp.s = s; tmp.len = len; trim_leading(&tmp); if (tmp.len == 0) { LOG(L_ERR, "event_parser: Empty body\n"); return -1; } e->name.s = tmp.s; end = skip_token(tmp.s, tmp.len); e->name.len = end - tmp.s; e->type = EVENT_OTHER; for(i = 0; events[i].name.len; i++) { if (e->name.len == events[i].name.len && !strncasecmp(e->name.s, events[i].name.s, e->name.len)) { e->type = events[i].type; break; } } tmp.len -= end - tmp.s; tmp.s = end; trim_leading(&tmp); e->params.list = NULL; if (tmp.len && (tmp.s[0] == ';')) { /* Shift the semicolon and skip any leading whitespace, this is needed * for parse_params to work correctly. */ tmp.s++; tmp.len--; trim_leading(&tmp); if (!tmp.len) return 0; /* We have parameters to parse */ if (e->type == EVENT_DIALOG) { pclass = CLASS_EVENT_DIALOG; phooks = (param_hooks_t*)&e->params.hooks; } if (parse_params(&tmp, pclass, phooks, &e->params.list) < 0) { ERR("event_parser: Error while parsing parameters parameters\n"); return -1; } } return 0; }
int event_parser(char* _s, int _l, event_t* _e) { str tmp; char* end; param_hooks_t phooks; tmp.s = _s; tmp.len = _l; trim_leading(&tmp); if (tmp.len == 0) { LM_ERR("empty body\n"); goto parse_error; } _e->text.s = tmp.s; end = skip_token(tmp.s, tmp.len); _e->text.len = end - tmp.s; if ((_e->text.len == PRES_STR_LEN) && !strncasecmp(PRES_STR, tmp.s, _e->text.len)) { _e->parsed = EVENT_PRESENCE; } else if ((_e->text.len == PRES_XCAP_CHANGE_STR_LEN) && !strncasecmp(PRES_XCAP_CHANGE_STR, tmp.s, _e->text.len)) { _e->parsed = EVENT_XCAP_CHANGE; } else if ((_e->text.len == PRES_WINFO_STR_LEN) && !strncasecmp(PRES_WINFO_STR, tmp.s, _e->text.len)) { _e->parsed = EVENT_PRESENCE_WINFO; } else if ((_e->text.len == PRES_SIP_PROFILE_STR_LEN) && !strncasecmp(PRES_SIP_PROFILE_STR, tmp.s, _e->text.len)) { _e->parsed = EVENT_SIP_PROFILE; } else if ((_e->text.len == DIALOG_STR_LEN) && !strncasecmp(DIALOG_STR, tmp.s, _e->text.len)) { _e->parsed = EVENT_DIALOG; } else if ((_e->text.len == MWI_STR_LEN) && !strncasecmp(MWI_STR, tmp.s, _e->text.len)) { _e->parsed = EVENT_MWI; } else { _e->parsed = EVENT_OTHER; } if( (_e->text.len < tmp.len) && (*end)== ';') { str params_str; params_str.s = end+1; params_str.len = tmp.len- _e->text.len- 1; if (parse_params(¶ms_str, CLASS_ANY, &phooks, &_e->params)<0) goto parse_error; if(_e->parsed == EVENT_DIALOG && _e->params!= NULL && _e->params->name.len== 3 && strncasecmp(_e->params->name.s, "sla", 3)== 0 ) { _e->parsed = EVENT_DIALOG_SLA; } } else { _e->params= NULL; } return 0; parse_error: return -1; }
/*! \brief * Parse Route or Record-Route body */ static inline int do_parse_rr_body(char *buf, int len, rr_t **head) { rr_t* r, *last; str s; param_hooks_t hooks; /* Make a temporary copy of the string pointer */ if(buf==0 || len<=0) { DBG("parse_rr_body(): No body for record-route\n"); *head = 0; return -2; } s.s = buf; s.len = len; trim_leading(&s); last = 0; while(1) { /* Allocate and clear rr structure */ r = (rr_t*)pkg_malloc(sizeof(rr_t)); if (!r) { LOG(L_ERR, "parse_rr(): No memory left\n"); goto error; } memset(r, 0, sizeof(rr_t)); /* Parse name-addr part of the header */ if (parse_nameaddr(&s, &r->nameaddr) < 0) { LOG(L_ERR, "parse_rr(): Error while parsing name-addr (%.*s)\n", s.len, ZSW(s.s)); goto error; } r->len = r->nameaddr.len; /* Shift just behind the closing > */ s.s = r->nameaddr.name.s + r->nameaddr.len; /* Point just behind > */ s.len -= r->nameaddr.len; trim_leading(&s); /* Skip any white-chars */ if (s.len == 0) goto ok; /* Nothing left, finish */ if (s.s[0] == ';') { /* Route parameter found */ s.s++; s.len--; trim_leading(&s); if (s.len == 0) { LOG(L_ERR, "parse_rr(): Error while parsing params\n"); goto error; } /* Parse all parameters */ if (parse_params(&s, CLASS_ANY, &hooks, &r->params) < 0) { LOG(L_ERR, "parse_rr(): Error while parsing params\n"); goto error; } r->len = r->params->name.s + r->params->len - r->nameaddr.name.s; /* Copy hooks */ /*r->r2 = hooks.rr.r2; */ trim_leading(&s); if (s.len == 0) goto ok; } if (s.s[0] != ',') { LOG(L_ERR, "parse_rr(): Invalid character '%c', comma expected\n", s.s[0]); goto error; } /* Next character is comma or end of header*/ s.s++; s.len--; trim_leading(&s); if (s.len == 0) { LOG(L_ERR, "parse_rr(): Text after comma missing\n"); goto error; } /* Append the structure as last parameter of the linked list */ if (!*head) *head = r; if (last) last->next = r; last = r; } error: if (r) free_rr(&r); free_rr(head); /* Free any contacts created so far */ return -1; ok: if (!*head) *head = r; if (last) last->next = r; return 0; }
/* * Parse parameters * _s is string containing parameters, it will be updated to point behind the parameters * _c is class of parameters * _h is pointer to structure that will be filled with pointer to well known parameters * linked list of parsed parameters will be stored in * the variable _p is pointing to * The function returns 0 on success and negative number * on an error */ int parse_params(str* _s, pclass_t _c, param_hooks_t* _h, param_t** _p) { param_t* t; if (!_s || !_h || !_p) { LOG(L_ERR, "parse_params(): Invalid parameter value\n"); return -1; } memset(_h, 0, sizeof(param_hooks_t)); *_p = 0; if (!_s->s) { /* no parameters at all -- we're done */ DBG("DEBUG: parse_params: empty uri params, skipping\n"); return 0; } while(1) { t = (param_t*)pkg_malloc(sizeof(param_t)); if (t == 0) { LOG(L_ERR, "parse_params(): No memory left\n"); goto error; } memset(t, 0, sizeof(param_t)); parse_param_name(_s, _c, _h, t); trim_leading(_s); if (_s->len == 0) { /* The last parameter without body */ goto ok; } if (_s->s[0] == '=') { _s->s++; _s->len--; trim_leading(_s); if (_s->len == 0) { LOG(L_ERR, "parse_params(): Body missing\n"); goto error; } if (parse_param_body(_s, t) < 0) { LOG(L_ERR, "parse_params(): Error while parsing param body\n"); goto error; } t->len = _s->s - t->name.s; trim_leading(_s); if (_s->len == 0) { goto ok; } } else { t->len = _s->s - t->name.s; } if (_s->s[0] == ',') goto ok; /* To be able to parse header parameters */ if (_s->s[0] == '>') goto ok; /* To be able to parse URI parameters */ if (_s->s[0] != ';') { LOG(L_ERR, "parse_params(): Invalid character, ; expected\n"); goto error; } _s->s++; _s->len--; trim_leading(_s); if (_s->len == 0) { LOG(L_ERR, "parse_params(): Param name missing after ;\n"); goto error; } t->next = *_p; *_p = t; } error: if (t) pkg_free(t); free_params(*_p); return -2; ok: t->next = *_p; *_p = t; return 0; }
static int attr_hdr_body2attrs(struct sip_msg* m, char* header_, char* prefix_) { char name_buf[50]; str *prefix = (str*) prefix_; struct hdr_name *header = (void*) header_; struct hdr_field *hf; str s, name, val; int_str name2, val2; int val_type, arr; if (header->kind == HDR_STR) { if (parse_headers(m, HDR_EOH_F, 0) == -1) { LOG(L_ERR, "ERROR: attr_hdr_body2attrs: Error while parsing message\n"); return -1; } for (hf=m->headers; hf; hf=hf->next) { if ( (header->name.s.len == hf->name.len) && (!strncasecmp(header->name.s.s, hf->name.s, hf->name.len)) ) { break; } } } else { if (parse_headers(m, header->name.n, 0) == -1) { LOG(L_ERR, "ERROR: attr_hdr_body2attrs: Error while parsing message\n"); return -1; } switch (header->name.n) { // HDR_xxx: default: hf = NULL; break; } } if (!hf || !hf->body.len) return 1; // parse body of hf s = hf->body; name_buf[0] = '\0'; while (s.len) { trim_leading(&s); name.s = s.s; while ( s.len && ( (s.s[0] >= 'a' && s.s[0] <= 'z') || (s.s[0] >= 'A' && s.s[0] <= 'Z') || (s.s[0] >= '0' && s.s[0] <= '9') || s.s[0] == '_' || s.s[0] == '-' ) ) { s.s++; s.len--; } if (s.s == name.s) break; name.len = s.s - name.s; trim_leading(&s); if (!s.len) break; if (s.s[0] == '=') { s.s++; s.len--; arr = -1; while (s.len) { trim_leading(&s); val_type = 0; if (!s.len) break; if (s.s[0] == '"') { s.s++; s.len--; val.s = s.s; s.s = q_memchr(s.s, '\"', s.len); if (!s.s) break; val.len = s.s - val.s; val_type = AVP_VAL_STR; s.s++; s.len -= s.s - val.s; } else { int r; val.s = s.s; if (s.s[0] == '+' || s.s[0] == '-') { s.s++; s.len--; } val2.n = 0; r = 0; while (s.len) { if (s.s[0] == header->field_delimiter || (header->array_delimiter && header->array_delimiter == s.s[0])) goto token_end; switch (s.s[0]) { case ' ': case '\t': case '\n': case '\r': goto token_end; } if (!val_type && s.s[0] >= '0' && s.s[0]<= '9') { r++; val2.n *= 10; val2.n += s.s[0] - '0'; // overflow detection ??? } else { val_type = AVP_VAL_STR; } s.s++; s.len--; } token_end: if (r == 0) val_type = AVP_VAL_STR; if (!val_type && val.s[0] == '-') { val2.n = -val2.n; } val.len = s.s - val.s; } trim_leading(&s); if (arr >= 0 || (s.len && header->array_delimiter && header->array_delimiter == s.s[0])) { arr++; if (arr == 100) LOG(L_ERR, "ERROR: avp index out of limit\n"); } if (val.len && arr < 100) { if (prefix != NULL || arr >= 0) { if ((prefix?prefix->len:0)+name.len+1+((arr>=0)?3/*#99*/:0) > sizeof(name_buf)) { if (arr <= 0) LOG(L_ERR, "ERROR: avp name too long\n"); goto cont; } name2.s.len = 0; name2.s.s = name_buf; if (prefix != NULL) { if (name_buf[0] == '\0') { memcpy(&name_buf[0], prefix->s, prefix->len); } name2.s.len += prefix->len; } if (arr <= 0) { memcpy(&name_buf[name2.s.len], name.s, name.len); } name2.s.len += name.len; if (arr >= 0) { name_buf[name2.s.len] = '#'; name2.s.len++; if (arr >= 10) { name_buf[name2.s.len] = '0'+ (arr / 10); name2.s.len++; } name_buf[name2.s.len] = '0'+ (arr % 10); name2.s.len++; } } else { name2.s.s = name.s; name2.s.len = name.len; } if ( ((val_type & AVP_VAL_STR) && (header->val_types & VAL_TYPE_STR)) || ((val_type & AVP_VAL_STR) == 0 && (header->val_types & VAL_TYPE_INT)) ) { if (val_type) { val2.s.s = val.s; val2.s.len = val.len; DBG("DEBUG: attr_hdr_body2attrs: adding avp '%.*s', sval: '%.*s'\n", name2.s.len, (char*) name2.s.s, val.len, val.s); } else { DBG("DEBUG: attr_hdr_body2attrs: adding avp '%.*s', ival: '%d'\n", name2.s.len, (char*) name2.s.s, val2.n); } if ( add_avp(AVP_NAME_STR | val_type, name2, val2)!=0) { LOG(L_ERR, "ERROR: attr_hdr_body2attrs: add_avp failed\n"); return 1; } } } cont: if (s.len && header->array_delimiter && header->array_delimiter == s.s[0]) { s.s++; s.len--; } else { break; } }; } if (s.len && s.s[0] == header->field_delimiter) { s.s++; s.len--; } else { break; } } return 1; }
/*! \brief * Only parse one parameter * Returns: * t: out parameter * -1: on error * 0: success, but expect a next paramter * 1: success and expect no more parameters */ static inline int parse_param2( str *_s, pclass_t _c, param_hooks_t *_h, param_t *t, char separator) { memset(t, 0, sizeof(param_t)); parse_param_name(_s, _c, _h, t, separator); trim_leading(_s); if(_s->len == 0) { /* The last parameter without body */ t->len = t->name.len; goto ok; } if(_s->s[0] == '=') { _s->s++; _s->len--; trim_leading(_s); if(_s->len == 0) { /* Be forgiving and accept parameters with missing value, * we just set the length of parameter body to 0. */ t->body.s = _s->s; t->body.len = 0; } else if(parse_param_body(_s, t, separator) < 0) { LM_ERR("Error while parsing param body\n"); goto error; } t->len = _s->s - t->name.s; trim_leading(_s); if(_s->len == 0) { goto ok; } } else { t->len = t->name.len; } if(_s->s[0] == ',') goto ok; /* To be able to parse header parameters */ if(_s->s[0] == '>') goto ok; /* To be able to parse URI parameters */ if(_s->s[0] != separator) { LM_ERR("Invalid character, %c expected\n", separator); goto error; } _s->s++; _s->len--; trim_leading(_s); if(_s->len == 0) { LM_ERR("Param name missing after %c\n", separator); goto error; } return 0; /* expect more params */ ok: return 1; /* done with parsing for params */ error: return -1; }
/*! * This method is used to parse Privacy HF body, which consist of * comma separated list of priv-values. After parsing, msg->privacy->parsed * contains enum bits of privacy values defined in parse_privacy.h. * \return 0 on success and -1 on failure. */ int parse_privacy(struct sip_msg *msg) { unsigned int val_len, value, values, len; str next; char *p, *beyond; /* maybe the header is already parsed! */ if (msg->privacy && msg->privacy->parsed) return 0; /* parse Privacy HF (there should be only one) */ if (!msg->privacy && (parse_headers(msg, HDR_PRIVACY_F, 0) == -1 || !msg->privacy)) { return -1; } next.len = msg->privacy->body.len; next.s = msg->privacy->body.s; trim_leading(&next); if (next.len == 0) { LM_ERR("no values\n"); return -1; } values = 0; p = next.s; len = next.len; beyond = p + len; while (p < beyond) { if((val_len = parse_priv_value(p, len, &value)) != 0) { values |= value; p = p + val_len; len = len - val_len; } else { LM_ERR("invalid privacy value\n"); return -1; } while(p < beyond && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')) p++; if(p >= beyond) break; if (*p == ';') { p++; while(p < beyond && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')) p++; if(p >= beyond) { LM_ERR("no privacy value after comma\n"); return -1; } } else { LM_ERR("semicolon expected\n"); return -1; } } if ((values & PRIVACY_NONE) && (values ^ PRIVACY_NONE)) { LM_ERR("no other privacy values allowed with 'none'\n"); return -1; } msg->privacy->parsed = (void *)(long)values; return 0; }
int seek_config_path(FILE *f, char *config_path) { /* * Assumes the file pointer f points at the start of a rapified * class body. The config path should be formatted like one used * by the ingame commands (case insensitive): * * CfgExample >> MyClass >> MyValue * * This function then moves the file pointer to the start of the * desired class entry (or class body for classes). * * Returns a positive integer on failure, a 0 on success and -1 * if the given path doesn't exist. */ int i; uint8_t type; uint32_t num_entries; uint32_t fp; char path[2048]; char target[512]; char buffer[512]; // Trim leading spaces strncpy(path, config_path, sizeof(path)); trim_leading(path, sizeof(path)); // Extract first element for (i = 0; i < sizeof(target) - 1; i++) { if (path[i] == 0 || path[i] == '>' || path[i] == ' ') break; } strncpy(target, path, i); target[i] = 0; // Inherited classname while (fgetc(f) != 0); num_entries = read_compressed_int(f); for (i = 0; i < num_entries; i++) { fp = ftell(f); type = fgetc(f); if (type == 0) { // class if (fgets(buffer, sizeof(buffer), f) == NULL) return 1; fseek(f, fp + strlen(buffer) + 2, SEEK_SET); fread(&fp, 4, 1, f); if (stricmp(buffer, target)) continue; fseek(f, fp, SEEK_SET); if (strchr(path, '>') == NULL) return 0; strcpy(path, strchr(config_path, '>') + 2); return seek_config_path(f, path); } else if (type == 1) { // value type = fgetc(f); if (fgets(buffer, sizeof(buffer), f) == NULL) return 1; if (stricmp(buffer, target) == 0) { fseek(f, fp, SEEK_SET); return 0; } fseek(f, fp + strlen(buffer) + 3, SEEK_SET); if (type == 0) while (fgetc(f) != 0); else fseek(f, 4, SEEK_CUR); } else if (type == 2) { // array if (fgets(buffer, sizeof(buffer), f) == NULL) return 1; if (stricmp(buffer, target) == 0) { fseek(f, fp, SEEK_SET); return 0; } fseek(f, fp + strlen(buffer) + 2, SEEK_SET); skip_array(f); } else { // extern & delete statements while (fgetc(f) != 0); } } return -1; }
int preprocess(char *source, FILE *f_target, struct constant *constants) { /* * Writes the contents of source into the target file pointer, while * recursively resolving constants and includes using the includefolder * for finding included files. * * Returns 0 on success, a positive integer on failure. */ extern int current_operation; extern char current_target[2048]; extern char include_stack[MAXINCLUDES][1024]; int line = 0; int i = 0; int j = 0; int level = 0; int level_true = 0; int level_comment = 0; int success; size_t buffsize; char *buffer; char *ptr; char *token; char in_string = 0; char valuebuffer[262144]; char definition[256]; char tmp[2048]; char includepath[2048]; char actualpath[2048]; FILE *f_source; current_operation = OP_PREPROCESS; strcpy(current_target, source); for (i = 0; i < MAXINCLUDES && include_stack[i][0] != 0; i++) { if (strcmp(source, include_stack[i]) == 0) { errorf("Circular dependency detected, printing include stack:\n", source); fprintf(stderr, " !!! %s\n", source); for (j = MAXINCLUDES - 1; j >= 0; j--) { if (include_stack[j][0] == 0) continue; fprintf(stderr, " %s\n", include_stack[j]); } return 1; } } if (i == MAXINCLUDES) { errorf("Too many nested includes.\n"); return 1; } strcpy(include_stack[i], source); f_source = fopen(source, "rb"); if (!f_source) { errorf("Failed to open %s.\n", source); return 1; } // Skip byte order mark if it exists if (fgetc(f_source) == 0xef) fseek(f_source, 3, SEEK_SET); else fseek(f_source, 0, SEEK_SET); // first constant is file name // @todo: what form? strcpy(constants[0].name, "__FILE__"); if (constants[0].value == 0) constants[0].value = (char *)malloc(1024); snprintf(constants[0].value, 1024, "\"%s\"", source); strcpy(constants[1].name, "__LINE__"); strcpy(constants[2].name, "__EXEC"); if (constants[2].value == 0) constants[2].value = (char *)malloc(1); strcpy(constants[3].name, "__EVAL"); if (constants[3].value == 0) constants[3].value = (char *)malloc(1); while (true) { // get line line++; buffsize = LINEBUFFSIZE; buffer = (char *)malloc(buffsize + 1); if (getline(&buffer, &buffsize, f_source) == -1) { free(buffer); break; } // fix Windows line endings if (strlen(buffer) >= 2 && buffer[strlen(buffer) - 2] == '\r') { buffer[strlen(buffer) - 2] = '\n'; buffer[strlen(buffer) - 1] = 0; } // add next lines if line ends with a backslash while (strlen(buffer) >= 2 && buffer[strlen(buffer) - 2] == '\\') { if (strlen(buffer) >= buffsize) { errorf("Line %i exceeds maximum length.\n", line); return 1; } buffsize -= strlen(buffer); ptr = (char *)malloc(buffsize + 1); if (getline(&ptr, &buffsize, f_source) == -1) break; strncpy(strrchr(buffer, '\\'), ptr, buffsize); line++; free(ptr); // fix windows line endings again if (strlen(buffer) >= 2 && buffer[strlen(buffer) - 2] == '\r') { buffer[strlen(buffer) - 2] = '\n'; buffer[strlen(buffer) - 1] = 0; } } // Check for block comment delimiters for (i = 0; i < strlen(buffer); i++) { if (in_string != 0) { if (buffer[i] == in_string && buffer[i-1] != '\\') in_string = 0; else continue; } else { if (level_comment == 0 && (buffer[i] == '"' || buffer[i] == '\'') && (i == 0 || buffer[i-1] != '\\')) in_string = buffer[i]; } if (buffer[i] == '/' && buffer[i+1] == '/') { buffer[i+1] = 0; buffer[i] = '\n'; } else if (buffer[i] == '/' && buffer[i+1] == '*') { level_comment++; buffer[i] = ' '; buffer[i+1] = ' '; } else if (buffer[i] == '*' && buffer[i+1] == '/') { level_comment--; if (level_comment < 0) level_comment = 0; buffer[i] = ' '; buffer[i+1] = ' '; } if (level_comment > 0) { buffer[i] = ' '; continue; } } // trim leading spaces trim_leading(buffer, LINEBUFFSIZE); // skip lines inside untrue ifs if (level > level_true) { if ((strlen(buffer) < 5 || strncmp(buffer, "#else", 5) != 0) && (strlen(buffer) < 6 || strncmp(buffer, "#endif", 6) != 0)) { free(buffer); continue; } } // second constant is line number if (constants[1].value == 0) constants[1].value = (char *)malloc(16); sprintf(constants[1].value, "%i", line - 1); // get the constant name if (strlen(buffer) >= 9 && (strncmp(buffer, "#define", 7) == 0 || strncmp(buffer, "#undef", 6) == 0 || strncmp(buffer, "#ifdef", 6) == 0 || strncmp(buffer, "#ifndef", 7) == 0)) { definition[0] = 0; ptr = buffer + 7; while (*ptr == ' ') ptr++; strncpy(definition, ptr, 256); ptr = definition; while (*ptr != ' ' && *ptr != '(' && *ptr != '\n') ptr++; *ptr = 0; if (strlen(definition) == 0) { errorf("Missing definition in line %i of %s.\n", line, source); return 2; } } // check for preprocessor commands if (level_comment == 0 && strlen(buffer) >= 9 && strncmp(buffer, "#define", 7) == 0) { i = 0; while (strlen(constants[i].name) != 0 && strcmp(constants[i].name, definition) != 0 && i <= MAXCONSTS) i++; if (i == MAXCONSTS) { errorf("Maximum number of %i definitions exceeded in line %i of %s.\n", MAXCONSTS, line, source); return 3; } if (constants[i].name[0] != 0) nwarningf("redefinition-wo-undef", "Constant \"%s\" is being redefined without an #undef in line %i.\n", definition, line); ptr = buffer + strlen(definition) + 8; while (*ptr != ' ' && *ptr != '\t' && *ptr != '(' && *ptr != '\n') ptr++; // Get arguments and resolve macros in macro for (j = 0; j < MAXARGS; j++) constants[i].arguments[j][0] = 0; if (*ptr == '(' && strchr(ptr, ')') != NULL) { strncpy(tmp, ptr + 1, sizeof(tmp)); if (strchr(tmp, ')') == NULL) { errorf("Macro arguments too long in line %i of %s.\n", line, source); } *strchr(tmp, ')') = 0; token = strtok(tmp, ","); for (j = 0; j < MAXARGS && token; j++) { strncpy(constants[i].arguments[j], token, sizeof(constants[i].arguments[j])); trim(constants[i].arguments[j], sizeof(constants[i].arguments[j])); token = strtok(NULL, ","); } ptr = strchr(ptr, ')') + 1; } while (*ptr == ' ' || *ptr == '\t') ptr++; if (*ptr != '\n') { strncpy(valuebuffer, ptr, sizeof(valuebuffer)); valuebuffer[strlen(valuebuffer) - 1] = 0; success = resolve_macros(valuebuffer, sizeof(valuebuffer), constants); if (success) { errorf("Failed to resolve macros in line %i of %s.\n", line, source); return success; } if (strnlen(valuebuffer, sizeof(valuebuffer)) == sizeof(valuebuffer)) { errorf("Macro value in line %i of %s exceeds maximum size (%i).\n", line, source, sizeof(valuebuffer)); return 3; } if (constants[i].value != 0) free(constants[i].value); constants[i].value = (char *)malloc(strlen(valuebuffer) + 1); strcpy(constants[i].value, valuebuffer); } else { constants[i].value = (char *)malloc(1); constants[i].value[0] = 0; } strncpy(constants[i].name, definition, sizeof(constants[i].name)); } else if (level_comment == 0 && strlen(buffer) >= 6 && strncmp(buffer, "#undef", 6) == 0) { i = 0; while (strlen(constants[i].name) != 0 && strcmp(constants[i].name, definition) != 0 && i <= MAXCONSTS) i++; if (i == MAXCONSTS) { errorf("Include %s not found in line %i of %s.\n", definition, line, source); return 3; } constants[i].name[0] = 0; } else if (level_comment == 0 && strlen(buffer) >= 8 && (strncmp(buffer, "#ifdef", 6) == 0 || strncmp(buffer, "#ifndef", 7) == 0)) { level++; if (strncmp(buffer, "#ifndef", 7) == 0) level_true++; for (i = 0; i < MAXCONSTS; i++) { if (strcmp(definition, constants[i].name) == 0) { if (strncmp(buffer, "#ifdef", 6) == 0) level_true++; if (strncmp(buffer, "#ifndef", 7) == 0) level_true--; } } } else if (level_comment == 0 && strlen(buffer) >= 5 && strncmp(buffer, "#else", 5) == 0) { if (level == level_true) level_true--; else level_true = level; } else if (level_comment == 0 && strlen(buffer) >= 6 && strncmp(buffer, "#endif", 6) == 0) { if (level == 0) { errorf("Unexpected #endif in line %i of %s.\n", line, source); return 4; } if (level == level_true) level_true--; level--; } else if (level_comment == 0 && strlen(buffer) >= 11 && strncmp(buffer, "#include", 8) == 0) { for (i = 0; i < strlen(buffer) ; i++) { if (buffer[i] == '<' || buffer[i] == '>') buffer[i] = '"'; } if (strchr(buffer, '"') == NULL) { errorf("Failed to parse #include in line %i in %s.\n", line, source); return 5; } strncpy(includepath, strchr(buffer, '"') + 1, sizeof(includepath)); if (strchr(includepath, '"') == NULL) { errorf("Failed to parse #include in line %i in %s.\n", line, source); return 6; } *strchr(includepath, '"') = 0; if (find_file(includepath, source, actualpath)) { errorf("Failed to find %s.\n", includepath); return 7; } free(buffer); success = preprocess(actualpath, f_target, constants); if (success) return success; current_operation = OP_PREPROCESS; strcpy(current_target, source); for (i = 0; i < MAXINCLUDES && include_stack[i][0] != 0; i++); include_stack[i - 1][0] = 0; continue; } if (buffer[0] != '#' && strlen(buffer) > 1) { success = resolve_macros(buffer, buffsize, constants); if (success) { errorf("Failed to resolve macros in line %i of %s.\n", line, source); return success; } fputs(buffer, f_target); } free(buffer); } fclose(f_source); return 0; }
/* * Parse parameters * _s is string containing parameters, it will be updated to point behind the parameters * _c is class of parameters * _h is pointer to structure that will be filled with pointer to well known parameters * linked list of parsed parameters will be stored in * the variable _p is pointing to * The function returns 0 on success and negative number * on an error */ int parse_params(str* _s, pclass_t _c, param_hooks_t* _h, param_t** _p) { param_t* t; param_t* last; if (!_s || !_h || !_p) { LM_ERR("invalid parameter value\n"); return -1; } memset(_h, 0, sizeof(param_hooks_t)); last = NULL; *_p = 0; if (!_s->s) { /* no parameters at all -- we're done */ LM_DBG("empty uri params, skipping\n"); return 0; } LM_DBG("Parsing params for:[%.*s]\n",_s->len,_s->s); while(1) { t = (param_t*)pkg_malloc(sizeof(param_t)); if (t == 0) { LM_ERR("no pkg memory left\n"); goto error; } memset(t, 0, sizeof(param_t)); parse_param_name(_s, _c, _h, t); trim_leading(_s); if (_s->len == 0) { /* The last parameter without body */ t->len = t->name.len; goto ok; } if (_s->s[0] == '=') { _s->s++; _s->len--; trim_leading(_s); if (_s->len == 0) { LM_ERR("body missing\n"); goto error; } if (parse_param_body(_s, t) < 0) { LM_ERR("failed to parse param body\n"); goto error; } t->len = _s->s - t->name.s; trim_leading(_s); if (_s->len == 0) { goto ok; } } else { t->len = t->name.len; } if (_s->s[0]==',') goto ok; /* To be able to parse header parameters */ if (_s->s[0]=='>') goto ok; /* To be able to parse URI parameters */ if (_s->s[0] != ';') { LM_ERR("invalid character, ; expected, found %c \n",_s->s[0]); goto error; } _s->s++; _s->len--; trim_leading(_s); if (_s->len == 0) { LM_ERR("param name missing after ;\n"); goto error; } if (last) {last->next=t;} else {*_p = t;} last = t; } error: if (t) pkg_free(t); free_params(*_p); *_p = 0; return -2; ok: if (last) {last->next=t;} else {*_p = t;} _h->last_param = last = t; return 0; }
/** * Only parse one parameter * Returns: * t: out parameter * -1: on error * 0: success, but expect a next paramter * 1: success and exepect no more parameters */ inline int parse_param(str *_s, pclass_t _c, param_hooks_t *_h, param_t *t) { memset(t, 0, sizeof(param_t)); parse_param_name(_s, _c, _h, t); trim_leading(_s); if (_s->len == 0) { /* The last parameter without body */ t->len = t->name.len; goto ok; } if (_s->s[0] == '=') { _s->s++; _s->len--; trim_leading(_s); if (_s->len == 0) { LOG(L_ERR, "parse_params(): Body missing\n"); goto error; } if (parse_param_body(_s, t) < 0) { LOG(L_ERR, "parse_params(): Error while parsing param body\n"); goto error; } t->len = _s->s - t->name.s; trim_leading(_s); if (_s->len == 0) { goto ok; } } else { t->len = t->name.len; } if (_s->s[0] == ',') goto ok; /* To be able to parse header parameters */ if (_s->s[0] == '>') goto ok; /* To be able to parse URI parameters */ if (_s->s[0] != ';') { LOG(L_ERR, "parse_params(): Invalid character, ; expected\n"); goto error; } _s->s++; _s->len--; trim_leading(_s); if (_s->len == 0) { LOG(L_ERR, "parse_params(): Param name missing after ;\n"); goto error; } return 0; /* expect more params */ ok: return 1; /* done with parsing for params */ error: return -1; }