+ break;
+
+ case SILC_PARAM_REGEX:
+ {
+ const char *regex = va_arg(ap, char *);
+ SilcBufferRegexFlags rflags = va_arg(ap, SilcUInt32);
+ SilcBufferStruct match, saved;
+ SilcBool match_all = (rflags & SILC_STR_REGEX_ALL) != 0;
+ SilcBool match_nl = (rflags & SILC_STR_REGEX_NL) != 0;
+ SilcBool ret;
+ unsigned char *saved_incl = NULL;
+ int matched = 0, ret_len;
+ va_list cp;
+
+ if (!process)
+ break;
+
+ if (!regex)
+ goto fail;
+
+ memset(&saved, 0, sizeof(saved));
+
+ 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). */
+ saved = *src;
+ 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 */
+ UNFORMAT_HAS_SPACE(src, (match.data - src->data));
+ if (!silc_buffer_pull(src, (match.data - src->data)))
+ goto fail;
+ }
+
+ if (rflags & SILC_STR_REGEX_INCLUSIVE) {
+ saved_incl = src->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)
+ src->tail = saved_incl;
+
+ /* Advance buffer after formatting */
+ UNFORMAT_HAS_SPACE(src, ret_len);
+ 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. */
+ UNFORMAT_HAS_SPACE(src, src->tail - src->data);
+ if (!silc_buffer_pull(src, (src->tail - src->data)))
+ goto fail;
+ if (!silc_buffer_pull_tail(src, (saved.tail - src->tail)))
+ 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;
+