head 1.53; access; symbols LMTP2NNTP_1_4_1:1.53 LMTP2NNTP_1_4_0:1.53 VAR_1_1_3:1.53 VAR_1_1_2:1.51 VAR_1_1_1:1.50 LMTP2NNTP_1_3_0:1.50 LMTP2NNTP_1_3b2:1.50 LMTP2NNTP_1_3b1:1.50 LMTP2NNTP_1_3a3:1.50 LMTP2NNTP_1_3a2:1.50 LMTP2NNTP_1_3a1:1.50 VAR_1_1_0:1.50 VAR_1_0_0:1.48 LMTP2NNTP_1_2_0:1.47 LMTP2NNTP_1_2b4:1.47 LMTP2NNTP_1_2b3:1.47 LMTP2NNTP_1_2b2:1.47 LMTP2NNTP_1_2b1:1.45 LMTP2NNTP_1_2a8:1.45 LMTP2NNTP_1_2a7:1.45 LMTP2NNTP_1_2a6:1.45 LMTP2NNTP_1_2a5:1.45 LMTP2NNTP_1_2a4:1.45 VAR_0_9_0:1.45 LMTP2NNTP_1_2a3:1.40 OSSP_RC_SPEC:1.32; locks; strict; comment @ * @; 1.53 date 2005.10.02.16.58.31; author rse; state Exp; branches; next 1.52; 1.52 date 2005.01.20.20.29.06; author rse; state Exp; branches; next 1.51; 1.51 date 2004.10.29.19.42.20; author rse; state Exp; branches; next 1.50; 1.50 date 2004.04.04.08.07.34; author rse; state Exp; branches; next 1.49; 1.49 date 2003.10.25.19.56.07; author rse; state Exp; branches; next 1.48; 1.48 date 2003.02.14.21.17.07; author rse; state Exp; branches; next 1.47; 1.47 date 2003.02.10.15.37.15; author rse; state Exp; branches; next 1.46; 1.46 date 2003.02.10.15.27.54; author rse; state Exp; branches; next 1.45; 1.45 date 2002.03.08.12.57.16; author rse; state Exp; branches; next 1.44; 1.44 date 2002.03.07.14.58.41; author rse; state Exp; branches; next 1.43; 1.43 date 2002.03.07.12.11.09; author rse; state Exp; branches; next 1.42; 1.42 date 2002.03.07.09.14.05; author rse; state Exp; branches; next 1.41; 1.41 date 2002.03.06.11.09.12; author rse; state Exp; branches; next 1.40; 1.40 date 2002.03.04.12.01.53; author rse; state Exp; branches; next 1.39; 1.39 date 2002.03.04.11.53.27; author rse; state Exp; branches; next 1.38; 1.38 date 2002.02.28.20.27.05; author rse; state Exp; branches; next 1.37; 1.37 date 2002.02.28.12.40.01; author thl; state Exp; branches; next 1.36; 1.36 date 2002.02.28.09.29.48; author rse; state Exp; branches; next 1.35; 1.35 date 2002.02.28.08.48.44; author rse; state Exp; branches; next 1.34; 1.34 date 2002.02.28.08.08.16; author rse; state Exp; branches; next 1.33; 1.33 date 2002.02.27.13.44.16; author rse; state Exp; branches; next 1.32; 1.32 date 2002.01.09.11.23.01; author rse; state Exp; branches; next 1.31; 1.31 date 2002.01.09.11.17.20; author rse; state Exp; branches; next 1.30; 1.30 date 2002.01.02.17.12.18; author rse; state Exp; branches; next 1.29; 1.29 date 2001.12.17.10.29.43; author rse; state Exp; branches; next 1.28; 1.28 date 2001.12.16.23.40.16; author rse; state Exp; branches; next 1.27; 1.27 date 2001.12.14.13.49.40; author rse; state Exp; branches; next 1.26; 1.26 date 2001.12.14.13.47.01; author rse; state Exp; branches; next 1.25; 1.25 date 2001.12.13.16.03.42; author simons; state Exp; branches; next 1.24; 1.24 date 2001.12.12.17.18.55; author simons; state Exp; branches; next 1.23; 1.23 date 2001.12.12.16.51.20; author simons; state Exp; branches; next 1.22; 1.22 date 2001.12.08.16.28.41; author simons; state Exp; branches; next 1.21; 1.21 date 2001.12.08.16.27.57; author simons; state Exp; branches; next 1.20; 1.20 date 2001.12.08.16.17.56; author simons; state Exp; branches; next 1.19; 1.19 date 2001.12.08.16.02.15; author simons; state Exp; branches; next 1.18; 1.18 date 2001.12.08.15.31.06; author simons; state Exp; branches; next 1.17; 1.17 date 2001.12.08.15.14.33; author simons; state Exp; branches; next 1.16; 1.16 date 2001.12.04.13.35.58; author simons; state Exp; branches; next 1.15; 1.15 date 2001.12.03.10.51.27; author simons; state Exp; branches; next 1.14; 1.14 date 2001.11.20.15.46.35; author simons; state Exp; branches; next 1.13; 1.13 date 2001.11.20.11.49.24; author simons; state Exp; branches; next 1.12; 1.12 date 2001.11.20.11.41.54; author simons; state Exp; branches; next 1.11; 1.11 date 2001.11.14.15.55.09; author ms; state Exp; branches; next 1.10; 1.10 date 2001.11.14.12.21.15; author ms; state Exp; branches; next 1.9; 1.9 date 2001.11.14.11.11.01; author rse; state Exp; branches; next 1.8; 1.8 date 2001.11.14.10.47.17; author ms; state Exp; branches; next 1.7; 1.7 date 2001.11.13.14.42.57; author simons; state Exp; branches; next 1.6; 1.6 date 2001.11.13.14.36.55; author simons; state Exp; branches; next 1.5; 1.5 date 2001.11.13.13.33.28; author simons; state Exp; branches; next 1.4; 1.4 date 2001.11.13.13.29.50; author simons; state Exp; branches; next 1.3; 1.3 date 2001.11.13.13.25.18; author simons; state Exp; branches; next 1.2; 1.2 date 2001.11.13.12.46.50; author simons; state Exp; branches; next 1.1; 1.1 date 2001.11.13.12.08.30; author simons; state Exp; branches; next ; desc @@ 1.53 log @Fix some sprintf(3) parameter passing. @ text @/* ** OSSP var -- Variable Expansion ** Copyright (c) 2001-2005 Ralf S. Engelschall ** Copyright (c) 2001-2005 The OSSP Project (http://www.ossp.org/) ** Copyright (c) 2001-2005 Cable & Wireless (http://www.cw.com/) ** ** This file is part of OSSP var, a variable expansion ** library which can be found at http://www.ossp.org/pkg/lib/var/. ** ** Permission to use, copy, modify, and distribute this software for ** any purpose with or without fee is hereby granted, provided that ** the above copyright notice and this permission notice appear in all ** copies. ** ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. ** ** var_test.c: library regression test */ #include #include #include #include #include #include "config.h" #if defined(HAVE_DMALLOC_H) && defined(WITH_DMALLOC) #include #endif #include "var.h" #include "ts.h" /* ** ** ==== VARIABLE LOOKUP CALLBACK ==== ** */ struct variable { const char *name; const unsigned int idx; const char *data; }; static const struct variable lookup_vars[] = { { "ARRAY", 0, "entry0" }, { "ARRAY", 1, "entry1" }, { "ARRAY", 2, "entry2" }, { "ARRAY", 3, "entry3" }, { "BAR", 0, "type" }, { "EMPTY", 0, "" }, { "FOO", 0, "os" }, { "HEINZ", 0, "heinz0" }, { "HEINZ", 1, "heinz1" }, { "HOME", 0, "/home/regression-tests" }, { "MULTILINE", 0, "line1\nline2\n" }, { "NUMBER", 0, "+2" }, { "NUMEXP", 0, "((16)%5)" }, { "OSTYPE", 0, "regression-os" }, { "TERM", 0, "regression-term" }, { NULL, 0, NULL } }; static var_rc_t lookup_cb( var_t *var, void *context, const char *varname, size_t name_len, int idx, const char **data, size_t *data_len, size_t *buffer_size) { const struct variable *vars = context; size_t i, counter, length; static char buf[((sizeof(int)*8)/3)+10]; /* sufficient size: <#bits> x log_10(2) + safety */ if (idx >= 0) { for (i = 0; vars[i].name; ++i) { if (strncmp(varname, vars[i].name, name_len) == 0 && vars[i].idx == idx) { *data = vars[i].data; *data_len = strlen(*data); *buffer_size = 0; return VAR_OK; } } } else { for (i = 0; vars[i].name; ++i) { if (strncmp(varname, vars[i].name, name_len) == 0) { counter = 1; length = strlen(vars[i].data); while ( vars[i + counter].data && strncmp(varname, vars[i + counter].name, name_len) == 0) counter++; if (counter == 1) sprintf(buf, "%d", (int)length); else sprintf(buf, "%d", (int)counter); *data = buf; *data_len = strlen(buf); *buffer_size = 0; return VAR_OK; } } } return VAR_ERR_UNDEFINED_VARIABLE; } /* ** ** ==== OPERATION CALLBACK ==== ** */ static var_rc_t operate_cb( var_t *var, void *ctx, const char *op_ptr, size_t op_len, const char *arg_ptr, size_t arg_len, const char *val_ptr, size_t val_len, char **out_ptr, size_t *out_len, size_t *out_size) { int i; if (val_ptr == NULL) { *out_ptr = ""; *out_len = 0; *out_size = 0; return VAR_OK; } if (op_len == 6 && strncmp(op_ptr, "return", 6) == 0) { *out_ptr = malloc(arg_len); *out_len = arg_len; *out_size = arg_len; memcpy(*out_ptr, arg_ptr, arg_len); return VAR_OK; } else if (op_len == 5 && strncmp(op_ptr, "upper", 5) == 0) { *out_ptr = malloc(val_len); *out_len = val_len; *out_size = val_len; for (i = 0; i < val_len; i++) (*out_ptr)[i] = (char)toupper((int)(val_ptr[i])); return VAR_OK; } else if (op_len == 5 && strncmp(op_ptr, "lower", 5) == 0) { *out_ptr = malloc(val_len); *out_len = val_len; *out_size = val_len; for (i = 0; i < val_len; i++) (*out_ptr)[i] = (char)tolower((int)(val_ptr[i])); return VAR_OK; } else return VAR_ERR_UNDEFINED_OPERATION; } /* ** ** ==== TEST CASES ==== ** */ TS_TEST(test_expand) { struct test_case { const char *input; const char *expected; }; const struct test_case tests[] = { { "${HOME}${!!}", "/home/regression-tests${!!}" }, { "$HOME", "/home/regression-tests" }, { "${FOO}", "os" }, { "${BAR}", "type" }, { "${${FOO:u}${BAR:u}:l:u}", "REGRESSION-OS" }, { "${UNDEFINED}", "${UNDEFINED}" }, { "${OSTYPE:#}", "13" }, { "${EMPTY:-test${FOO}test}", "testostest" }, { "${EMPTY:-test${FOO:u}test}", "testOStest" }, { "${TERM:-test${FOO}test}", "regression-term" }, { "${EMPTY:+FOO}", "" }, { "${HOME:+test${FOO}test}", "testostest" }, { "${HOME:+${OS${BAR:u}}}", "regression-os" }, { "${HOME:+OS${UNDEFINED:u}}", "OS${UNDEFINED:u}" }, { "${UNDEFINED:+OS${BAR:u}}", "${UNDEFINED:+OS${BAR:u}}" }, { "${HOME:*heinz}", "" }, { "${EMPTY:*claus}", "claus" }, { "${TERM}", "regression-term" }, { "${HOME:s/reg/bla/}", "/home/blaression-tests" }, { "${HOME:s/e/bla/}", "/hombla/regression-tests" }, { "${HOME:s/e/bla/g}", "/hombla/rblagrblassion-tblasts" }, { "${HOME:s/\\//_/g}", "_home_regression-tests" }, { "${HOME:s/[eso]/_/g}", "/h_m_/r_gr___i_n-t__t_" }, { "${HOME:s/[esO]/_/g}", "/hom_/r_gr___ion-t__t_" }, { "${HOME:s/[esO]/_/gi}", "/h_m_/r_gr___i_n-t__t_" }, { "${OSTYPE:s/^[re]/_/g}", "_egression-os" }, { "${EMPTY:s/^[re]/_/g}", "" }, { "${HOME:s/.*\\x{}/heinz/}", "heinz" }, { "${HOME:s/e/bla/t}", "/hombla/regression-tests" }, { "${HOME:s/E/bla/t}", "/home/regression-tests" }, { "${HOME:s/E/bla/ti}", "/hombla/regression-tests" }, { "${HOME:s/E/bla/tig}", "/hombla/rblagrblassion-tblasts" }, { "${HOME:s/^(.*)$/<\\1>/}", "" }, { "${HOME:o1-5}", "home/" }, { "${HOME:o1,5}", "home/" }, { "${HOME:o5,}", "/regression-tests" }, { "${HOME:o5-}", "/regression-tests" }, { "${HOME:o7,13}", "egressi" }, { "${HOME:y/a-z/A-YZ/}", "/HOME/REGRESSION-TESTS" }, { "${HOME:y/e-g/a-c/}", "/homa/racrassion-tasts" }, { "${FOO:p/15/../l}", "os............." }, { "${FOO:p/15/12345/l}", "os1234512345123" }, { "${FOO:p/15/../r}", ".............os" }, { "${FOO:p/15/12345/r}", "1234512345123os" }, { "${FOO:p/15/../c}", "......os......." }, { "${FOO:p/15/12345/c}", "123451os1234512" }, { "${FOO:s/os/\\x{4F}\\123/g}", "OS" }, { "${FOO:s/os/\\1\\x4F\\123/t}", "\\1OS" }, { "${HOME:s/g(res)s/x\\1x/g}", "/home/rexresxion-tests" }, { "${HOME:s/(s+)/_\\1_/g}", "/home/regre_ss_ion-te_s_t_s_" }, { "${HOME:s/\\x65/\\x45/g}", "/homE/rEgrEssion-tEsts" }, { "${HOME:s/(s*)/x\\1X/g}", "xX/xXhxXoxXmxXexX/xXrxXexXgxXrxXexssXxXixXoxXnxX-xXtxXexsXxXtxsX" }, { "${HOME:s/./\\\\/g}", "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" }, { "${ARRAY[1]}", "entry1", }, { "${ARRAY[5+4*2-1]}", "${ARRAY[5+4*2-1]}", }, { "${ARRAY[(5+(3+4)*2)%16]}", "entry3", }, { "${ARRAY[(5+(3+4)*2)/9]}", "entry2", }, { "${ARRAY[+1--2]}", "entry3" }, { "${ARRAY[-1]}", "4" }, { "${HOME[-1]}", "22" }, { "${ARRAY[$NUMBER]}", "entry2" }, { "${ARRAY[$NUMEXP]}", "entry1" }, { "${ARRAY[$NUMEXP-1]}", "entry0" }, { "${ARRAY[${UNDEFINED}-1]}", "${ARRAY[${UNDEFINED}-1]}" }, { "${ARRAY[5/(${UNDEFINED})]}", "${ARRAY[5/(${UNDEFINED})]}" }, { "[${ARRAY[#]}-]", "entry0-entry1-entry2-entry3-" }, { "[${ARRAY[#+1]}-]", "entry1-entry2-entry3-" }, { "-[${ARRAY[#]}:]{1,$NUMBER}-", "-entry1:entry2:-" }, { "-[${ARRAY[#]}:]{1,3,5}-", "-entry1::-" }, { "${MULTILINE:s/^/ | /gm}", " | line1\n | line2\n" }, { "${HOME:%upper}", "/HOME/REGRESSION-TESTS" }, { "${HOME:%upper:%lower}", "/home/regression-tests" }, { "${EMPTY:%return($HOME)}", "/home/regression-tests" }, { "[${ARRAY}:${ARRAY[#]}-]", "entry0:entry0-entry0:entry1-entry0:entry2-entry0:entry3-" }, { "[${HEINZ[#]}:${ARRAY[#]}-]", "heinz0:entry0-heinz1:entry1-:entry2-:entry3-" }, { "[${HEINZ[#]}:[${ARRAY[#]}] ]", "heinz0:entry0entry1entry2entry3 heinz1:entry0entry1entry2entry3 " }, { "[${HEINZ[#]}: [${ARRAY[#]}${ARRAY[#+1]:+, }]${HEINZ[#+1]:+; }]", "heinz0: entry0, entry1, entry2, entry3; heinz1: entry0, entry1, entry2, entry3" }, { "[${ARRAY[#]}:[${ARRAY[#]},]{1,2,} ]{0,2,}", "entry0:entry1,entry3, entry2:entry1,entry3, " }, }; char *tmp; size_t tmp_len; var_rc_t rc; size_t i; char buffer[1024]; var_t *var; char *err; ts_test_check(TS_CTX, "create environment"); if ((rc = var_create(&var)) != VAR_OK) { var_strerror(NULL, rc, &err); ts_test_fail(TS_CTX, "var_create: %s (%d)", err, rc); return; } if ((rc = var_config(var, VAR_CONFIG_CB_VALUE, lookup_cb, lookup_vars)) != VAR_OK) { var_strerror(NULL, rc, &err); ts_test_fail(TS_CTX, "var_config: %s (%d)", err, rc); return; } if ((rc = var_config(var, VAR_CONFIG_CB_OPERATION, operate_cb, NULL)) != VAR_OK) { var_strerror(NULL, rc, &err); ts_test_fail(TS_CTX, "var_config: %s (%d)", err, rc); return; } for (i = 0; i < sizeof(tests)/sizeof(struct test_case); i++) { ts_test_check(TS_CTX, "expansion (#%d): raw input \"%s\"", i, tests[i].input); rc = var_unescape(var, tests[i].input, strlen(tests[i].input), buffer, sizeof(buffer), 0); if (rc != VAR_OK) { var_strerror(var, rc, &err); ts_test_fail(TS_CTX, "var_unescape: %s (%d)", err, rc); continue; } ts_test_check(TS_CTX, "expansion (#%d): unescaped input \"%s\"", i, buffer); rc = var_expand(var, buffer, strlen(buffer), &tmp, &tmp_len, 0); if (rc != VAR_OK) { var_strerror(var, rc, &err); ts_test_fail(TS_CTX, "var_expand: %s (%d)", err, rc); continue; } ts_test_check(TS_CTX, "expansion (#%d): expanded output \"%s\"", i, tmp); if ( tmp_len != strlen(tests[i].expected) || memcmp(tests[i].expected, tmp, tmp_len) != 0) { ts_test_fail(TS_CTX, "expected \"%s\", got \"%s\"", tests[i].expected, tmp); free(tmp); continue; } free(tmp); } var_destroy(var); return; } TS_TEST(test_format) { var_rc_t rc; var_t *var; char *err; char *fmt; char *expect; char *got; ts_test_check(TS_CTX, "create environment"); if ((rc = var_create(&var)) != VAR_OK) { var_strerror(NULL, rc, &err); ts_test_fail(TS_CTX, "var_create: %s (%d)", err, rc); return; } if ((rc = var_config(var, VAR_CONFIG_CB_VALUE, lookup_cb, lookup_vars)) != VAR_OK) { var_strerror(NULL, rc, &err); ts_test_fail(TS_CTX, "var_config: %s (%d)", err, rc); return; } /* check trivial formatting */ fmt = "foo"; expect = "foo"; ts_test_check(TS_CTX, "formatting \"%s\"", fmt); if ((rc = var_format(var, &got, 1, fmt)) != VAR_OK) { var_strerror(var, rc, &err); ts_test_fail(TS_CTX, "var_format: %s (%d)", err, rc); return; } if (strcmp(got, expect) != 0) { ts_test_fail(TS_CTX, "var_format: expected \"%s\", got \"%s\"\n", expect, got); free(got); return; } free(got); /* check real formatting */ fmt = "foo<%s><%d><%c>quux"; expect = "foo<123>quux"; ts_test_check(TS_CTX, "formatting \"%s\"", fmt); if ((rc = var_format(var, &got, 1, fmt, "bar", 123, 'x')) != VAR_OK) { var_strerror(var, rc, &err); ts_test_fail(TS_CTX, "var_format: %s (%d)", err, rc); return; } if (strcmp(got, expect) != 0) { ts_test_fail(TS_CTX, "var_format: expected \"%s\", got \"%s\"\n", expect, got); free(got); return; } free(got); /* check combined formatting and expansion */ fmt = "foo<${ARRAY[%d]}>bar"; expect = "foobar"; ts_test_check(TS_CTX, "formatting \"%s\"", fmt); if ((rc = var_format(var, &got, 1, fmt, 1)) != VAR_OK) { var_strerror(var, rc, &err); ts_test_fail(TS_CTX, "var_format: %s (%d)", err, rc); return; } if (strcmp(got, expect) != 0) { ts_test_fail(TS_CTX, "var_format: expected \"%s\", got \"%s\"\n", expect, got); free(got); return; } free(got); var_destroy(var); } int main(int argc, char *argv[]) { ts_suite_t *ts; int n; ts = ts_suite_new("OSSP var (Variable Expansion)"); ts_suite_test(ts, test_expand, "expansion"); ts_suite_test(ts, test_format, "formatting"); n = ts_suite_run(ts); ts_suite_free(ts); return n; } @ 1.52 log @Bumped year in copyright messages for new year 2005 @ text @d105 1 a105 1 sprintf(buf, "%d", length); d107 1 a107 1 sprintf(buf, "%d", counter); @ 1.51 log @o Various code comment cleanups. o Fixed dmalloc support. @ text @d3 3 a5 3 ** Copyright (c) 2001-2004 Ralf S. Engelschall ** Copyright (c) 2001-2004 The OSSP Project (http://www.ossp.org/) ** Copyright (c) 2001-2004 Cable & Wireless (http://www.cw.com/) @ 1.50 log @adjust copyrights @ text @d32 1 d39 1 a39 1 #include "dmalloc.h" @ 1.49 log @use 'expect' instead of 'exp' because most systems have a exp(3) function and so the symbols shadow @ text @d3 3 a5 3 ** Copyright (c) 2001-2003 Ralf S. Engelschall ** Copyright (c) 2001-2003 The OSSP Project (http://www.ossp.org/) ** Copyright (c) 2001-2003 Cable & Wireless Deutschland (http://www.cw.com/de/) @ 1.48 log @final polishing for release 1.0.0 @ text @d320 1 a320 1 char *exp; d337 1 a337 1 exp = "foo"; d344 2 a345 2 if (strcmp(got, exp) != 0) { ts_test_fail(TS_CTX, "var_format: expected \"%s\", got \"%s\"\n", exp, got); d353 1 a353 1 exp = "foo<123>quux"; d360 2 a361 2 if (strcmp(got, exp) != 0) { ts_test_fail(TS_CTX, "var_format: expected \"%s\", got \"%s\"\n", exp, got); d369 1 a369 1 exp = "foobar"; d376 2 a377 2 if (strcmp(got, exp) != 0) { ts_test_fail(TS_CTX, "var_format: expected \"%s\", got \"%s\"\n", exp, got); @ 1.47 log @cosmetics: strip trailing whitespaces @ text @d3 3 a5 3 ** Copyright (c) 2001-2002 Ralf S. Engelschall ** Copyright (c) 2001-2002 The OSSP Project (http://www.ossp.org/) ** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) @ 1.46 log @fix memory leak in OSSP var test suite (under error conditions only) @ text @d123 1 a123 1 static var_rc_t d162 1 a162 1 else d253 1 a253 1 { "[${HEINZ[#]}:${ARRAY[#]}-]", "heinz0:entry0-heinz1:entry1-:entry2-:entry3-" }, d285 1 a285 1 rc = var_unescape(var, tests[i].input, strlen(tests[i].input), @ 1.45 log @more copyright/license polishing @ text @d346 1 d362 1 d378 1 @ 1.44 log @- use our standard ts.[ch] test suite library - add support for Dmalloc facility @ text @d3 1 d28 1 a28 1 ** var_test.c: library regression test. @ 1.43 log @New API functions var_format and var_formatv which provide a convinience interface to printf-style expansion and variable expansion. var_format is like a combination of snprintf(3) and var_expand(). Example: Assume the variable value context gives "bar" for ${ARRAY[7]}, then the call.. var_format(var, &tmp, 1, "foo${ARRAY[%d]}quux", 7);o ..results in tmp containing the malloc(3)'ed string "foobarquux". Thanks to Thomas L. for providing the hint to this functionality. @ text @d35 5 d41 1 d43 5 a47 42 static var_rc_t var_operation( var_t *var, void *ctx, const char *op_ptr, size_t op_len, const char *arg_ptr, size_t arg_len, const char *val_ptr, size_t val_len, char **out_ptr, size_t *out_len, size_t *out_size) { int i; if (val_ptr == NULL) { *out_ptr = ""; *out_len = 0; *out_size = 0; return VAR_OK; } if (op_len == 6 && strncmp(op_ptr, "return", 6) == 0) { *out_ptr = malloc(arg_len); *out_len = arg_len; *out_size = arg_len; memcpy(*out_ptr, arg_ptr, arg_len); return VAR_OK; } else if (op_len == 5 && strncmp(op_ptr, "upper", 5) == 0) { *out_ptr = malloc(val_len); *out_len = val_len; *out_size = val_len; for (i = 0; i < val_len; i++) (*out_ptr)[i] = (char)toupper((int)(val_ptr[i])); return VAR_OK; } else if (op_len == 5 && strncmp(op_ptr, "lower", 5) == 0) { *out_ptr = malloc(val_len); *out_len = val_len; *out_size = val_len; for (i = 0; i < val_len; i++) (*out_ptr)[i] = (char)tolower((int)(val_ptr[i])); return VAR_OK; } else return VAR_ERR_UNDEFINED_OPERATION; } d55 20 a74 1 static var_rc_t var_lookup( d116 5 a120 4 struct test_case { const char *input; const char *expected; }; d122 7 a128 1 int main(int argc, char **argv) d130 1 a130 18 const struct variable vars[] = { { "ARRAY", 0, "entry0" }, { "ARRAY", 1, "entry1" }, { "ARRAY", 2, "entry2" }, { "ARRAY", 3, "entry3" }, { "BAR", 0, "type" }, { "EMPTY", 0, "" }, { "FOO", 0, "os" }, { "HEINZ", 0, "heinz0" }, { "HEINZ", 1, "heinz1" }, { "HOME", 0, "/home/regression-tests" }, { "MULTILINE", 0, "line1\nline2\n" }, { "NUMBER", 0, "+2" }, { "NUMEXP", 0, "((16)%5)" }, { "OSTYPE", 0, "regression-os" }, { "TERM", 0, "regression-term" }, { NULL, 0, NULL } }; d132 45 d251 5 a255 20 { "[${ARRAY}:${ARRAY[#]}-]", "entry0:entry0-entry0:entry1-entry0:entry2-entry0:entry3-" }, { "[${HEINZ[#]}:${ARRAY[#]}-]", "heinz0:entry0-heinz1:entry1-:entry2-:entry3-" }, { "[${HEINZ[#]}:[${ARRAY[#]}] ]", "heinz0:entry0entry1entry2entry3 heinz1:entry0entry1entry2entry3 " }, { "[${HEINZ[#]}: [${ARRAY[#]}${ARRAY[#+1]:+, }]${HEINZ[#+1]:+; }]", "heinz0: entry0, entry1, entry2, entry3; heinz1: entry0, entry1, entry2, entry3" }, { "[${ARRAY[#]}:[${ARRAY[#]},]{1,2,} ]{0,2,}", "entry0:entry1,entry3, entry2:entry1,entry3, " }, d265 1 d268 2 a269 2 printf("unable to create variable expansion context: %s (%d)\n", err, rc); return 1; d271 1 a271 1 if ((rc = var_config(var, VAR_CONFIG_CB_VALUE, var_lookup, vars)) != VAR_OK) { d273 2 a274 2 printf("unable to configure variable expansion context: %s (%d)\n", err, rc); return 1; d276 1 a276 1 if ((rc = var_config(var, VAR_CONFIG_CB_OPERATION, var_operation, NULL)) != VAR_OK) { d278 2 a279 2 printf("unable to configure variable expansion context: %s (%d)\n", err, rc); return 1; d282 4 a285 3 for (i = 0; i < sizeof(tests)/sizeof(struct test_case); ++i) { printf("Test case #%02d: Original input is '%s'.\n", i, tests[i].input); rc = var_unescape(var, tests[i].input, strlen(tests[i].input), buffer, sizeof(buffer), 0); d288 2 a289 2 printf("Test case #%02d: var_unescape() failed: %s (%d)\n", i, err, rc); return 1; d291 1 a291 1 printf("Test case #%02d: Unescaped input is '%s'.\n", i, buffer); d295 2 a296 2 printf("Test case #%02d: var_expand() failed: %s (%d).\n", i, err, rc); return 1; d298 1 a298 1 printf("Test case #%02d: Expanded output is '%s'.\n", i, tmp); a299 1 || tmp == NULL d301 3 a303 3 printf("Test case #%02d: Expected result '%s' but got '%s'.\n", i, tests[i].expected, tmp); return 1; d308 19 a326 5 fprintf(stderr, "Test case: formatting \"foo\"\n"); if ((rc = var_format(var, &tmp, 1, "foo")) != VAR_OK) { var_strerror(var, rc, &err); fprintf(stderr, "Formatting failed: %s (%d)\n", err, rc); return 1; d328 4 a331 3 if (strcmp(tmp, "foo") != 0) { fprintf(stderr, "Formatting failed: expected \"foo\", got \"%s\"\n", tmp); return 1; a332 1 free(tmp); d334 5 a338 2 fprintf(stderr, "Test case: formatting \"foo<123>\"\n"); if ((rc = var_format(var, &tmp, 1, "foo<%s><%d><%c>", "bar", 123, 'x')) != VAR_OK) { d340 2 a341 2 fprintf(stderr, "Formatting failed: %s (%d)\n", err, rc); return 1; d343 14 a356 3 if (strcmp(tmp, "foo<123>") != 0) { fprintf(stderr, "Formatting failed: expected \"foo<123>\", got \"%s\"\n", tmp); return 1; d358 11 a368 4 free(tmp); fprintf(stderr, "Test case: formatting \"foo${ARRAY[1]}bar\"\n"); if ((rc = var_format(var, &tmp, 1, "foo${ARRAY[%d]}bar", 1)) != VAR_OK) { d370 2 a371 2 fprintf(stderr, "Formatting failed: %s (%d)\n", err, rc); return 1; d373 3 a375 3 if (strcmp(tmp, "fooentry1bar") != 0) { fprintf(stderr, "Formatting failed: expected \"fooentry1bar\", got \"%s\"\n", tmp); return 1; d377 1 a377 1 free(tmp); d380 13 a392 1 return 0; @ 1.42 log @Major bugfixing and enhancing of search & replace operation: - finally fix ${name:s/$/foo/} type substitutions (zero-length matching!) - add s/.../.../mg matching support (Perl-style multiline) - make non-multiline matching the default @ text @d298 37 @ 1.41 log @cleanup output of test suite @ text @d224 1 a224 1 { "${MULTILINE:s/^/ | /g}", " | line1\n | line2\n" }, @ 1.40 log @Fix regex problem by no longer allowing variables in the pattern part of s/pattern/subst/. Because it is far more common that one needs '$' there instead of a variable. @ text @a46 2 fprintf(stderr, "op=<%s>(%d) arg=<%s>(%d) val=<%s>(%d)\n", op_ptr, op_len, arg_ptr, arg_len, val_ptr, val_len); d274 1 a274 2 printf("Test case #%02d: Original input is '%s'.\n", i, tests[i].input); d278 1 a278 1 printf("Test case #%d: var_unescape() failed: %s (%d)\n", i, err, rc); d285 1 a285 1 printf("Test case #%d: var_expand() failed: %s (%d).\n", i, err, rc); d292 1 a292 1 printf("Test case #%d: Expected result '%s' but got '%s'.\n", @ 1.39 log @Add new important feature: user-supplied post-operation functions. This allows one to configure a var_cb_operation_t callback in the var_t context and allow it to implement functions triggered by ${name:%func[(arg)]}. This is especially intended for application-specific encoding and post-adjustment functions. @ text @d189 1 @ 1.38 log @always print on testing, not just on debugging @ text @d33 1 d37 45 d226 3 d264 5 @ 1.37 log @prepare for API finally passing "val_t *" to callback, currently pass NULL @ text @a64 3 #ifdef DEBUG printf("Found variable at index %d.\n", i); #endif a220 1 #ifdef DEBUG a222 1 #endif a228 1 #ifdef DEBUG a229 1 #endif a235 1 #ifdef DEBUG a236 1 #endif @ 1.36 log @Try to solve the expansion problem with invalid name characters we encountered in OSSP lmtp2nntp if we expand in two passed with different name character sets. We want that the variable constructs which are not valid in the first pass to be correctly kept (assuming deactivated force_expand!) instead of an error produced. According to Peter Simons, this might be not the correct solution, although THL and RSE are sure it is, because we tried it in detail and it seems to be correct. Nevertheless Peter's comment (in german) for reference: | Ich weiß nicht, ob das unbedingt eine gute Idee ist? Der Fehler | "incomplete variable spec" wird immer dann ausgelöst, wenn innerhalb | der "${...}"-Umgebung ein Zeichen auftritt, das dort nicht sein | dürfte. Einmal kommt das natürlich vor, wenn die gültigen Zeichen für | Variablen von Pass 1 zu Pass 2 verschieden sind ... Aber eine andere | Ursache kann auch sein, daß beispielsweise die schließende "}"-Klammer | fehlt. | | IMHO ist die Tatsache, daß libvar an dieser Stelle einen Fehler | liefert kein Softwarefehler, sondern liegt in der Natur der Sache. Die | "richtige" Lösung für das Problem wäre meiner Meinung nach, in beiden | Pässen die Vereinigung beider Zeichenmengen zuzulassen und dann im | jeweiligen Callback zu testen, ob der Variablenname richtig war oder | nicht. | | Genaugenommen sollte man ohnehin überlegen, ob es nicht günstiger | wäre, mit _einem_ Callback das ganze in einem Pass zu parsen, und | diesen dann einfach zwischen Callback A und B entscheiden zu lassen, | um die tatsächliche Auflösung durchzuführen. @ text @d43 1 a43 1 void *context, @ 1.35 log @URL fixing and additional documents @ text @d114 1 @ 1.34 log @HEADS UPS: Mega-commit, revamping the whole library! - completely new API - completely new manual page @ text @d7 1 a7 1 ** library which can be found at http://www.ossp.org/pkg/var/. @ 1.33 log @style and text cleanups @ text @d208 2 d211 12 a222 1 for (i = 0; i < sizeof(tests) / sizeof(struct test_case); ++i) { d227 1 a227 1 rc = var_unescape(tests[i].input, strlen(tests[i].input), buffer, 0); d229 2 a230 2 printf ("Test case #%d: First var_unescape() failed with return code %d ('%s').\n", i, rc, var_strerror(rc)); d236 1 a236 2 rc = var_expand(buffer, strlen(buffer), &tmp, &tmp_len, &var_lookup, (void *)vars, NULL, 0); d238 2 a239 2 printf ("Test case #%d: var_expand() failed with return code %d ('%s').\n", i, rc, var_strerror(rc)); d249 1 a249 1 i, tests[i].expected, tmp); d254 1 @ 1.32 log @Added test case that verifies the correct behavior of search_and_replace() when zero-length matches occur. @ text @d2 1 a2 1 ** VAR - OSSP variable expression library. d6 1 a6 1 ** This file is part of OSSP VAR, an extensible data serialization d27 1 a27 1 ** var_test.c: VAR library regression test. @ 1.31 log @Fixed a test case where the expected result was incorrect. Thus, the test didn't not fail even though search_and_replace() contained a bug. @ text @d95 16 a110 15 { "HOME", 0, "/home/regression-tests" }, { "OSTYPE", 0, "regression-os" }, { "TERM", 0, "regression-term" }, { "FOO", 0, "os" }, { "BAR", 0, "type" }, { "EMPTY", 0, "" }, { "ARRAY", 0, "entry0" }, { "ARRAY", 1, "entry1" }, { "ARRAY", 2, "entry2" }, { "ARRAY", 3, "entry3" }, { "HEINZ", 0, "heinz0" }, { "HEINZ", 1, "heinz1" }, { "NUMBER", 0, "+2" }, { "NUMEXP", 0, "((16)%5)" }, { NULL, 0, NULL } d181 1 @ 1.30 log @bump copyright year @ text @d162 1 a162 1 { "${HOME:s/(s*)/x\\1X/g}", "xXxXxXxXxXxXxXxXxXxXxXxssXxXxXxXxXxXxXxsXxXxsX" }, @ 1.29 log @Finally adjust return code semantics of var_cb_t to use var_rc_t only. @ text @d3 2 a4 2 ** Copyright (c) 2001 The OSSP Project (http://www.ossp.org/) ** Copyright (c) 2001 Cable & Wireless Deutschland (http://www.cw.com/de/) @ 1.28 log @Implemented loops with explicit start, stop, and step values. @ text @d42 1 a42 1 static int var_lookup( d58 1 a58 1 return 1; d65 1 d67 1 d80 1 a80 1 return 1; d84 1 a84 1 return 0; @ 1.27 log @Manual OSSP coding style adjustments. @ text @d68 1 a68 1 while ( vars[i + counter].data d137 1 a137 1 { "${HOME:s/.*/heinz/}", "heinz" }, d176 2 d193 5 a197 1 } d229 1 a229 1 if ( tmp_len != strlen(tests[i].expected) @ 1.26 log @Get rid of the following warnings under "gcc -O2 -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-align -Winline -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Wno-long-long": var.h:91: warning: declaration of `index' shadows global declaration var.c: In function `expression': var.c:693: warning: declaration of `index' shadows global declaration var.c: At top level: var.c:1769: warning: declaration of `varname' shadows global declaration var.c:1769: warning: declaration of `index' shadows global declaration var.c: In function `lookup_wrapper': var.c:1772: warning: declaration of `index' shadows global declaration var.c:1772: warning: declaration of `varname' shadows global declaration var_test.c:13: warning: declaration of `index' shadows global declaration var_test.c: In function `var_lookup': var_test.c:16: warning: declaration of `index' shadows global declaration @ text @d1 29 d33 1 d42 2 a43 1 static int var_lookup(void *context, d48 1 a48 1 const struct variable* vars = context; d52 3 a54 6 if (idx >= 0) { for (i = 0; vars[i].name; ++i) { if (strncmp(varname, vars[i].name, name_len) == 0 && vars[i].idx == idx) { a58 1 } d61 4 a64 6 else { for (i = 0; vars[i].name; ++i) { if (strncmp(varname, vars[i].name, name_len) == 0) { d68 3 a70 2 while (vars[i + counter].data && strncmp(varname, vars[i + counter].name, name_len) == 0) ++counter; a78 1 } d81 1 d202 1 a202 1 tests[i].input); d223 3 a225 2 if (tmp_len != strlen(tests[i].expected) || tmp == NULL || memcmp(tests[i].expected, tmp, tmp_len) != 0) { d230 1 a230 1 free(tmp); a231 1 d234 1 @ 1.25 log @Implemented correct termination and recursion for loop constructs. @ text @d8 1 a8 1 const unsigned int index; d13 1 a13 1 const char *varname, size_t name_len, int index, d21 1 a21 1 if (index >= 0) d25 1 a25 1 if (strncmp(varname, vars[i].name, name_len) == 0 && vars[i].index == index) @ 1.24 log @Guarantee that the buffer returned by var_expand() is terminated with a null byte. @ text @d77 2 d148 18 a165 1 { "[${ARRAY}-]", "entry0-entry1-entry2-entry3-" } @ 1.23 log @Implemented the looping construct. However, there are still some semantical issues that need to be clarified before the code is stable. @ text @d146 1 a146 1 { ":[${ARRAY}-]:", ":entry0-entry1-entry2-entry3-:" } @ 1.22 log @Fixed test case for division-by-zero error with force_expand mode. @ text @d145 2 a146 1 { "${ARRAY[5/(${UNDEFINED})]}", "${ARRAY[5/(${UNDEFINED})]}" } @ 1.21 log @Implemented division-by-zero error. @ text @d145 1 a145 1 { "${ARRAY[5/(${UNDEFINED}-1)]}", "${ARRAY[5/(${UNDEFINED}-1)]}" } @ 1.20 log @Implemented force_expand mode in num_exp(). @ text @d144 2 a145 1 { "${ARRAY[${UNDEFINED}-1]}", "${ARRAY[${UNDEFINED}-1]}" } @ 1.19 log @Added support for variables as operands in index specifications. @ text @d144 1 a144 1 { "${ARRAY[${ARRAY[-1]}-1]}", "entry3" } @ 1.18 log @Implemented the semantic for negative index yielding the length of the variable or the length of the array. @ text @d77 2 d140 5 a144 1 { "${HOME[-1]}", "22" } @ 1.17 log @Implemented array-lookups in the callback and customized test cases appropriately. @ text @d18 2 a19 1 size_t i; d21 34 a54 9 if (index < 0) return VAR_ERR_ARRAY_LOOKUPS_ARE_UNSUPPORTED; for (i = 0; vars[i].name; ++i) { if (strncmp(varname, vars[i].name, name_len) == 0 && vars[i].index == index) { *data = vars[i].data; *data_len = strlen(*data); *buffer_size = 0; return 1; a55 1 } d136 3 a138 1 { "${ARRAY[+1--2]}", "entry3" } @ 1.16 log @Added test cases for array lookups. @ text @d8 1 d20 1 a20 1 if (0 && index != 0) d24 1 a24 1 if (strncmp(varname, vars[i].name, name_len) == 0) { d42 11 a52 7 { "HOME", "/home/regression-tests" }, { "OSTYPE", "regression-os" }, { "TERM", "regression-term" }, { "FOO", "os" }, { "BAR", "type" }, { "EMPTY", "" }, { NULL, NULL } d107 1 d109 3 a111 3 { "${ARRAY[5+(3+4)*2]}", "${ARRAY[5+(3+4)*2]}" }, { "${ARRAY[(5+(3+4)*2)]}", "${ARRAY[(5+(3+4)*2)]}" }, { "${ARRAY[+4--3]}", "${ARRAY[+4--3]}" } @ 1.15 log @Extended the interface of var_cb_t to support variable arrays. To customize your already existing lookup functions quickly to the new interface, just add the "int index" parameter to the function's prototype and add the lines if (index != 0) return VAR_ERR_ARRAY_LOOKUPS_ARE_UNSUPPORTED; to the function itself. @ text @d19 1 a19 1 if (index != 0) d51 55 a105 51 {"$HOME", "/home/regression-tests"}, {"${FOO}", "os"}, {"${BAR}", "type"}, {"${${FOO:u}${BAR:u}:l:u}", "REGRESSION-OS"}, {"${UNDEFINED}", "${UNDEFINED}"}, {"${OSTYPE:#}", "13"}, {"${EMPTY:-test${FOO}test}", "testostest"}, {"${EMPTY:-test${FOO:u}test}", "testOStest"}, {"${TERM:-test${FOO}test}", "regression-term"}, {"${EMPTY:+FOO}", ""}, {"${HOME:+test${FOO}test}", "testostest"}, {"${HOME:+${OS${BAR:u}}}", "regression-os"}, {"${HOME:+OS${UNDEFINED:u}}", "OS${UNDEFINED:u}"}, {"${UNDEFINED:+OS${BAR:u}}", "${UNDEFINED:+OS${BAR:u}}"}, {"${HOME:*heinz}", ""}, {"${EMPTY:*claus}", "claus"}, {"${TERM}", "regression-term"}, {"${HOME:s/reg/bla/}", "/home/blaression-tests"}, {"${HOME:s/e/bla/}", "/hombla/regression-tests"}, {"${HOME:s/e/bla/g}", "/hombla/rblagrblassion-tblasts"}, {"${HOME:s/\\//_/g}", "_home_regression-tests"}, {"${HOME:s/[eso]/_/g}", "/h_m_/r_gr___i_n-t__t_"}, {"${HOME:s/[esO]/_/g}", "/hom_/r_gr___ion-t__t_"}, {"${HOME:s/[esO]/_/gi}", "/h_m_/r_gr___i_n-t__t_"}, {"${OSTYPE:s/^[re]/_/g}", "_egression-os"}, {"${EMPTY:s/^[re]/_/g}", ""}, {"${HOME:s/.*/heinz/}", "heinz"}, {"${HOME:s/e/bla/t}", "/hombla/regression-tests"}, {"${HOME:s/E/bla/t}", "/home/regression-tests"}, {"${HOME:s/E/bla/ti}", "/hombla/regression-tests"}, {"${HOME:s/E/bla/tig}", "/hombla/rblagrblassion-tblasts"}, {"${HOME:o1-5}", "home/"}, {"${HOME:o1,5}", "home/"}, {"${HOME:o5,}", "/regression-tests"}, {"${HOME:o5-}", "/regression-tests"}, {"${HOME:o7,13}", "egressi"}, {"${HOME:y/a-z/A-YZ/}", "/HOME/REGRESSION-TESTS"}, {"${HOME:y/e-g/a-c/}", "/homa/racrassion-tasts"}, {"${FOO:p/15/../l}", "os............."}, {"${FOO:p/15/12345/l}", "os1234512345123"}, {"${FOO:p/15/../r}", ".............os"}, {"${FOO:p/15/12345/r}", "1234512345123os"}, {"${FOO:p/15/../c}", "......os......."}, {"${FOO:p/15/12345/c}", "123451os1234512"}, {"${FOO:s/os/\\x{4F}\\123/g}", "OS"}, {"${FOO:s/os/\\1\\x4F\\123/t}", "\\1OS"}, {"${HOME:s/g(res)s/x\\1x/g}", "/home/rexresxion-tests"}, {"${HOME:s/(s+)/_\\1_/g}", "/home/regre_ss_ion-te_s_t_s_"}, {"${HOME:s/\\x65/\\x45/g}", "/homE/rEgrEssion-tEsts"}, {"${HOME:s/(s*)/x\\1X/g}", "xXxXxXxXxXxXxXxXxXxXxXxssXxXxXxXxXxXxXxsXxXxsX"}, {"${HOME:s/./\\\\/g}", "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"} d120 2 a121 2 printf ("Test case #%d: First var_unescape() \ failed with return code %d.\n", i, rc); d130 2 a131 2 printf ("Test case #%d: var_expand() \ failed with return code %d.\n", i, rc); @ 1.14 log @Changed semantics of the :o operation so that the specified end-offset is included in the result. Updated documentation and test cases appropriately. @ text @d12 1 a12 1 const char *varname, size_t name_len, d18 3 @ 1.13 log @Renamed callback from env_lookup to var_lookup(). @ text @d80 1 a80 1 {"${HOME:o1,5}", "home"}, d83 1 a83 1 {"${HOME:o7,13}", "egress"}, d97 2 a98 4 {"${HOME:s/(s*)/x\\1X/g}", "xXxXxXxXxXxXxXxXxXxXxXxssXxXxXxXxXxXxXxsXxXxsX"}, {"${HOME:s/./\\\\/g}", "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"} @ 1.12 log @Rewrote env_lookup callback to use an internal array of variables rather than the system environment, because setenv() and unsetenv() are not really portable. Also, these routines lose memory, which is not a good thing for a test program. @ text @d11 1 a11 1 static int env_lookup(void *context, d123 1 a123 1 &env_lookup, (void *)vars, NULL, 0); @ 1.11 log @Minor corrections. @ text @d6 5 d16 2 a17 1 char tmp[256]; d19 7 a25 5 if (name_len > sizeof(tmp) - 1) { /* Callback can't expand variable names longer than sizeof(tmp) characters. */ return VAR_ERR_CALLBACK; d27 1 a27 8 memcpy(tmp, varname, name_len); tmp[name_len] = '\0'; *data = getenv(tmp); if (*data == NULL) return 0; *data_len = strlen(*data); *buffer_size = 0; return 1; d37 10 a107 10 if (setenv("HOME", "/home/regression-tests", 1) != 0 || setenv("OSTYPE", "regression-os", 1) != 0 || setenv("TERM", "regression-term", 1) != 0 || setenv("FOO", "os", 1) != 0 || setenv("BAR", "type", 1) != 0 || setenv("EMPTY", "", 1) != 0) { printf("Failed to set the environment: %s.\n", strerror(errno)); return 1; } unsetenv("UNDEFINED"); d123 1 a123 1 &env_lookup, NULL, NULL, 0); @ 1.10 log @Fix indentation. @ text @d8 2 a9 2 const char **data, size_t * data_len, size_t * buffer_size) @ 1.9 log @Rename the return codes VAR_XXX to VAR_ERR_XXX (except for VAR_OK) to be consistent with other OSSP libraries like L2. @ text @d7 3 a9 3 const char *varname, size_t name_len, const char **data, size_t * data_len, size_t * buffer_size) d23 1 a23 1 return 0; d37 53 a89 53 {"$HOME", "/home/regression-tests"}, {"${FOO}", "os"}, {"${BAR}", "type"}, {"${${FOO:u}${BAR:u}:l:u}", "REGRESSION-OS"}, {"${UNDEFINED}", "${UNDEFINED}"}, {"${OSTYPE:#}", "13"}, {"${EMPTY:-test${FOO}test}", "testostest"}, {"${EMPTY:-test${FOO:u}test}", "testOStest"}, {"${TERM:-test${FOO}test}", "regression-term"}, {"${EMPTY:+FOO}", ""}, {"${HOME:+test${FOO}test}", "testostest"}, {"${HOME:+${OS${BAR:u}}}", "regression-os"}, {"${HOME:+OS${UNDEFINED:u}}", "OS${UNDEFINED:u}"}, {"${UNDEFINED:+OS${BAR:u}}", "${UNDEFINED:+OS${BAR:u}}"}, {"${HOME:*heinz}", ""}, {"${EMPTY:*claus}", "claus"}, {"${TERM}", "regression-term"}, {"${HOME:s/reg/bla/}", "/home/blaression-tests"}, {"${HOME:s/e/bla/}", "/hombla/regression-tests"}, {"${HOME:s/e/bla/g}", "/hombla/rblagrblassion-tblasts"}, {"${HOME:s/\\//_/g}", "_home_regression-tests"}, {"${HOME:s/[eso]/_/g}", "/h_m_/r_gr___i_n-t__t_"}, {"${HOME:s/[esO]/_/g}", "/hom_/r_gr___ion-t__t_"}, {"${HOME:s/[esO]/_/gi}", "/h_m_/r_gr___i_n-t__t_"}, {"${OSTYPE:s/^[re]/_/g}", "_egression-os"}, {"${EMPTY:s/^[re]/_/g}", ""}, {"${HOME:s/.*/heinz/}", "heinz"}, {"${HOME:s/e/bla/t}", "/hombla/regression-tests"}, {"${HOME:s/E/bla/t}", "/home/regression-tests"}, {"${HOME:s/E/bla/ti}", "/hombla/regression-tests"}, {"${HOME:s/E/bla/tig}", "/hombla/rblagrblassion-tblasts"}, {"${HOME:o1-5}", "home/"}, {"${HOME:o1,5}", "home"}, {"${HOME:o5,}", "/regression-tests"}, {"${HOME:o5-}", "/regression-tests"}, {"${HOME:o7,13}", "egress"}, {"${HOME:y/a-z/A-YZ/}", "/HOME/REGRESSION-TESTS"}, {"${HOME:y/e-g/a-c/}", "/homa/racrassion-tasts"}, {"${FOO:p/15/../l}", "os............."}, {"${FOO:p/15/12345/l}", "os1234512345123"}, {"${FOO:p/15/../r}", ".............os"}, {"${FOO:p/15/12345/r}", "1234512345123os"}, {"${FOO:p/15/../c}", "......os......."}, {"${FOO:p/15/12345/c}", "123451os1234512"}, {"${FOO:s/os/\\x{4F}\\123/g}", "OS"}, {"${FOO:s/os/\\1\\x4F\\123/t}", "\\1OS"}, {"${HOME:s/g(res)s/x\\1x/g}", "/home/rexresxion-tests"}, {"${HOME:s/(s+)/_\\1_/g}", "/home/regre_ss_ion-te_s_t_s_"}, {"${HOME:s/\\x65/\\x45/g}", "/homE/rEgrEssion-tEsts"}, {"${HOME:s/(s*)/x\\1X/g}", "xXxXxXxXxXxXxXxXxXxXxXxssXxXxXxXxXxXxXxsXxXxsX"}, {"${HOME:s/./\\\\/g}", "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"} d102 2 a103 2 printf("Failed to set the environment: %s.\n", strerror(errno)); return 1; d109 1 a109 1 printf("Test case #%02d: Original input is '%s'.\n", i, d112 6 a117 8 rc = var_unescape(tests[i].input, strlen(tests[i].input), buffer, 0); if (rc != VAR_OK) { printf ("Test case #%d: First var_unescape() failed with return code %d.\n", i, rc); return 1; } d119 1 a119 1 printf("Test case #%02d: Unescaped input is '%s'.\n", i, buffer); d121 1 a121 1 rc = var_expand(buffer, strlen(buffer), &tmp, &tmp_len, d123 5 a127 6 if (rc != VAR_OK) { printf ("Test case #%d: var_expand() failed with return code %d.\n", i, rc); return 1; } d129 1 a129 1 printf("Test case #%02d: Expanded output is '%s'.\n", i, tmp); d131 1 a131 1 if (tmp_len != strlen(tests[i].expected) || tmp == NULL d133 4 a136 4 printf("Test case #%d: Expected result '%s' but got '%s'.\n", i, tests[i].expected, tmp); return 1; } @ 1.8 log @Expanded tabs. @ text @d17 1 a17 1 return VAR_CALLBACK_ERROR; @ 1.7 log @Reformatted the sources to Kernighan & Ritchie style according to the wishes of Ralf. @ text @d7 3 a9 3 const char *varname, size_t name_len, const char **data, size_t * data_len, size_t * buffer_size) d14 2 a15 2 /* Callback can't expand variable names longer than sizeof(tmp) characters. */ d17 1 a17 1 return VAR_CALLBACK_ERROR; d23 1 a23 1 return 0; d37 53 a89 53 {"$HOME", "/home/regression-tests"}, {"${FOO}", "os"}, {"${BAR}", "type"}, {"${${FOO:u}${BAR:u}:l:u}", "REGRESSION-OS"}, {"${UNDEFINED}", "${UNDEFINED}"}, {"${OSTYPE:#}", "13"}, {"${EMPTY:-test${FOO}test}", "testostest"}, {"${EMPTY:-test${FOO:u}test}", "testOStest"}, {"${TERM:-test${FOO}test}", "regression-term"}, {"${EMPTY:+FOO}", ""}, {"${HOME:+test${FOO}test}", "testostest"}, {"${HOME:+${OS${BAR:u}}}", "regression-os"}, {"${HOME:+OS${UNDEFINED:u}}", "OS${UNDEFINED:u}"}, {"${UNDEFINED:+OS${BAR:u}}", "${UNDEFINED:+OS${BAR:u}}"}, {"${HOME:*heinz}", ""}, {"${EMPTY:*claus}", "claus"}, {"${TERM}", "regression-term"}, {"${HOME:s/reg/bla/}", "/home/blaression-tests"}, {"${HOME:s/e/bla/}", "/hombla/regression-tests"}, {"${HOME:s/e/bla/g}", "/hombla/rblagrblassion-tblasts"}, {"${HOME:s/\\//_/g}", "_home_regression-tests"}, {"${HOME:s/[eso]/_/g}", "/h_m_/r_gr___i_n-t__t_"}, {"${HOME:s/[esO]/_/g}", "/hom_/r_gr___ion-t__t_"}, {"${HOME:s/[esO]/_/gi}", "/h_m_/r_gr___i_n-t__t_"}, {"${OSTYPE:s/^[re]/_/g}", "_egression-os"}, {"${EMPTY:s/^[re]/_/g}", ""}, {"${HOME:s/.*/heinz/}", "heinz"}, {"${HOME:s/e/bla/t}", "/hombla/regression-tests"}, {"${HOME:s/E/bla/t}", "/home/regression-tests"}, {"${HOME:s/E/bla/ti}", "/hombla/regression-tests"}, {"${HOME:s/E/bla/tig}", "/hombla/rblagrblassion-tblasts"}, {"${HOME:o1-5}", "home/"}, {"${HOME:o1,5}", "home"}, {"${HOME:o5,}", "/regression-tests"}, {"${HOME:o5-}", "/regression-tests"}, {"${HOME:o7,13}", "egress"}, {"${HOME:y/a-z/A-YZ/}", "/HOME/REGRESSION-TESTS"}, {"${HOME:y/e-g/a-c/}", "/homa/racrassion-tasts"}, {"${FOO:p/15/../l}", "os............."}, {"${FOO:p/15/12345/l}", "os1234512345123"}, {"${FOO:p/15/../r}", ".............os"}, {"${FOO:p/15/12345/r}", "1234512345123os"}, {"${FOO:p/15/../c}", "......os......."}, {"${FOO:p/15/12345/c}", "123451os1234512"}, {"${FOO:s/os/\\x{4F}\\123/g}", "OS"}, {"${FOO:s/os/\\1\\x4F\\123/t}", "\\1OS"}, {"${HOME:s/g(res)s/x\\1x/g}", "/home/rexresxion-tests"}, {"${HOME:s/(s+)/_\\1_/g}", "/home/regre_ss_ion-te_s_t_s_"}, {"${HOME:s/\\x65/\\x45/g}", "/homE/rEgrEssion-tEsts"}, {"${HOME:s/(s*)/x\\1X/g}", "xXxXxXxXxXxXxXxXxXxXxXxssXxXxXxXxXxXxXxsXxXxsX"}, {"${HOME:s/./\\\\/g}", "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"} d98 6 a103 6 setenv("OSTYPE", "regression-os", 1) != 0 || setenv("TERM", "regression-term", 1) != 0 || setenv("FOO", "os", 1) != 0 || setenv("BAR", "type", 1) != 0 || setenv("EMPTY", "", 1) != 0) { printf("Failed to set the environment: %s.\n", strerror(errno)); return 1; d109 2 a110 2 printf("Test case #%02d: Original input is '%s'.\n", i, tests[i].input); d112 8 a119 8 rc = var_unescape(tests[i].input, strlen(tests[i].input), buffer, 0); if (rc != VAR_OK) { printf ("Test case #%d: First var_unescape() failed with return code %d.\n", i, rc); return 1; } d121 1 a121 1 printf("Test case #%02d: Unescaped input is '%s'.\n", i, buffer); d123 8 a130 8 rc = var_expand(buffer, strlen(buffer), &tmp, &tmp_len, &env_lookup, NULL, NULL, 0); if (rc != VAR_OK) { printf ("Test case #%d: var_expand() failed with return code %d.\n", i, rc); return 1; } d132 1 a132 1 printf("Test case #%02d: Expanded output is '%s'.\n", i, tmp); d134 7 a140 7 if (tmp_len != strlen(tests[i].expected) || tmp == NULL || memcmp(tests[i].expected, tmp, tmp_len) != 0) { printf("Test case #%d: Expected result '%s' but got '%s'.\n", i, tests[i].expected, tmp); return 1; } free(tmp); @ 1.6 log @Implemented submatching in regular expressions and added the appropriate test cases. @ text @d6 5 a10 4 static int env_lookup(void* context, const char* varname, size_t name_len, const char** data, size_t* data_len, size_t* buffer_size) { d13 3 a15 4 if (name_len > sizeof(tmp)-1) { /* Callback can't expand variable names longer than sizeof(tmp) characters. */ d17 2 a18 2 return VAR_CALLBACK_ERROR; } d23 1 a23 1 return 0; d27 1 a27 1 } d29 61 a89 4 struct test_case { const char* input; const char* expected; d91 2 a92 59 int main(int argc, char** argv) { const struct test_case tests[] = { { "$HOME", "/home/regression-tests" }, { "${FOO}", "os" }, { "${BAR}", "type" }, { "${${FOO:u}${BAR:u}:l:u}", "REGRESSION-OS" }, { "${UNDEFINED}", "${UNDEFINED}" }, { "${OSTYPE:#}", "13" }, { "${EMPTY:-test${FOO}test}", "testostest" }, { "${EMPTY:-test${FOO:u}test}", "testOStest" }, { "${TERM:-test${FOO}test}", "regression-term" }, { "${EMPTY:+FOO}", "" }, { "${HOME:+test${FOO}test}", "testostest" }, { "${HOME:+${OS${BAR:u}}}", "regression-os" }, { "${HOME:+OS${UNDEFINED:u}}", "OS${UNDEFINED:u}" }, { "${UNDEFINED:+OS${BAR:u}}", "${UNDEFINED:+OS${BAR:u}}" }, { "${HOME:*heinz}", "" }, { "${EMPTY:*claus}", "claus" }, { "${TERM}", "regression-term" }, { "${HOME:s/reg/bla/}", "/home/blaression-tests" }, { "${HOME:s/e/bla/}", "/hombla/regression-tests" }, { "${HOME:s/e/bla/g}", "/hombla/rblagrblassion-tblasts" }, { "${HOME:s/\\//_/g}", "_home_regression-tests" }, { "${HOME:s/[eso]/_/g}", "/h_m_/r_gr___i_n-t__t_" }, { "${HOME:s/[esO]/_/g}", "/hom_/r_gr___ion-t__t_" }, { "${HOME:s/[esO]/_/gi}", "/h_m_/r_gr___i_n-t__t_" }, { "${OSTYPE:s/^[re]/_/g}", "_egression-os" }, { "${EMPTY:s/^[re]/_/g}", "" }, { "${HOME:s/.*/heinz/}", "heinz" }, { "${HOME:s/e/bla/t}", "/hombla/regression-tests" }, { "${HOME:s/E/bla/t}", "/home/regression-tests" }, { "${HOME:s/E/bla/ti}", "/hombla/regression-tests" }, { "${HOME:s/E/bla/tig}", "/hombla/rblagrblassion-tblasts" }, { "${HOME:o1-5}", "home/" }, { "${HOME:o1,5}", "home" }, { "${HOME:o5,}", "/regression-tests" }, { "${HOME:o5-}", "/regression-tests" }, { "${HOME:o7,13}", "egress" }, { "${HOME:y/a-z/A-YZ/}", "/HOME/REGRESSION-TESTS" }, { "${HOME:y/e-g/a-c/}", "/homa/racrassion-tasts" }, { "${FOO:p/15/../l}", "os............." }, { "${FOO:p/15/12345/l}", "os1234512345123" }, { "${FOO:p/15/../r}", ".............os" }, { "${FOO:p/15/12345/r}", "1234512345123os" }, { "${FOO:p/15/../c}", "......os......." }, { "${FOO:p/15/12345/c}", "123451os1234512" }, { "${FOO:s/os/\\x{4F}\\123/g}", "OS" }, { "${FOO:s/os/\\1\\x4F\\123/t}", "\\1OS" }, { "${HOME:s/g(res)s/x\\1x/g}", "/home/rexresxion-tests" }, { "${HOME:s/(s+)/_\\1_/g}", "/home/regre_ss_ion-te_s_t_s_" }, { "${HOME:s/\\x65/\\x45/g}", "/homE/rEgrEssion-tEsts" }, { "${HOME:s/(s*)/x\\1X/g}", "xXxXxXxXxXxXxXxXxXxXxXxssXxXxXxXxXxXxXxsXxXxsX" }, { "${HOME:s/./\\\\/g}", "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" } }; char* tmp; size_t tmp_len; d94 2 a95 2 size_t i; char buffer[1024]; d98 7 a104 9 setenv("OSTYPE", "regression-os", 1) != 0 || setenv("TERM", "regression-term", 1) != 0 || setenv("FOO", "os", 1) != 0 || setenv("BAR", "type", 1) != 0 || setenv("EMPTY", "", 1) != 0) { printf("Failed to set the environment: %s.\n", strerror(errno)); return 1; } d107 1 a107 2 for (i = 0; i < sizeof(tests) / sizeof(struct test_case); ++i) { d109 2 a110 1 printf("Test case #%02d: Original input is '%s'.\n", i, tests[i].input); d112 8 a119 6 rc = var_unescape(tests[i].input, strlen(tests[i].input), buffer, 0); if (rc != VAR_OK) { printf("Test case #%d: First var_unescape() failed with return code %d.\n", i, rc); return 1; } d121 1 a121 1 printf("Test case #%02d: Unescaped input is '%s'.\n", i, buffer); d123 8 a130 8 rc = var_expand(buffer, strlen(buffer), &tmp, &tmp_len, &env_lookup, NULL, NULL, 0); if (rc != VAR_OK) { printf("Test case #%d: var_expand() failed with return code %d.\n", i, rc); return 1; } d132 1 a132 1 printf("Test case #%02d: Expanded output is '%s'.\n", i, tmp); d134 8 a141 7 if (tmp_len != strlen(tests[i].expected) || tmp == NULL || memcmp(tests[i].expected, tmp, tmp_len) != 0) { printf("Test case #%d: Expected result '%s' but got '%s'.\n", i, tests[i].expected, tmp); return 1; } free(tmp); } d144 1 a144 1 } @ 1.5 log @The test program will print the data in each step to stdout when compiled with a DEBUG define. @ text @d6 1 a6 1 int env_lookup(void* context, d84 6 a89 1 { "${FOO:s/os/\\1\\x4F\\123/t}", "\\1OS" } a90 4 /* { "${HOME:s/g(res)s/x\\\\1x/g}","/homE/rEgrEssion-tEsts" } { "${HOME:s/\\x65/\\x45/g}", "/home/regression-tests" } */ a138 9 rc = var_unescape(tests[i].input, strlen(tests[i].input), buffer, 1); if (rc != VAR_OK) { printf("Test case #%d: Second var_unescape() failed with return code %d.\n", i, rc); return 1; } #ifdef DEBUG printf("Test case #%02d: Unescaped output is '%s'.\n\n", i, tmp); #endif @ 1.4 log @Changed the semantics of var_unescape(): It will only recognize a named character as being an octal if there are three digits following the backslash. Anything else will be interpreted as an ordinary quoted character that's copied verbatimly. Added a test case to verify that behavior. @ text @d110 1 d112 1 d119 1 d121 1 d130 1 d132 1 d144 1 d146 1 @ 1.3 log @Implemented the unescape_all-behavior and added modified the test program to make use of var_unescape(). Also added a test case, which verifies hex and octal characters are handled correctly. @ text @d39 46 a84 45 { "$HOME", "/home/regression-tests" }, { "${FOO}", "os" }, { "${BAR}", "type" }, { "${${FOO:u}${BAR:u}:l:u}", "REGRESSION-OS" }, { "${UNDEFINED}", "${UNDEFINED}" }, { "${OSTYPE:#}", "13" }, { "${EMPTY:-test${FOO}test}", "testostest" }, { "${EMPTY:-test${FOO:u}test}", "testOStest" }, { "${TERM:-test${FOO}test}", "regression-term" }, { "${EMPTY:+FOO}", "" }, { "${HOME:+test${FOO}test}", "testostest" }, { "${HOME:+${OS${BAR:u}}}", "regression-os" }, { "${HOME:+OS${UNDEFINED:u}}", "OS${UNDEFINED:u}" }, { "${UNDEFINED:+OS${BAR:u}}", "${UNDEFINED:+OS${BAR:u}}" }, { "${HOME:*heinz}", "" }, { "${EMPTY:*claus}", "claus" }, { "${TERM}", "regression-term" }, { "${HOME:s/reg/bla/}", "/home/blaression-tests" }, { "${HOME:s/e/bla/}", "/hombla/regression-tests" }, { "${HOME:s/e/bla/g}", "/hombla/rblagrblassion-tblasts" }, { "${HOME:s/\\//_/g}", "_home_regression-tests" }, { "${HOME:s/[eso]/_/g}", "/h_m_/r_gr___i_n-t__t_" }, { "${HOME:s/[esO]/_/g}", "/hom_/r_gr___ion-t__t_" }, { "${HOME:s/[esO]/_/gi}", "/h_m_/r_gr___i_n-t__t_" }, { "${OSTYPE:s/^[re]/_/g}", "_egression-os" }, { "${EMPTY:s/^[re]/_/g}", "" }, { "${HOME:s/.*/heinz/}", "heinz" }, { "${HOME:s/e/bla/t}", "/hombla/regression-tests" }, { "${HOME:s/E/bla/t}", "/home/regression-tests" }, { "${HOME:s/E/bla/ti}", "/hombla/regression-tests" }, { "${HOME:s/E/bla/tig}", "/hombla/rblagrblassion-tblasts" }, { "${HOME:o1-5}", "home/" }, { "${HOME:o1,5}", "home" }, { "${HOME:o5,}", "/regression-tests" }, { "${HOME:o5-}", "/regression-tests" }, { "${HOME:o7,13}", "egress" }, { "${HOME:y/a-z/A-YZ/}", "/HOME/REGRESSION-TESTS" }, { "${HOME:y/e-g/a-c/}", "/homa/racrassion-tasts" }, { "${FOO:p/15/../l}", "os............." }, { "${FOO:p/15/12345/l}", "os1234512345123" }, { "${FOO:p/15/../r}", ".............os" }, { "${FOO:p/15/12345/r}", "1234512345123os" }, { "${FOO:p/15/../c}", "......os......." }, { "${FOO:p/15/12345/c}", "123451os1234512" }, { "${FOO:s/os/\\x{4F}\\123/g}", "OS" } @ 1.2 log @The callback will now return a proper error code in case of failure, rather than using exit(1). @ text @d82 2 a83 1 { "${FOO:p/15/12345/c}", "123451os1234512" } d93 1 d109 9 a117 2 rc = var_expand(tests[i].input, strlen(tests[i].input), &tmp, &tmp_len, d125 1 d131 7 a137 1 printf("Test case #%02d: '%s' --> '%s'.\n", i, tests[i].input, tmp); @ 1.1 log @- Moved all routines into a single source file var.c. - Renamed varexp.h to var.h. - Removed odin-based build system. - Moved test cases into var_test.c. - Adapted build system. @ text @d7 2 a8 2 const char* varname, size_t name_len, const char** data, size_t* data_len, size_t* buffer_size) d14 4 a17 2 printf("Callback can't expand variable names longer than %d characters.\n", sizeof(tmp-1)); exit(1); @