+ SilcBufferUnformatFunc func;
+ void **val;
+ void *context;
+ int tmp_len;
+ func = va_arg(ap, SilcBufferUnformatFunc);
+ val = va_arg(ap, void **);
+ context = va_arg(ap, void *);
+
+ if (!process)
+ break;
+
+ tmp_len = func(stack, src, val, context);
+ if (tmp_len < 0)
+ goto fail;
+ if (tmp_len) {
+ UNFORMAT_HAS_SPACE(src, tmp_len);
+ silc_buffer_pull(src, tmp_len);
+ }
+ }
+ break;
+
+ case SILC_PARAM_REGEX:
+ {
+ const char *regex = va_arg(ap, char *);
+ SilcBufferRegexFlags rflags = va_arg(ap, SilcBufferRegexFlags);
+ SilcBufferStruct match;
+ SilcBool match_all = (rflags & SILC_STR_REGEX_ALL) != 0;
+ SilcBool match_nl = (rflags & SILC_STR_REGEX_NL) != 0;
+ SilcBool ret;
+ SilcUInt32 inclusive_pos = 0;
+ int matched = 0, ret_len;
+ va_list cp;
+
+ if (!process)
+ break;
+
+ if (!regex)
+ break;
+
+ if (match_nl) {
+ start_nl_match:
+ /* Match for '\n' in the buffer. If not found, treat as line
+ without '\n' (buffer has only one line, or this is last line). */
+ if (silc_regex_buffer(src, "\n", &match, NULL))
+ src->tail = match.tail;
+ }
+
+ start_match:
+ /* Match */
+ ret = silc_regex_buffer(src, regex, &match, NULL);
+ ret ^= (rflags & SILC_STR_REGEX_NOT) != 0;
+ if (!ret) {
+ if (!matched && rflags & SILC_STR_REGEX_MISMATCH) {
+ silc_set_errno(SILC_ERR_NOT_FOUND);
+ goto fail;
+ }
+ goto end_match;
+ }
+ matched++;
+
+ if (rflags & SILC_STR_REGEX_NOT)
+ match = *src;
+
+ if (!(rflags & SILC_STR_REGEX_NO_ADVANCE)) {
+ /* Advance buffer after match */
+ if (!silc_buffer_pull(src, (match.data - src->data)))
+ goto fail;
+ }
+
+ if (rflags & SILC_STR_REGEX_INCLUSIVE) {
+ inclusive_pos = src->tail - match.tail;
+ src->tail = match.tail;
+ }
+
+ /* Recursively format */
+ silc_va_copy(cp, ap);
+ ret_len = silc_buffer_sunformat_vp_i(stack, src, cp, TRUE);
+ va_end(cp);
+ if (ret_len < 0)
+ goto fail;
+
+ if (rflags & SILC_STR_REGEX_INCLUSIVE)
+ if (!silc_buffer_pull_tail(src, inclusive_pos))
+ goto fail;
+
+ /* Advance buffer after formatting */
+ if (!silc_buffer_pull(src, ret_len))
+ goto fail;
+
+ if (match_all && (!match_nl || silc_buffer_len(src) > 1))
+ goto start_match;
+
+ end_match:
+ if (match_nl) {
+ /* Go to next line, it is at the end of the data area. Adjust
+ the tail area of the target buffer to show rest of the buffer. */
+ if (!silc_buffer_pull(src, (src->tail - src->data)))
+ goto fail;
+ if (!silc_buffer_pull_tail(src, silc_buffer_taillen(src)))
+ goto fail;
+
+ if (silc_buffer_len(src) > 0)
+ goto start_nl_match;
+ }
+
+ /* Skip to the next SILC_PARAM_END */
+ silc_buffer_sunformat_vp_i(NULL, src, ap, FALSE);
+ break;
+ }
+ break;
+
+ case SILC_PARAM_UICHAR:
+ {
+ unsigned char **x = va_arg(ap, unsigned char **);
+ SilcUInt32 len2 = va_arg(ap, SilcUInt32);
+
+ if (!process)
+ break;
+
+ UNFORMAT_HAS_SPACE(src, len2);
+ if (silc_likely(len2 && x))
+ *x = src->data;
+ silc_buffer_pull(src, len2);
+ break;
+ }
+
+ case SILC_PARAM_UICHAR | SILC_PARAM_ALLOC:
+ {
+ unsigned char **x = va_arg(ap, unsigned char **);
+ SilcUInt32 len2 = va_arg(ap, SilcUInt32);
+
+ if (!process)
+ break;
+
+ UNFORMAT_HAS_SPACE(src, len2);
+ if (silc_likely(len2 && x)) {
+ *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
+ memcpy(*x, src->data, len2);
+ }
+ silc_buffer_pull(src, len2);