From: Pekka Riikonen Date: Tue, 1 Jan 2008 16:10:46 +0000 (+0000) Subject: Added SILC_STR_REGEX macro to SILC Buffer Format API. X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=f2462c5dd7e885e3daa00066fbf53e166fd361e0 Added SILC_STR_REGEX macro to SILC Buffer Format API. It provides powerful regular expression matching within the SilcBuffer. Combined with SILC Buffer Format API it can turn the API into a Stream Editor (sed) and Awk like, providing powerful ways to match and edit the buffer in myriad of ways. The SILC_STR_REGEX can also mimic the behavior of sed (match and edit line by line). --- diff --git a/CHANGES.RUNTIME b/CHANGES.RUNTIME index d129dfea..f97fb9dd 100644 --- a/CHANGES.RUNTIME +++ b/CHANGES.RUNTIME @@ -1,3 +1,25 @@ +Tue Jan 1 18:00:47 EET 2008 Pekka Riikonen + + * Added silc_regex and silc_regex_buffer, routines that provide + convenient use of regular expressions. Affected files + are lib/silcutil/silcregex.[ch]. Deprecated the + silc_string_regex_match. Affected files are + lib/silcutil/silcstrutil.[ch]. + + * Added SILC_STR_REGEX macro to SILC Buffer Format API. It + provides powerful regular expression matching within the + SilcBuffer. Combined with SILC Buffer Format API it can turn + the API into a Stream Editor (sed) and Awk like, providing + powerful ways to match and edit the buffer in myriad of ways. + The SILC_STR_REGEX can also mimic the behavior of sed (match + and edit line by line). Affected files are + lib/silcutil/silcbuffmt.[ch], silctypes.h. + +Mon Dec 31 15:50:31 EET 2007 Pekka Riikonen + + * Added SILC_STR_OFFSET_START and SILC_STR_OFFSET_END to + lib/silcutil/silcbuffmt.[ch]. + Mon Dec 31 01:30:17 EET 2007 Pekka Riikonen * Added SILC regular expression API to lib/silcutil/silcregex.[ch]. diff --git a/lib/silcutil/silcbuffmt.c b/lib/silcutil/silcbuffmt.c index b0c5d5c5..366c4478 100644 --- a/lib/silcutil/silcbuffmt.c +++ b/lib/silcutil/silcbuffmt.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2007 Pekka Riikonen + Copyright (C) 1997 - 2008 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -47,36 +47,8 @@ do { \ /******************************* Formatting *********************************/ -int silc_buffer_format(SilcBuffer dst, ...) -{ - va_list ap; - int ret; - - va_start(ap, dst); - ret = silc_buffer_sformat_vp(NULL, dst, ap); - va_end(ap); - - return ret; -} - -int silc_buffer_format_vp(SilcBuffer dst, va_list ap) -{ - return silc_buffer_sformat_vp(NULL, dst, ap); -} - -int silc_buffer_sformat(SilcStack stack, SilcBuffer dst, ...) -{ - va_list ap; - int ret; - - va_start(ap, dst); - ret = silc_buffer_sformat_vp(stack, dst, ap); - va_end(ap); - - return ret; -} - -int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap) +int silc_buffer_sformat_vp_i(SilcStack stack, SilcBuffer dst, va_list ap, + SilcBool process) { SilcParam fmt; int flen = 0; @@ -86,7 +58,7 @@ int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap) while (1) { fmt = va_arg(ap, SilcParam); - SILC_LOG_DEBUG(("Buffer format type %x", fmt)); + SILC_LOG_DEBUG(("Buffer format type %d", fmt)); switch (fmt) { case SILC_PARAM_FUNC: @@ -95,9 +67,14 @@ int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap) void *val; void *context; int tmp_len; + func = va_arg(ap, SilcBufferFormatFunc); val = va_arg(ap, void *); context = va_arg(ap, void *); + + if (!process) + break; + tmp_len = func(stack, dst, val, context); if (tmp_len < 0) goto fail; @@ -107,6 +84,101 @@ int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap) } } 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 = *dst; + if (silc_regex_buffer(dst, "\n", &match, NULL)) + dst->tail = match.tail; + } + + start_match: + /* Match */ + ret = silc_regex_buffer(dst, 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 = *dst; + + if (!(rflags & SILC_STR_REGEX_NO_ADVANCE)) { + /* Advance buffer after match */ + flen += (match.data - dst->data); + if (!silc_buffer_pull(dst, (match.data - dst->data))) + goto fail; + } + + if (rflags & SILC_STR_REGEX_INCLUSIVE) { + saved_incl = dst->tail; + dst->tail = match.tail; + } + + /* Recursively format */ + silc_va_copy(cp, ap); + ret_len = silc_buffer_sformat_vp_i(stack, dst, cp, TRUE); + va_end(cp); + if (ret_len < 0) + goto fail; + + if (rflags & SILC_STR_REGEX_INCLUSIVE) + dst->tail = saved_incl; + + /* Advance buffer after formatting */ + flen += ret_len; + if (!silc_buffer_pull(dst, ret_len)) + goto fail; + + if (match_all && (!match_nl || silc_buffer_len(dst) > 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. */ + flen += (dst->tail - dst->data); + if (!silc_buffer_pull(dst, (dst->tail - dst->data))) + goto fail; + if (!silc_buffer_pull_tail(dst, (saved.tail - dst->tail))) + goto fail; + + if (silc_buffer_len(dst) > 0) + goto start_nl_match; + } + + /* Skip to the next SILC_PARAM_END */ + silc_buffer_sformat_vp_i(NULL, NULL, ap, FALSE); + } + break; + case SILC_PARAM_UI8_STRING: case SILC_PARAM_UI16_STRING: case SILC_PARAM_UI32_STRING: @@ -116,6 +188,10 @@ int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap) { char *x = va_arg(ap, char *); SilcUInt32 tmp_len = x ? strlen(x) : 0; + + if (!process) + break; + if (x && tmp_len) { FORMAT_HAS_SPACE(stack, dst, tmp_len); silc_buffer_put(dst, (unsigned char *)x, tmp_len); @@ -123,6 +199,7 @@ int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap) } break; } + case SILC_PARAM_UI8_NSTRING: case SILC_PARAM_UI16_NSTRING: case SILC_PARAM_UI32_NSTRING: @@ -134,6 +211,10 @@ int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap) { unsigned char *x = va_arg(ap, unsigned char *); SilcUInt32 tmp_len = va_arg(ap, SilcUInt32); + + if (!process) + break; + if (x && tmp_len) { FORMAT_HAS_SPACE(stack, dst, tmp_len); silc_buffer_put(dst, x, tmp_len); @@ -141,87 +222,132 @@ int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap) } break; } + case SILC_PARAM_UINT8: { unsigned char x = (unsigned char)va_arg(ap, int); + + if (!process) + break; + FORMAT_HAS_SPACE(stack, dst, 1); silc_buffer_put(dst, &x, 1); silc_buffer_pull(dst, 1); break; } + case SILC_PARAM_UINT16: { unsigned char xf[2]; SilcUInt16 x = (SilcUInt16)va_arg(ap, int); + + if (!process) + break; + FORMAT_HAS_SPACE(stack, dst, 2); SILC_PUT16_MSB(x, xf); silc_buffer_put(dst, xf, 2); silc_buffer_pull(dst, 2); break; } + case SILC_PARAM_UINT32: { unsigned char xf[4]; SilcUInt32 x = va_arg(ap, SilcUInt32); + + if (!process) + break; + FORMAT_HAS_SPACE(stack, dst, 4); SILC_PUT32_MSB(x, xf); silc_buffer_put(dst, xf, 4); silc_buffer_pull(dst, 4); break; } + case SILC_PARAM_UINT64: { unsigned char xf[8]; SilcUInt64 x = va_arg(ap, SilcUInt64); + + if (!process) + break; + FORMAT_HAS_SPACE(stack, dst, sizeof(SilcUInt64)); SILC_PUT64_MSB(x, xf); silc_buffer_put(dst, xf, sizeof(SilcUInt64)); silc_buffer_pull(dst, sizeof(SilcUInt64)); break; } + case SILC_PARAM_SINT8: { char x = (char)va_arg(ap, int); + + if (!process) + break; + FORMAT_HAS_SPACE(stack, dst, 1); silc_buffer_put(dst, (unsigned char *)&x, 1); silc_buffer_pull(dst, 1); break; } + case SILC_PARAM_SINT16: { unsigned char xf[2]; SilcInt16 x = (SilcInt16)va_arg(ap, int); + + if (!process) + break; + FORMAT_HAS_SPACE(stack, dst, 2); SILC_PUT16_MSB(x, xf); silc_buffer_put(dst, xf, 2); silc_buffer_pull(dst, 2); break; } + case SILC_PARAM_SINT32: { unsigned char xf[4]; SilcInt32 x = va_arg(ap, SilcInt32); + + if (!process) + break; + FORMAT_HAS_SPACE(stack, dst, 4); SILC_PUT32_MSB(x, xf); silc_buffer_put(dst, xf, 4); silc_buffer_pull(dst, 4); break; } + case SILC_PARAM_SINT64: { unsigned char xf[8]; SilcInt64 x = va_arg(ap, SilcInt64); + + if (!process) + break; + FORMAT_HAS_SPACE(stack, dst, sizeof(SilcInt64)); SILC_PUT64_MSB(x, xf); silc_buffer_put(dst, xf, sizeof(SilcInt64)); silc_buffer_pull(dst, sizeof(SilcInt64)); break; } + case SILC_PARAM_BUFFER: case SILC_PARAM_BUFFER | SILC_PARAM_ALLOC: { SilcBuffer x = va_arg(ap, SilcBuffer); unsigned char xf[4]; + + if (!process) + break; + if (x && silc_buffer_len(x)) { FORMAT_HAS_SPACE(stack, dst, silc_buffer_len(x) + 4); SILC_PUT32_MSB(silc_buffer_len(x), xf); @@ -232,11 +358,17 @@ int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap) } } break; + case SILC_PARAM_OFFSET: { int offst = va_arg(ap, int); + + if (!process) + break; + if (!offst) break; + if (offst > 1) { if (offst > silc_buffer_len(dst)) { silc_set_errno(SILC_ERR_OVERFLOW); @@ -250,12 +382,32 @@ int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap) } break; } + + case SILC_PARAM_OFFSET_START: + if (!process) + break; + if (!silc_buffer_push(dst, flen)) + goto fail; + flen = 0; + break; + + case SILC_PARAM_OFFSET_END: + if (!process) + break; + flen += silc_buffer_len(dst); + silc_buffer_pull(dst, silc_buffer_len(dst)); + break; + case SILC_PARAM_ADVANCE: + if (!process) + break; advance = TRUE; break; + case SILC_PARAM_END: goto ok; break; + default: SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not " "format the data.", fmt)); @@ -268,50 +420,55 @@ int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap) fail: SILC_LOG_DEBUG(("Error occured while formatting data")); - if (!advance) + if (process && !advance) silc_buffer_push(dst, flen); return -1; ok: /* Push the buffer back to where it belongs. */ - if (!advance) + if (process && !advance) silc_buffer_push(dst, flen); return flen; } - -/****************************** Unformatting ********************************/ - -int silc_buffer_unformat(SilcBuffer src, ...) +int silc_buffer_format(SilcBuffer dst, ...) { va_list ap; int ret; - va_start(ap, src); - ret = silc_buffer_sunformat_vp(NULL, src, ap); + va_start(ap, dst); + ret = silc_buffer_sformat_vp(NULL, dst, ap); va_end(ap); return ret; } -int silc_buffer_unformat_vp(SilcBuffer src, va_list ap) +int silc_buffer_format_vp(SilcBuffer dst, va_list ap) { - return silc_buffer_sunformat_vp(NULL, src, ap); + return silc_buffer_sformat_vp(NULL, dst, ap); } -int silc_buffer_sunformat(SilcStack stack, SilcBuffer src, ...) +int silc_buffer_sformat(SilcStack stack, SilcBuffer dst, ...) { va_list ap; int ret; - va_start(ap, src); - ret = silc_buffer_sunformat_vp(stack, src, ap); + va_start(ap, dst); + ret = silc_buffer_sformat_vp(stack, dst, ap); va_end(ap); return ret; } -int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) +int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap) +{ + return silc_buffer_sformat_vp_i(stack, dst, ap, TRUE); +} + +/****************************** Unformatting ********************************/ + +int silc_buffer_sunformat_vp_i(SilcStack stack, SilcBuffer src, va_list ap, + SilcBool process) { SilcParam fmt; unsigned char *start_ptr = src->data; @@ -322,7 +479,7 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) while (1) { fmt = va_arg(ap, SilcParam); - SILC_LOG_DEBUG(("Buffer unformat type %x", fmt)); + SILC_LOG_DEBUG(("Buffer unformat type %d", fmt)); switch (fmt) { case SILC_PARAM_FUNC: @@ -334,6 +491,10 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) 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; @@ -342,20 +503,125 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) silc_buffer_pull(src, tmp_len); } } + 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; + 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)); @@ -364,82 +630,127 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) silc_buffer_pull(src, len2); break; } + case SILC_PARAM_UINT8: { unsigned char *x = va_arg(ap, unsigned char *); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 1); if (silc_likely(x)) *x = src->data[0]; silc_buffer_pull(src, 1); break; } + case SILC_PARAM_UINT16: { SilcUInt16 *x = va_arg(ap, SilcUInt16 *); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 2); if (silc_likely(x)) SILC_GET16_MSB(*x, src->data); silc_buffer_pull(src, 2); break; } + case SILC_PARAM_UINT32: { SilcUInt32 *x = va_arg(ap, SilcUInt32 *); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 4); if (silc_likely(x)) SILC_GET32_MSB(*x, src->data); silc_buffer_pull(src, 4); break; } + case SILC_PARAM_UINT64: { SilcUInt64 *x = va_arg(ap, SilcUInt64 *); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, sizeof(SilcUInt64)); if (silc_likely(x)) SILC_GET64_MSB(*x, src->data); silc_buffer_pull(src, sizeof(SilcUInt64)); break; } + case SILC_PARAM_SINT8: { char *x = va_arg(ap, char *); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 1); if (silc_likely(x)) *x = src->data[0]; silc_buffer_pull(src, 1); break; } + case SILC_PARAM_SINT16: { SilcInt16 *x = va_arg(ap, SilcInt16 *); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 2); if (silc_likely(x)) SILC_GET16_MSB(*x, src->data); silc_buffer_pull(src, 2); break; } + case SILC_PARAM_SINT32: { SilcInt32 *x = va_arg(ap, SilcInt32 *); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 4); if (silc_likely(x)) SILC_GET32_MSB(*x, src->data); silc_buffer_pull(src, 4); break; } + case SILC_PARAM_SINT64: { SilcInt64 *x = va_arg(ap, SilcInt64 *); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, sizeof(SilcInt64)); if (silc_likely(x)) SILC_GET64_MSB(*x, src->data); silc_buffer_pull(src, sizeof(SilcInt64)); break; } + case SILC_PARAM_UI8_STRING: { SilcUInt8 len2; unsigned char **x = va_arg(ap, unsigned char **); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 1); len2 = (SilcUInt8)src->data[0]; silc_buffer_pull(src, 1); @@ -449,10 +760,15 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) silc_buffer_pull(src, len2); break; } + case SILC_PARAM_UI8_STRING | SILC_PARAM_ALLOC: { SilcUInt8 len2; unsigned char **x = va_arg(ap, unsigned char **); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 1); len2 = (SilcUInt8)src->data[0]; silc_buffer_pull(src, 1); @@ -464,10 +780,15 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) silc_buffer_pull(src, len2); break; } + case SILC_PARAM_UI16_STRING: { SilcUInt16 len2; unsigned char **x = va_arg(ap, unsigned char **); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 2); SILC_GET16_MSB(len2, src->data); silc_buffer_pull(src, 2); @@ -477,10 +798,15 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) silc_buffer_pull(src, len2); break; } + case SILC_PARAM_UI16_STRING | SILC_PARAM_ALLOC: { SilcUInt16 len2; unsigned char **x = va_arg(ap, unsigned char **); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 2); SILC_GET16_MSB(len2, src->data); silc_buffer_pull(src, 2); @@ -492,10 +818,15 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) silc_buffer_pull(src, len2); break; } + case SILC_PARAM_UI32_STRING: { SilcUInt32 len2; unsigned char **x = va_arg(ap, unsigned char **); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 4); SILC_GET32_MSB(len2, src->data); silc_buffer_pull(src, 4); @@ -505,10 +836,15 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) silc_buffer_pull(src, len2); break; } + case SILC_PARAM_UI32_STRING | SILC_PARAM_ALLOC: { SilcUInt32 len2; unsigned char **x = va_arg(ap, unsigned char **); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 4); SILC_GET32_MSB(len2, src->data); silc_buffer_pull(src, 4); @@ -520,11 +856,16 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) silc_buffer_pull(src, len2); break; } + case SILC_PARAM_UI8_NSTRING: { SilcUInt8 len2; unsigned char **x = va_arg(ap, unsigned char **); SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 1); len2 = (SilcUInt8)src->data[0]; silc_buffer_pull(src, 1); @@ -536,11 +877,16 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) silc_buffer_pull(src, len2); break; } + case SILC_PARAM_UI8_NSTRING | SILC_PARAM_ALLOC: { SilcUInt8 len2; unsigned char **x = va_arg(ap, unsigned char **); SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 1); len2 = (SilcUInt8)src->data[0]; silc_buffer_pull(src, 1); @@ -554,11 +900,16 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) silc_buffer_pull(src, len2); break; } + case SILC_PARAM_UI16_NSTRING: { SilcUInt16 len2; unsigned char **x = va_arg(ap, unsigned char **); SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 2); SILC_GET16_MSB(len2, src->data); silc_buffer_pull(src, 2); @@ -570,11 +921,16 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) silc_buffer_pull(src, len2); break; } + case SILC_PARAM_UI16_NSTRING | SILC_PARAM_ALLOC: { SilcUInt16 len2; unsigned char **x = va_arg(ap, unsigned char **); SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 2); SILC_GET16_MSB(len2, src->data); silc_buffer_pull(src, 2); @@ -588,11 +944,16 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) silc_buffer_pull(src, len2); break; } + case SILC_PARAM_UI32_NSTRING: { SilcUInt32 len2; unsigned char **x = va_arg(ap, unsigned char **); SilcUInt32 *len3 = va_arg(ap, SilcUInt32 *); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 4); SILC_GET32_MSB(len2, src->data); silc_buffer_pull(src, 4); @@ -604,11 +965,16 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) silc_buffer_pull(src, len2); break; } + case SILC_PARAM_UI32_NSTRING | SILC_PARAM_ALLOC: { SilcUInt32 len2; unsigned char **x = va_arg(ap, unsigned char **); SilcUInt32 *len3 = va_arg(ap, SilcUInt32 *); + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 4); SILC_GET32_MSB(len2, src->data); silc_buffer_pull(src, 4); @@ -622,10 +988,15 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) silc_buffer_pull(src, len2); break; } + case SILC_PARAM_BUFFER: { SilcBuffer x = va_arg(ap, SilcBuffer); SilcUInt32 len2; + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 4); SILC_GET32_MSB(len2, src->data); silc_buffer_pull(src, 4); @@ -634,10 +1005,15 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) silc_buffer_pull(src, len2); } break; + case SILC_PARAM_BUFFER | SILC_PARAM_ALLOC: { SilcBuffer x = va_arg(ap, SilcBuffer); SilcUInt32 len2; + + if (!process) + break; + UNFORMAT_HAS_SPACE(src, 4); SILC_GET32_MSB(len2, src->data); silc_buffer_pull(src, 4); @@ -648,11 +1024,17 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) silc_buffer_pull(src, len2); } break; + case SILC_PARAM_OFFSET: { int offst = va_arg(ap, int); + + if (!process) + break; + if (!offst) break; + if (offst > 1) { UNFORMAT_HAS_SPACE(src, offst); silc_buffer_pull(src, offst); @@ -661,12 +1043,29 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) } break; } + + case SILC_PARAM_OFFSET_START: + if (!process) + break; + silc_buffer_push(src, (src->data - start_ptr)); + break; + + case SILC_PARAM_OFFSET_END: + if (!process) + break; + silc_buffer_pull(src, silc_buffer_len(src)); + break; + case SILC_PARAM_ADVANCE: + if (!process) + break; advance = TRUE; break; + case SILC_PARAM_END: goto ok; break; + default: SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not " "format the data.", fmt)); @@ -679,19 +1078,54 @@ int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) fail: SILC_LOG_DEBUG(("Error occured while unformatting buffer, type %d", fmt)); - len = src->data - start_ptr; - silc_buffer_push(src, len); + if (process && !advance) { + len = src->data - start_ptr; + silc_buffer_push(src, len); + } return -1; ok: /* Push the buffer back to the start. */ - if (!advance) { + if (process && !advance) { len = src->data - start_ptr; silc_buffer_push(src, len); } return len; } +int silc_buffer_unformat(SilcBuffer src, ...) +{ + va_list ap; + int ret; + + va_start(ap, src); + ret = silc_buffer_sunformat_vp(NULL, src, ap); + va_end(ap); + + return ret; +} + +int silc_buffer_unformat_vp(SilcBuffer src, va_list ap) +{ + return silc_buffer_sunformat_vp(NULL, src, ap); +} + +int silc_buffer_sunformat(SilcStack stack, SilcBuffer src, ...) +{ + va_list ap; + int ret; + + va_start(ap, src); + ret = silc_buffer_sunformat_vp(stack, src, ap); + va_end(ap); + + return ret; +} + +int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap) +{ + return silc_buffer_sunformat_vp_i(stack, src, ap, TRUE); +} /**************************** Utility functions *****************************/ diff --git a/lib/silcutil/silcbuffmt.h b/lib/silcutil/silcbuffmt.h index 4668f7f9..4334dc57 100644 --- a/lib/silcutil/silcbuffmt.h +++ b/lib/silcutil/silcbuffmt.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2007 Pekka Riikonen + Copyright (C) 1997 - 2008 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,6 +26,16 @@ * into specified data types. It is especially useful to encode packets, * protocol payloads and such. * + * It also provides many advanced features like calling user specified + * encoder and decoder functions that are free to do anything to the buffer. + * The API also provides powerful regular expression matching capabilities + * within the buffer, enabling caller to not only match regular expressions + * but to make the API behave like Stream Editor (Sed) and Awk. The buffer + * can be matched against regular expression and then edited. Caller can + * do anything they want to the buffer after a match. The SILC_STR_REGEX + * macro provides many different flags that can change the behavior of the + * matching, with capabilities to also mimic Sed behavior. + * * As the SilcBuffer API is not thread-safe these routines may not be used * in multithreaded environment with a same SilcBuffer context without * concurrency control. @@ -45,6 +55,12 @@ * if (ret < 0) * error; * + * // sed 's/foo/bar/', replace first foo with bar + * silc_buffer_format(buffer, + * SILC_STR_REGEX("foo", 0), + * SILC_STR_STRING("bar"), + * SILC_STR_END, SILC_STR_END); + * ***/ #ifndef SILCBUFFMT_H @@ -489,6 +505,32 @@ int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...); #define SILC_STR_SI_INT64(x) SILC_PARAM_SINT64, (x) #define SILC_STR_UI_INT64(x) SILC_PARAM_UINT64, (x) +/****d* silcutil/SilcBufferFormatAPI/SILC_STR_STRING + * + * NAME + * + * #define SILC_STR_STRING() ... + * + * DESCRIPTION + * + * Encode NULL terminated string. Use this only for formatting. + * + * Formatting: SILC_STR_STRING(char *) + * + * For unformatting use one of the SILC_STR_*_STRING macros, which + * automatically gets the length of the string from the buffer. Note + * SILC_STR_STRING does not save the length of the string into the buffer. + * The caller must do that in order for the unformatting macros to work. + * + * Example: + * + * Formatting: ..., SILC_STR_UINT32(strlen(string)), + * SILC_STR_STRING(string), ... + * Unformatting: ..., SILC_STR_UI32_STRING(&string), ... + * + ***/ +#define SILC_STR_STRING(x) SILC_PARAM_UI8_STRING, (x) + /****d* silcutil/SilcBufferFormatAPI/SILC_STR_*_STRING * * NAME @@ -511,22 +553,21 @@ int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...); * * Unformatting procedure will check for length of the string from the * buffer before trying to get the string out. Thus, one *must* format the - * length as UI_INT or UI_SHORT into the buffer *before* formatting the - * actual string to the buffer, and, in unformatting one must ignore the + * length as UINT32 or UINT16 or UINT8 into the buffer *before* formatting + * the actual string to the buffer, and, in unformatting one ignores the * length of the string because unformatting procedure will take it * automatically. * * Example: * - * Formatting: ..., SILC_STR_UI_INT(strlen(string)), + * Formatting: ..., SILC_STR_UINT32(strlen(string)), * SILC_STR_UI32_STRING(string), ... * Unformatting: ..., SILC_STR_UI32_STRING(&string), ... * * I.e., you can ignore the formatted length field in unformatting. * * UI8, UI16 and UI32 means that the length is considered to be - * either char (8 bits), short (16 bits) or int (32 bits) in - * unformatting. + * either UINT8, UINT16 or UINT32 in unformatting. * * _ALLOC routines automatically allocates memory for the variable sent * as argument in unformatting. @@ -559,14 +600,14 @@ int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...); * * Unformatting procedure will check for length of the string from the * buffer before trying to get the string out. Thus, one *must* format the - * length as UI_INT or UI_SHORT into the buffer *before* formatting the - * actual string to the buffer, and, in unformatting one must ignore the + * length as UINT32 or UINT16 or UINT8 into the buffer *before* formatting + * the actual string to the buffer, and, in unformatting one ignores the * length of the string because unformatting procedure will take it * automatically. * * Example: * - * Formatting: ..., SILC_STR_UI_INT(strlen(string)), + * Formatting: ..., SILC_STR_UINT32(strlen(string)), * SILC_STR_UI32_NSTRING(string, strlen(string)), ... * Unformatting: ..., SILC_STR_UI32_NSTRING(&string, &len), ... * @@ -575,8 +616,7 @@ int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...); * argument (&len in above example). * * UI8, UI16 and UI32 means that the length is considered to be - * either char (8 bits), short (16 bits) or int (32 bits) in - * unformatting. + * either UINT8, UINT16 or UINT32 in unformatting. * * _ALLOC routines automatically allocates memory for the variable sent * as argument in unformatting. @@ -654,7 +694,7 @@ int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...); * * DESCRIPTION * - * SilcBuffer formatting. + * Formatting and unformatting of arbitrary data. * * Formatting: SILC_STR_FUNC(function, void *value, void *context) * Unformatting: SILC_STR_FUNC(function, void **value, void *context) @@ -699,6 +739,134 @@ int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...); #define SILC_STR_FUNC(func, val, context) SILC_PARAM_FUNC, \ func, (val), (context) +/****d* silcutil/SilcBufferFormatAPI/SilcBufferRegexFlags + * + * NAME + * + * typedef enum { ... } SilcBufferRegexFlags; + * + * DESCRIPTION + * + * Regular expression flags for SILC_STR_REGEX macro. The flags can be + * used to manipulate the behavior of the SILC_STR_REGEX. All flags + * may be combined unless otherwise stated. + * + * SOURCE + */ +typedef enum { + SILC_STR_REGEX_NONE = 0x00000000, + + /* By default mismatch will be skipped. Set this flag if mismatch should + cause error and stopping of the formatting/unformatting. */ + SILC_STR_REGEX_MISMATCH = 0x00000001, + + /* By default only the first match is found. Set this flag to find + all matches. */ + SILC_STR_REGEX_ALL = 0x00000002, + + /* By default the buffer position is advanced to the position of the + first match. Set this flag if the buffer should not be advanced to + the match. */ + SILC_STR_REGEX_NO_ADVANCE = 0x00000004, + + /* By default SILC_STR_REGEX performs the match on the whole buffer. Set + this flag to make it behave like sed and match line by line. Each line + must end with '\n'. If buffer doesn't have '\n' it is considered to be + one line. Note that, any formatting done immediately after SILC_STR_REGEX + block with this flag will be formatted to the end of the buffer (after + last line). Use SILC_STR_OFFSET* macros to change the position if + needed. Also note that, any encoding macro inside the SILC_STR_REGEX + block will see only the matched line (including '\n'), instead of whole + buffer after the match. */ + SILC_STR_REGEX_NL = 0x00000008, + + /* Set this flag to not match the regular expression, but to match everything + else. When combined with SILC_STR_REGEX_NL this flag matches all other + lines except the ones with matching regular expression. */ + SILC_STR_REGEX_NOT = 0x00000010, + + /* By default the buffer is advanced to the first match and the rest of the + buffer remains as is. Set this flag to pass the exact match to the + SILC_STR_* macros in the SILC_STR_REGEX block; macros see the start of + the match and the end of the match, but not rest of the buffer (ie. with + match 'foo' the size of the buffer is 3 bytes). */ + SILC_STR_REGEX_INCLUSIVE = 0x00000020, +} SilcBufferRegexFlags; +/***/ + +/****d* silcutil/SilcBufferFormatAPI/SILC_STR_REGEX + * + * NAME + * + * #define SILC_STR_REGEX() ... + * + * DESCRIPTION + * + * Regular expression matching within the buffer. + * + * Formatting: SILC_STR_REGEX(char *regex, SilcBufferRegexFlags flags) + * Unformatting: SILC_STR_REGEX(char *regex, SilcBufferRegexFlags flags) + * + * SILC_STR_REGEX can be used to do regular expression matching within + * the SilcBuffer. When the string in the buffer matches the regular + * expression the position of the buffer is advanced to the position of + * the first match (rest of the buffer remains intact). If the regular + * expression does not match it is skipped, unless the flags specify + * otherwise. If flags are not needed they can be set to 0. + * + * In addition of matching regular expressions it can be used in a + * Stream Editor (sed) and Awk like fashion. The regular expression can be + * matched and then edited by any of the SILC_STR_* macros. The flags + * can be used to perform complex operations on the data. Some sed + * features that cannot be directly done with the flags can be done with + * SILC_STR_FUNC and other macros (the SILC_STR_FUNC could do anything + * after the match). + * + * The SILC_STR_REGEX itself is used as an opening of a block of encoding + * macros and must be closed with SILC_STR_END. This means that for + * each SILC_STR_REGEX there must be one SILC_STR_END. See examples for + * more information. + * + * The SILC_STR_REGEX can be used in buffer unformatting also to do + * string matching and parsing, but not editing, except with SILC_STR_FUNC + * macro, which can do anything caller wants. + * + * EXAMPLE + * + * // sed 's/foo/bar/', replace first foo with bar + * silc_buffer_format(buffer, + * SILC_STR_REGEX("foo", 0), + * SILC_STR_STRING("bar"), + * SILC_STR_END, SILC_STR_END); + * + * // sed 's/foo/bar/g', replace all foo's with bar + * silc_buffer_format(buffer, + * SILC_STR_REGEX("foo", SILC_STR_REGEX_ALL), + * SILC_STR_STRING("bar"), + * SILC_STR_END, SILC_STR_END); + * + * // sed '/baz/s/foo/bar/g, replace all foo's with bar on lines with baz + * silc_buffer_format(buffer, + * SILC_STR_REGEX("baz", SILC_STR_REGEX_NL), + * SILC_STR_REGEX("foo", SILC_STR_REGEX_ALL), + * SILC_STR_STRING("bar"), + * SILC_STR_END, + * SILC_STR_END, SILC_STR_END); + * + * // Print all lines that start with 'R' + * int print(SilcStack stack, SilcBuffer buf, void *value, void *context) + * { + * return fwrite(silc_buffer_data(buf), 1, silc_buffer_len(buf), stdout); + * } + * + * silc_buffer_unformat(buffer, + * SILC_STR_REGEX("^R", SILC_STR_REGEX_NL), + * SILC_STR_FUNC(print, NULL, NULL), + * SILC_STR_END, SILC_STR_END); + * + ***/ +#define SILC_STR_REGEX(regex, flags) SILC_PARAM_REGEX, (regex), (flags) + /****d* silcutil/SilcBufferFormatAPI/SILC_STR_OFFSET * * NAME @@ -724,6 +892,40 @@ int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...); ***/ #define SILC_STR_OFFSET(x) SILC_PARAM_OFFSET, (x) +/****d* silcutil/SilcBufferFormatAPI/SILC_STR_OFFSET_START + * + * NAME + * + * #define SILC_STR_OFFSET_START ... + * + * DESCRIPTION + * + * Moves the buffer position to the start of the data area. + * + * Example: + * + * ..., SILC_STR_OFFSET_START, ... + * + ***/ +#define SILC_STR_OFFSET_START SILC_PARAM_OFFSET_START + +/****d* silcutil/SilcBufferFormatAPI/SILC_STR_OFFSET_END + * + * NAME + * + * #define SILC_STR_OFFSET_END ... + * + * DESCRIPTION + * + * Moves the buffer position to the end of the data area. + * + * Example: + * + * ..., SILC_STR_OFFSET_END, ... + * + ***/ +#define SILC_STR_OFFSET_END SILC_PARAM_OFFSET_END + /****d* silcutil/SilcBufferFormatAPI/SILC_STR_ADVANCE * * NAME diff --git a/lib/silcutil/silctypes.h b/lib/silcutil/silctypes.h index b6bbffd2..a4a06d9e 100644 --- a/lib/silcutil/silctypes.h +++ b/lib/silcutil/silctypes.h @@ -268,7 +268,6 @@ typedef void * SilcSocket; #endif /***/ - /****d* silcutil/SILCTypes/SilcParam * * NAME @@ -310,6 +309,9 @@ typedef SilcUInt32 SilcParam; #define SILC_PARAM_OFFSET 106 #define SILC_PARAM_ADVANCE 107 #define SILC_PARAM_FUNC 108 +#define SILC_PARAM_REGEX 109 +#define SILC_PARAM_OFFSET_START 110 +#define SILC_PARAM_OFFSET_END 111 #define SILC_PARAM_ALLOC 0x00010000 /* Allocate, bitmask */ /* Macros */ diff --git a/lib/silcutil/tests/Makefile.am b/lib/silcutil/tests/Makefile.am index 7d6f4e31..a08a0863 100644 --- a/lib/silcutil/tests/Makefile.am +++ b/lib/silcutil/tests/Makefile.am @@ -22,7 +22,7 @@ bin_PROGRAMS = test_silcstrutil test_silcstringprep test_silchashtable \ test_silcnet test_silcstack test_silcmime test_silcfdstream \ test_silcatomic test_silcmutex test_silctime test_silcthread \ test_silcdll test_silcenv test_silctimer test_silcbitops \ - test_silcregex + test_silcregex test_silcbuffmt test_silcstrutil_SOURCES = test_silcstrutil.c test_silcstringprep_SOURCES = test_silcstringprep.c @@ -44,6 +44,7 @@ test_silcenv_SOURCES = test_silcenv.c test_silctimer_SOURCES = test_silctimer.c test_silcbitops_SOURCES = test_silcbitops.c test_silcregex_SOURCES = test_silcregex.c +test_silcbuffmt_SOURCES = test_silcbuffmt.c LIBS = $(SILC_COMMON_LIBS) LDADD = -L.. -L../.. -lsilc diff --git a/lib/silcutil/tests/test_silcbuffmt.c b/lib/silcutil/tests/test_silcbuffmt.c new file mode 100644 index 00000000..dba97fd0 --- /dev/null +++ b/lib/silcutil/tests/test_silcbuffmt.c @@ -0,0 +1,123 @@ +/* Buffer formatting tests */ + +#include "silc.h" + +int print(SilcStack stack, SilcBuffer buf, void *value, void *context) +{ + fwrite(silc_buffer_data(buf), 1, silc_buffer_len(buf), stdout); + if (!silc_buffer_strchr(buf, '\n', TRUE)) + printf("\n"); + fflush(stdout); + return silc_buffer_len(buf); +} + +int main(int argc, char **argv) +{ + SilcBool success = FALSE; + char string[1024]; + SilcBufferStruct buf; + + if (argc > 1 && !strcmp(argv[1], "-d")) { + silc_log_debug(TRUE); + silc_log_quick(TRUE); + silc_log_debug_hexdump(TRUE); + silc_log_set_debug_string("*buf*,*regex*,*errno*"); + } + + silc_snprintf(string, sizeof(string), "This is foobar"); + silc_buffer_set(&buf, string, strlen(string)); + SILC_LOG_DEBUG(("sed 's/foo/bar/'")); + SILC_LOG_DEBUG(("string: %s", string)); + if (silc_buffer_format(&buf, + SILC_STR_REGEX("foo", 0), + SILC_STR_STRING("bar"), + SILC_STR_END, + SILC_STR_END) < 0) + goto err; + SILC_LOG_DEBUG(("string: %s", silc_buffer_data(&buf))); + if (strcmp("This is barbar", silc_buffer_data(&buf))) + goto err; + + silc_snprintf(string, sizeof(string), "This is foobar\n"); + silc_buffer_set(&buf, string, strlen(string)); + SILC_LOG_DEBUG(("sed 's/\\n/\\0/'")); + SILC_LOG_DEBUG(("string: %s", string)); + if (silc_buffer_format(&buf, + SILC_STR_REGEX("\n", 0), + SILC_STR_UINT8(0), + SILC_STR_END, + SILC_STR_END) < 0) + goto err; + SILC_LOG_DEBUG(("string: %s", silc_buffer_data(&buf))); + if (strcmp("This is foobar", silc_buffer_data(&buf))) + goto err; + + silc_snprintf(string, sizeof(string), "foo\nfoobar\nbarfoofoo\nbar\n\nfoo"); + silc_buffer_set(&buf, string, strlen(string)); + SILC_LOG_DEBUG(("sed 's/foo/bar/g'")); + SILC_LOG_DEBUG(("string: %s", string)); + if (silc_buffer_format(&buf, + SILC_STR_REGEX("foo", SILC_STR_REGEX_NL | + SILC_STR_REGEX_ALL), + SILC_STR_STRING("bar"), + SILC_STR_END, + SILC_STR_END) < 0) + goto err; + SILC_LOG_DEBUG(("string: %s", silc_buffer_data(&buf))); + if (strcmp("bar\nbarbar\nbarbarbar\nbar\n\nbar", silc_buffer_data(&buf))) + goto err; + + silc_snprintf(string, sizeof(string), + "foo\nbazfoobar\nbarfoofoo\nbar\nbaz\nbazfoo"); + silc_buffer_set(&buf, string, strlen(string)); + SILC_LOG_DEBUG(("sed '/baz/s/foo/bar/")); + SILC_LOG_DEBUG(("string: %s", string)); + if (silc_buffer_format(&buf, + SILC_STR_REGEX("baz", SILC_STR_REGEX_NL), + SILC_STR_REGEX("foo", SILC_STR_REGEX_ALL), + SILC_STR_STRING("bar"), + SILC_STR_END, + SILC_STR_END, SILC_STR_END) < 0) + goto err; + SILC_LOG_DEBUG(("string: %s", silc_buffer_data(&buf))); + if (strcmp("foo\nbazbarbar\nbarfoofoo\nbar\nbaz\nbazbar", + silc_buffer_data(&buf))) + goto err; + + silc_snprintf(string, sizeof(string), + "foo\nbazfoobar\nbarfoofoo\nbar\nbaz\nbazfoo"); + silc_buffer_set(&buf, string, strlen(string)); + SILC_LOG_DEBUG(("sed '/baz/!s/foo/bar/")); + SILC_LOG_DEBUG(("string: %s", string)); + if (silc_buffer_format(&buf, + SILC_STR_REGEX("baz", SILC_STR_REGEX_NL | + SILC_STR_REGEX_NOT), + SILC_STR_REGEX("foo", SILC_STR_REGEX_ALL), + SILC_STR_STRING("bar"), + SILC_STR_END, + SILC_STR_END, SILC_STR_END) < 0) + goto err; + SILC_LOG_DEBUG(("string: %s", silc_buffer_data(&buf))); + if (strcmp("bar\nbazfoobar\nbarbarbar\nbar\nbaz\nbazfoo", + silc_buffer_data(&buf))) + goto err; + + SILC_LOG_DEBUG(("Print all lines starting with 'R'")); + silc_snprintf(string, sizeof(string), + "Rfoo\nbazfoobar\nRbarfoofoo\nRbar\nbaz\nRbazfoo"); + silc_buffer_set(&buf, string, strlen(string)); + SILC_LOG_DEBUG(("string: %s", string)); + if (silc_buffer_unformat(&buf, + SILC_STR_REGEX("^R", SILC_STR_REGEX_NL), + SILC_STR_FUNC(print, NULL, NULL), + SILC_STR_END, SILC_STR_END) < 0) + goto err; + + success = TRUE; + + err: + SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE")); + fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE"); + + return success; +} diff --git a/lib/silcutil/tests/test_silcregex.c b/lib/silcutil/tests/test_silcregex.c index 6e79cb0a..ba98bbe0 100644 --- a/lib/silcutil/tests/test_silcregex.c +++ b/lib/silcutil/tests/test_silcregex.c @@ -17,6 +17,28 @@ int main(int argc, char **argv) silc_log_set_debug_string("*regex*,*errno*"); } + regex = "(H..).(o..)"; + SILC_LOG_DEBUG(("Regex %s", regex)); + if (!silc_regex_compile(®, regex, 0)) + goto err; + + string = "Hello World"; + SILC_LOG_DEBUG(("Match %s", string)); + if (!silc_regex_match(®, string, num_match, match, 0)) + goto err; + for (i = 0; i < num_match; i++) { + if (match[i].start != -1) { + SILC_LOG_DEBUG(("Match start %d, end %d", match[i].start, + match[i].end)); + sub = silc_memdup(string + match[i].start, match[i].end - + match[i].start); + SILC_LOG_DEBUG(("Match substring '%s'", sub)); + silc_free(sub); + } + } + + silc_regex_free(®); + regex = "foo[0-9]*"; SILC_LOG_DEBUG(("Regex %s", regex)); if (!silc_regex_compile(®, regex, 0))