From 38b10925eeea619c2b6fa646892df4416e6dd08f Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sat, 5 Jan 2008 16:09:07 +0000 Subject: [PATCH] Added SILC_STR_STRING and SILC_STR_STRING_APPEND and support for appending with SilcBuffer format API. Added silc_buffer_equal. --- CHANGES.RUNTIME | 11 ++ includes/silc.h.in | 2 +- lib/silcutil/silcbuffer.h | 181 +++++++++++++++++++++++++-- lib/silcutil/silcbuffmt.c | 48 +++++-- lib/silcutil/silcbuffmt.h | 44 ++++++- lib/silcutil/silctypes.h | 3 +- lib/silcutil/tests/test_silcbuffmt.c | 21 +++- 7 files changed, 285 insertions(+), 25 deletions(-) diff --git a/CHANGES.RUNTIME b/CHANGES.RUNTIME index cbe2cca6..b04693d6 100644 --- a/CHANGES.RUNTIME +++ b/CHANGES.RUNTIME @@ -1,3 +1,14 @@ +Sat Jan 5 18:00:06 EET 2008 Pekka Riikonen + + * Added silc_buffer_equal to lib/silcutil/silcbuffer.h. + + * Added SILC_STR_STRING and SILC_STR_STRING_APPEND buffer format + macros. Affected files are lib/silcutil/silcbuffmt.[ch]. + + * Added support for matching and appending with SILC_STR_REGEX + and SILC_STR_STRING_APPEND. Affected files are + lib/silcutil/silcbuffmt.[ch]. + Thu Jan 3 18:37:42 EET 2008 Pekka Riikonen * Added SilcStack support to silc_regex and silc_regex_buffer diff --git a/includes/silc.h.in b/includes/silc.h.in index 88fa7d16..669c1343 100644 --- a/includes/silc.h.in +++ b/includes/silc.h.in @@ -255,6 +255,7 @@ extern "C" { #include "silcthread.h" #include "silcschedule.h" #include "silclog.h" +#include "silcfileutil.h" #include "silcbuffer.h" #include "silcbuffmt.h" #include "silcasync.h" @@ -283,7 +284,6 @@ extern "C" { #include "silchashtable.h" #include "silcstream.h" #include "silcnet.h" -#include "silcfileutil.h" #include "silcbase64.h" #include "silcstrutil.h" #include "silcutf8.h" diff --git a/lib/silcutil/silcbuffer.h b/lib/silcutil/silcbuffer.h index 30f11dc3..3a3db7b6 100644 --- a/lib/silcutil/silcbuffer.h +++ b/lib/silcutil/silcbuffer.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1998 - 2007 Pekka Riikonen + Copyright (C) 1998 - 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 @@ -725,6 +725,14 @@ unsigned char *silc_buffer_put_head(SilcBuffer sb, return NULL; } + if (sb->head > data) { + if (sb->head - data <= len) + return (unsigned char *)memmove(sb->head, data, len); + } else { + if (data - sb->head <= len) + return (unsigned char *)memmove(sb->head, data, len); + } + return (unsigned char *)memcpy(sb->head, data, len); } @@ -768,6 +776,14 @@ unsigned char *silc_buffer_put(SilcBuffer sb, return NULL; } + if (sb->data > data) { + if (sb->data - data <= len) + return (unsigned char *)memmove(sb->data, data, len); + } else { + if (data - sb->data <= len) + return (unsigned char *)memmove(sb->data, data, len); + } + return (unsigned char *)memcpy(sb->data, data, len); } @@ -811,6 +827,14 @@ unsigned char *silc_buffer_put_tail(SilcBuffer sb, return NULL; } + if (sb->tail > data) { + if (sb->tail - data <= len) + return (unsigned char *)memmove(sb->tail, data, len); + } else { + if (data - sb->tail <= len) + return (unsigned char *)memmove(sb->tail, data, len); + } + return (unsigned char *)memcpy(sb->tail, data, len); } @@ -1165,14 +1189,8 @@ SilcBuffer silc_buffer_srealloc(SilcStack stack, dlen = silc_buffer_len(sb); h = (unsigned char *)silc_srealloc(stack, silc_buffer_truelen(sb), sb->head, newsize); - if (!h) { - /* Do slow and stack wasting realloc. The old sb->head is lost and - is freed eventually. */ - h = (unsigned char *)silc_smalloc(stack, newsize); - if (silc_unlikely(!h)) - return NULL; - memcpy(h, sb->head, silc_buffer_truelen(sb)); - } + if (!h) + return NULL; sb->head = h; sb->data = sb->head + hlen; @@ -1314,6 +1332,106 @@ SilcBool silc_buffer_senlarge(SilcStack stack, SilcBuffer sb, SilcUInt32 size) return TRUE; } +/****f* silcutil/SilcBufferAPI/silc_buffer_append + * + * SYNOPSIS + * + * static inline + * SilcBuffer silc_buffer_append(SilcBuffer sb, SilcUInt32 size); + * + * DESCRIPTION + * + * Appends the current data area by the amount of `size'. The tail area + * of the buffer remains intact and contains the same data than the old + * tail area (the data is copied to the new tail area). After appending + * there is now `size' bytes more free area in the data area. Returns + * FALSE if system is out of memory. + * + * EXAMPLE + * + * Before appending: + * --------------------------------- + * | head | data | tail | + * --------------------------------- + * + * After appending: + * ------------------------------------ + * | head | data | tail | + * ------------------------------------- + * + * silc_buffer_append(sb, 5); + * + ***/ + +static inline +SilcBool silc_buffer_append(SilcBuffer sb, SilcUInt32 size) +{ + if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) + size))) + return FALSE; + + /* Enlarge data area */ + silc_buffer_pull_tail(sb, size); + + /* Copy old tail area to new tail area */ + silc_buffer_put_tail(sb, sb->tail - size, silc_buffer_taillen(sb)); + + return TRUE; +} + +/****f* silcutil/SilcBufferAPI/silc_buffer_append + * + * SYNOPSIS + * + * static inline + * SilcBool silc_buffer_sappend(SilcStack stack, SilcBuffer sb, + * SilcUInt32 size) + * + * DESCRIPTION + * + * Appends the current data area by the amount of `size'. The tail area + * of the buffer remains intact and contains the same data than the old + * tail area (the data is copied to the new tail area). After appending + * there is now `size' bytes more free area in the data area. Returns + * FALSE if system is out of memory. + * + * This routine use SilcStack are memory source. If `stack' is NULL + * reverts back to normal allocating routine. + * + * Note that this call consumes the `stack'. The caller should push the + * stack before calling the function and pop it later. + * + * EXAMPLE + * + * Before appending: + * --------------------------------- + * | head | data | tail | + * --------------------------------- + * + * After appending: + * ------------------------------------ + * | head | data | tail | + * ------------------------------------- + * + * silc_buffer_append(sb, 5); + * + ***/ + +static inline +SilcBool silc_buffer_sappend(SilcStack stack, SilcBuffer sb, SilcUInt32 size) +{ + if (silc_unlikely(!silc_buffer_srealloc(stack, sb, + silc_buffer_truelen(sb) + size))) + return FALSE; + + /* Enlarge data area */ + silc_buffer_pull_tail(sb, size); + + /* Copy old tail area to new tail area */ + silc_buffer_put_tail(sb, sb->tail - size, silc_buffer_taillen(sb)); + + return TRUE; +} + /****f* silcutil/SilcBufferAPI/silc_buffer_strchr * * SYNOPSIS @@ -1367,4 +1485,49 @@ unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first) return NULL; } +/****f* silcutil/SilcBufferAPI/silc_buffer_cmp + * + * SYNOPSIS + * + * static inline + * SilcBool silc_buffer_equal(SilcBuffer sb1, SilcBuffer sb2) + * + * DESCRIPTION + * + * Compares if the data area of the buffer `sb1' and `sb2' are identical. + * Returns TRUE if they match and FALSE if they differ. + * + ***/ + +static inline +SilcBool silc_buffer_equal(SilcBuffer sb1, SilcBuffer sb2) +{ + if (silc_buffer_len(sb1) != silc_buffer_len(sb2)) + return FALSE; + return memcmp(sb1->data, sb2->data, silc_buffer_len(sb1)) == 0; +} + +/****f* silcutil/SilcBufferAPI/silc_buffer_printf + * + * SYNOPSIS + * + * static inline + * void silc_buffer_printf(SilcBuffer sb, SilcBool newline); + * + * DESCRIPTION + * + * Prints the current data area of `sb' into stdout. If `newline' is + * TRUE prints '\n' after the data in the buffer. + * + ***/ + +static inline +void silc_buffer_printf(SilcBuffer sb, SilcBool newline) +{ + silc_file_write(1, silc_buffer_data(sb), silc_buffer_len(sb)); + if (newline) + printf("\n"); + fflush(stdout); +} + #endif /* SILCBUFFER_H */ diff --git a/lib/silcutil/silcbuffmt.c b/lib/silcutil/silcbuffmt.c index 366c4478..559e7309 100644 --- a/lib/silcutil/silcbuffmt.c +++ b/lib/silcutil/silcbuffmt.c @@ -31,6 +31,16 @@ do { \ flen += req; \ } while(0) +/* Check that buffer has enough room to format data in it, if not + allocate more. This will append, thus not replacing any existing data. */ +#define FORMAT_HAS_SPACE_APPEND(s, b, req) \ +do { \ + if (silc_buffer_len(b) < req) \ + if (silc_unlikely(!silc_buffer_sappend(s, b, req - silc_buffer_len(b)))) \ + goto fail; \ + flen += req; \ +} while(0) + /* Check that there is data to be unformatted */ #define UNFORMAT_HAS_SPACE(b, req) \ do { \ @@ -82,8 +92,8 @@ int silc_buffer_sformat_vp_i(SilcStack stack, SilcBuffer dst, va_list ap, silc_buffer_pull(dst, tmp_len); flen += tmp_len; } + break; } - break; case SILC_PARAM_REGEX: { @@ -93,7 +103,7 @@ int silc_buffer_sformat_vp_i(SilcStack stack, SilcBuffer dst, va_list ap, 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; + SilcUInt32 inclusive_pos = 0; int matched = 0, ret_len; va_list cp; @@ -138,7 +148,7 @@ int silc_buffer_sformat_vp_i(SilcStack stack, SilcBuffer dst, va_list ap, } if (rflags & SILC_STR_REGEX_INCLUSIVE) { - saved_incl = dst->tail; + inclusive_pos = dst->tail - match.tail; dst->tail = match.tail; } @@ -150,7 +160,8 @@ int silc_buffer_sformat_vp_i(SilcStack stack, SilcBuffer dst, va_list ap, goto fail; if (rflags & SILC_STR_REGEX_INCLUSIVE) - dst->tail = saved_incl; + if (!silc_buffer_pull_tail(dst, inclusive_pos)) + goto fail; /* Advance buffer after formatting */ flen += ret_len; @@ -176,8 +187,8 @@ int silc_buffer_sformat_vp_i(SilcStack stack, SilcBuffer dst, va_list ap, /* Skip to the next SILC_PARAM_END */ silc_buffer_sformat_vp_i(NULL, NULL, ap, FALSE); + break; } - break; case SILC_PARAM_UI8_STRING: case SILC_PARAM_UI16_STRING: @@ -194,7 +205,25 @@ int silc_buffer_sformat_vp_i(SilcStack stack, SilcBuffer dst, va_list ap, if (x && tmp_len) { FORMAT_HAS_SPACE(stack, dst, tmp_len); - silc_buffer_put(dst, (unsigned char *)x, tmp_len); + silc_buffer_put(dst, x, tmp_len); + silc_buffer_pull(dst, tmp_len); + } + break; + } + + case SILC_PARAM_UI8_STRING | SILC_PARAM_APPEND: + case SILC_PARAM_UI16_STRING | SILC_PARAM_APPEND: + case SILC_PARAM_UI32_STRING | SILC_PARAM_APPEND: + { + char *x = va_arg(ap, char *); + SilcUInt32 tmp_len = x ? strlen(x) : 0; + + if (!process) + break; + + if (x && tmp_len) { + FORMAT_HAS_SPACE_APPEND(stack, dst, tmp_len); + silc_buffer_put(dst, x, tmp_len); silc_buffer_pull(dst, tmp_len); } break; @@ -513,7 +542,7 @@ int silc_buffer_sunformat_vp_i(SilcStack stack, SilcBuffer src, va_list ap, 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; + SilcUInt32 inclusive_pos = 0; int matched = 0, ret_len; va_list cp; @@ -558,7 +587,7 @@ int silc_buffer_sunformat_vp_i(SilcStack stack, SilcBuffer src, va_list ap, } if (rflags & SILC_STR_REGEX_INCLUSIVE) { - saved_incl = src->tail; + inclusive_pos = src->tail - match.tail; src->tail = match.tail; } @@ -570,7 +599,8 @@ int silc_buffer_sunformat_vp_i(SilcStack stack, SilcBuffer src, va_list ap, goto fail; if (rflags & SILC_STR_REGEX_INCLUSIVE) - src->tail = saved_incl; + if (!silc_buffer_pull_tail(src, inclusive_pos)) + goto fail; /* Advance buffer after formatting */ UNFORMAT_HAS_SPACE(src, ret_len); diff --git a/lib/silcutil/silcbuffmt.h b/lib/silcutil/silcbuffmt.h index 4334dc57..32aa9bb6 100644 --- a/lib/silcutil/silcbuffmt.h +++ b/lib/silcutil/silcbuffmt.h @@ -531,6 +531,41 @@ int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...); ***/ #define SILC_STR_STRING(x) SILC_PARAM_UI8_STRING, (x) +/****d* silcutil/SilcBufferFormatAPI/SILC_STR_STRING_APPEND + * + * NAME + * + * #define SILC_STR_STRING_APPEND() ... + * + * DESCRIPTION + * + * Encode NULL terminated string and append it to the buffer without + * replacing any data if the end of the data area is reached before + * encoding the whole string. If buffer has tail area, it will not be + * replaced if the string is longer than the current data area, but the + * buffer will be enlarged and the tail area will be copied to the new + * tail area in order not to replace any data while appending the string. + * This will then enlarge the current data area. + * + * Use this only for formatting. + * + * Formatting: SILC_STR_STRING_APPEND(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_APPEND 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_APPEND(string), ... + * Unformatting: ..., SILC_STR_UI32_STRING(&string), ... + * + ***/ +#define SILC_STR_STRING_APPEND(x) SILC_PARAM_UI8_STRING | SILC_PARAM_APPEND, (x) + /****d* silcutil/SilcBufferFormatAPI/SILC_STR_*_STRING * * NAME @@ -839,10 +874,13 @@ typedef enum { * SILC_STR_STRING("bar"), * SILC_STR_END, SILC_STR_END); * - * // sed 's/foo/bar/g', replace all foo's with bar + * // sed 's/foo/barbar/g', replace all foo's with barbar, without + * // overwriting any data in the buffer, but appending it. The match + * // must be SILC_STR_REGEX_INCLUSIVE to make appending work. * silc_buffer_format(buffer, - * SILC_STR_REGEX("foo", SILC_STR_REGEX_ALL), - * SILC_STR_STRING("bar"), + * SILC_STR_REGEX("foo", SILC_STR_REGEX_ALL | + * SILC_STR_REGEX_INCLUSIVE), + * SILC_STR_STRING_APPEND("barbar"), * SILC_STR_END, SILC_STR_END); * * // sed '/baz/s/foo/bar/g, replace all foo's with bar on lines with baz diff --git a/lib/silcutil/silctypes.h b/lib/silcutil/silctypes.h index a4a06d9e..f060a3e0 100644 --- a/lib/silcutil/silctypes.h +++ b/lib/silcutil/silctypes.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2002 - 2007 Pekka Riikonen + Copyright (C) 2002 - 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 @@ -312,6 +312,7 @@ typedef SilcUInt32 SilcParam; #define SILC_PARAM_REGEX 109 #define SILC_PARAM_OFFSET_START 110 #define SILC_PARAM_OFFSET_END 111 +#define SILC_PARAM_APPEND 112 #define SILC_PARAM_ALLOC 0x00010000 /* Allocate, bitmask */ /* Macros */ diff --git a/lib/silcutil/tests/test_silcbuffmt.c b/lib/silcutil/tests/test_silcbuffmt.c index dba97fd0..16c4483c 100644 --- a/lib/silcutil/tests/test_silcbuffmt.c +++ b/lib/silcutil/tests/test_silcbuffmt.c @@ -14,8 +14,8 @@ int print(SilcStack stack, SilcBuffer buf, void *value, void *context) int main(int argc, char **argv) { SilcBool success = FALSE; - char string[1024]; - SilcBufferStruct buf; + char string[1024], *astring; + SilcBufferStruct buf, buf2; if (argc > 1 && !strcmp(argv[1], "-d")) { silc_log_debug(TRUE); @@ -38,6 +38,23 @@ int main(int argc, char **argv) if (strcmp("This is barbar", silc_buffer_data(&buf))) goto err; + silc_snprintf(string, sizeof(string), "This is foobar string!!"); + astring = silc_memdup(string, strlen(string)); + silc_buffer_set(&buf, astring, strlen(astring) + 1); + SILC_LOG_DEBUG(("sed 's/foo/barbar/g'")); + SILC_LOG_DEBUG(("string: %s", astring)); + if (silc_buffer_format(&buf, + SILC_STR_REGEX("foo", SILC_STR_REGEX_ALL | + SILC_STR_REGEX_INCLUSIVE), + SILC_STR_STRING_APPEND("barbar"), + SILC_STR_END, + SILC_STR_END) < 0) + goto err; + silc_buffer_printf(&buf, TRUE); + if (strcmp("This is barbarbar string!!", silc_buffer_data(&buf))) + goto err; + silc_buffer_purge(&buf); + silc_snprintf(string, sizeof(string), "This is foobar\n"); silc_buffer_set(&buf, string, strlen(string)); SILC_LOG_DEBUG(("sed 's/\\n/\\0/'")); -- 2.24.0