Index: ossp-pkg/var/Makefile RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/Makefile,v rcsdiff -q -kk '-r1.1' '-r1.2' -u '/v/ossp/cvs/ossp-pkg/var/Attic/Makefile,v' 2>/dev/null --- Makefile 2001/11/09 17:01:37 1.1 +++ Makefile 2001/11/13 12:08:30 1.2 @@ -11,9 +11,7 @@ CFLAGS = LDFLAGS = -OBJS = expand-named-characters.o expand-character-class.o command.o \ - expression.o variable.o text.o expand.o input.o tokenbuf.o \ - search-and-replace.o cut-out-offset.o transpose.o padding.o +OBJS = var.o .c.o: $(CC) $(CPPFLAGS) $(WARNFLAGS) $(OPTFLAGS) $(CFLAGS) -c $< @@ -25,26 +23,10 @@ $(AR) cr $@ $(OBJS) $(RANLIB) $@ -clean:: - @(cd regression-tests && $(MAKE) clean) - rm -f $(OBJS) - rm -f libvarexp.a +var_test: var_test.o libvarexp.a + $(CC) $(LDFLAGS) -o $@ var_test.o libvarexp.a -check:: - (cd regression-tests && $(MAKE) check) +clean:: + rm -f $(OBJS) libvarexp.a var_test # Dependencies - -command.o: internal.h varexp.h -cut-out-offset.o: internal.h varexp.h -expand-character-class.o: internal.h varexp.h -expand-named-characters.o: internal.h varexp.h -expand.o: internal.h varexp.h -expression.o: internal.h varexp.h -input.o: internal.h varexp.h -padding.o: internal.h varexp.h -search-and-replace.o: internal.h varexp.h -text.o: internal.h varexp.h -tokenbuf.o: internal.h varexp.h -transpose.o: internal.h varexp.h -variable.o: internal.h varexp.h Index: ossp-pkg/var/Odinfile RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/Odinfile,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/Attic/Odinfile,v' | diff -u - /dev/null -L'ossp-pkg/var/Odinfile' 2>/dev/null --- ossp-pkg/var/Odinfile +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,23 +0,0 @@ -# Build variable-expression library. - -libvarexp.a == %libvarexp.a.sm +cc='gcc -Wall -pedantic' \ - +debug \ - :a - -%libvarexp.a.sm == << - expand-named-characters.c - expand-character-class.c - command.c - expression.c - variable.c - text.c - expand.c - input.c - tokenbuf.c - search-and-replace.c - cut-out-offset.c - transpose.c - padding.c - -%clean ! == !<< - rm -f libvarexp.a Index: ossp-pkg/var/command.c RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/command.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/Attic/command.c,v' | diff -u - /dev/null -L'ossp-pkg/var/command.c' 2>/dev/null --- ossp-pkg/var/command.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,385 +0,0 @@ -#include "internal.h" - -int command(const char* begin, const char* end, const var_config_t* config, - const char nameclass[256], var_cb_t lookup, void* lookup_context, - int force_expand, tokenbuf* data) - { - const char* p = begin; - tokenbuf tmptokbuf; - tokenbuf search, replace, flags; - tokenbuf number1, number2; - int isrange; - int rc; - - init_tokenbuf(&tmptokbuf); - init_tokenbuf(&search); - init_tokenbuf(&replace); - init_tokenbuf(&flags); - init_tokenbuf(&number1); - init_tokenbuf(&number2); - - if (begin == end) - return 0; - - switch (tolower(*p)) - { - case 'l': /* Turn data to lowercase. */ - if (data->begin) - { - char* ptr; - /* If the buffer does not life in an allocated buffer, - we have to copy it before modifying the contents. */ - - if (data->buffer_size == 0) - { - if (!assign_to_tokenbuf(data, data->begin, data->end - data->begin)) - { - rc = VAR_OUT_OF_MEMORY; - goto error_return; - } - } - for (ptr = (char*)data->begin; ptr != data->end; ++ptr) - *ptr = tolower(*ptr); - } - ++p; - break; - - case 'u': /* Turn data to uppercase. */ - if (data->begin) - { - char* ptr; - if (data->buffer_size == 0) - { - if (!assign_to_tokenbuf(data, data->begin, data->end - data->begin)) - { - rc = VAR_OUT_OF_MEMORY; - goto error_return; - } - } - for (ptr = (char*)data->begin; ptr != data->end; ++ptr) - *ptr = toupper(*ptr); - } - ++p; - break; - - case 'o': /* Cut out substrings. */ - ++p; - rc = number(p, end); - if (rc == 0) - { - rc = VAR_MISSING_START_OFFSET; - goto error_return; - } - else - { - number1.begin = p; - number1.end = p + rc; - number1.buffer_size = 0; - p += rc; - } - - if (*p == ',') - { - isrange = 0; - ++p; - } - else if (*p == '-') - { - isrange = 1; - ++p; - } - else - { - rc = VAR_INVALID_OFFSET_DELIMITER; - goto error_return; - } - - rc = number(p, end); - number2.begin = p; - number2.end = p + rc; - number2.buffer_size = 0; - p += rc; - if (data->begin) - { - rc = cut_out_offset(data, &number1, &number2, isrange); - if (rc < 0) - goto error_return; - } - break; - - case '#': /* Substitute length of the string. */ - if (data->begin) - { - char buf[1024]; - sprintf(buf, "%d", data->end - data->begin); - free_tokenbuf(data); - if (!assign_to_tokenbuf(data, buf, strlen(buf))) - { - rc = VAR_OUT_OF_MEMORY; - goto error_return; - } - } - ++p; - break; - - case '-': /* Substitute parameter if data is empty. */ - ++p; - rc = exptext_or_variable(p, end, config, nameclass, lookup, lookup_context, - force_expand, &tmptokbuf); - if (rc < 0) - goto error_return; - else if (rc == 0) - { - rc = VAR_MISSING_PARAMETER_IN_COMMAND; - goto error_return; - } - else - p += rc; - if (data->begin != NULL && data->begin == data->end) - { - free_tokenbuf(data); - move_tokenbuf(&tmptokbuf, data); - } - break; - - case '*': /* Return "" if data is not empty, parameter otherwise. */ - ++p; - rc = exptext_or_variable(p, end, config, nameclass, lookup, lookup_context, - force_expand, &tmptokbuf); - if (rc < 0) - goto error_return; - else if (rc == 0) - { - rc = VAR_MISSING_PARAMETER_IN_COMMAND; - goto error_return; - } - else - p += rc; - if (data->begin != NULL) - { - if (data->begin == data->end) - { - free_tokenbuf(data); - move_tokenbuf(&tmptokbuf, data); - } - else - { - free_tokenbuf(data); - data->begin = data->end = ""; - data->buffer_size = 0; - } - } - break; - - case '+': /* Substitute parameter if data is not empty. */ - ++p; - rc = exptext_or_variable(p, end, config, nameclass, lookup, lookup_context, - force_expand, &tmptokbuf); - if (rc < 0) - goto error_return; - else if (rc == 0) - { - rc = VAR_MISSING_PARAMETER_IN_COMMAND; - goto error_return; - } - else - p += rc; - if (data->begin != NULL) - { - if (data->begin != data->end) - { - free_tokenbuf(data); - move_tokenbuf(&tmptokbuf, data); - } - } - break; - - case 's': /* Search and replace. */ - ++p; - - if (*p != '/') - return VAR_MALFORMATTED_REPLACE; - else - ++p; - - rc = substext_or_variable(p, end, config, nameclass, lookup, lookup_context, - force_expand, &search); - if (rc < 0) - goto error_return; - else - p += rc; - - if (*p != '/') - { - rc = VAR_MALFORMATTED_REPLACE; - goto error_return; - } - else - ++p; - - rc = substext_or_variable(p, end, config, nameclass, lookup, lookup_context, - force_expand, &replace); - if (rc < 0) - goto error_return; - else - p += rc; - - if (*p != '/') - { - rc = VAR_MALFORMATTED_REPLACE; - goto error_return; - } - else - ++p; - - rc = exptext(p, end, config); - if (rc < 0) - goto error_return; - else - { - flags.begin = p; - flags.end = p + rc; - flags.buffer_size = 0; - p += rc; - } - - if (data->begin) - { - rc = search_and_replace(data, &search, &replace, &flags); - if (rc < 0) - goto error_return; - } - break; - - case 'y': /* Transpose characters from class A to class B. */ - ++p; - - if (*p != '/') - return VAR_MALFORMATTED_TRANSPOSE; - else - ++p; - - rc = substext_or_variable(p, end, config, nameclass, lookup, lookup_context, - force_expand, &search); - if (rc < 0) - goto error_return; - else - p += rc; - - if (*p != '/') - { - rc = VAR_MALFORMATTED_TRANSPOSE; - goto error_return; - } - else - ++p; - - rc = substext_or_variable(p, end, config, nameclass, lookup, lookup_context, - force_expand, &replace); - if (rc < 0) - goto error_return; - else - p += rc; - - if (*p != '/') - { - rc = VAR_MALFORMATTED_TRANSPOSE; - goto error_return; - } - else - ++p; - - if (data->begin) - { - rc = transpose(data, &search, &replace); - if (rc < 0) - goto error_return; - } - break; - - - case 'p': /* Padding. */ - ++p; - - if (*p != '/') - return VAR_MALFORMATTED_PADDING; - else - ++p; - - rc = number(p, end); - if (rc == 0) - { - rc = VAR_MISSING_PADDING_WIDTH; - goto error_return; - } - else - { - number1.begin = p; - number1.end = p + rc; - number1.buffer_size = 0; - p += rc; - } - - if (*p != '/') - { - rc = VAR_MALFORMATTED_PADDING; - goto error_return; - } - else - ++p; - - rc = substext_or_variable(p, end, config, nameclass, lookup, lookup_context, - force_expand, &replace); - if (rc < 0) - goto error_return; - else - p += rc; - - if (*p != '/') - { - rc = VAR_MALFORMATTED_PADDING; - goto error_return; - } - else - ++p; - - if (*p != 'l' && *p != 'c' && *p != 'r') - { - rc = VAR_MALFORMATTED_PADDING; - goto error_return; - } - else - ++p; - - if (data->begin) - { - rc = padding(data, &number1, &replace, p[-1]); - if (rc < 0) - goto error_return; - } - break; - - default: - return VAR_UNKNOWN_COMMAND_CHAR; - } - - /* Exit gracefully. */ - - free_tokenbuf(&tmptokbuf); - free_tokenbuf(&search); - free_tokenbuf(&replace); - free_tokenbuf(&flags); - free_tokenbuf(&number1); - free_tokenbuf(&number2); - return p - begin; - - error_return: - free_tokenbuf(data); - free_tokenbuf(&tmptokbuf); - free_tokenbuf(&search); - free_tokenbuf(&replace); - free_tokenbuf(&flags); - free_tokenbuf(&number1); - free_tokenbuf(&number2); - return rc; - } Index: ossp-pkg/var/cut-out-offset.c RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/cut-out-offset.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/Attic/cut-out-offset.c,v' | diff -u - /dev/null -L'ossp-pkg/var/cut-out-offset.c' 2>/dev/null --- ossp-pkg/var/cut-out-offset.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,58 +0,0 @@ -#include "internal.h" - -size_t tokenbuf2int(tokenbuf* number) - { - const char* p; - size_t num = 0; - for (p = number->begin; p != number->end; ++p) - { - num *= 10; - num += *p - '0'; - } - return num; - } - -int cut_out_offset(tokenbuf* data, tokenbuf* number1, tokenbuf* number2, int isrange) - { - tokenbuf res; - const char* p; - size_t num1 = tokenbuf2int(number1); - size_t num2 = tokenbuf2int(number2); - - /* Determine begin of result string. */ - - if ((data->end - data->begin) < num1) - return VAR_OFFSET_OUT_OF_BOUNDS; - else - p = data->begin + num1; - - /* If num2 is zero, we copy the rest from there. */ - - if (num2 == 0) - { - if (!assign_to_tokenbuf(&res, p, data->end - p)) - return VAR_OUT_OF_MEMORY; - } - else /* OK, then use num2. */ - { - if (isrange) - { - if ((p + num2) > data->end) - return VAR_RANGE_OUT_OF_BOUNDS; - if (!assign_to_tokenbuf(&res, p, num2)) - return VAR_OUT_OF_MEMORY; - } - else - { - if (num2 < num1) - return VAR_OFFSET_LOGIC_ERROR; - if ((data->begin + num2) > data->end) - return VAR_RANGE_OUT_OF_BOUNDS; - if (!assign_to_tokenbuf(&res, p, (data->begin + num2) - p)) - return VAR_OUT_OF_MEMORY; - } - } - free_tokenbuf(data); - move_tokenbuf(&res, data); - return VAR_OK; - } Index: ossp-pkg/var/expand-character-class.c RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/expand-character-class.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/Attic/expand-character-class.c,v' | diff -u - /dev/null -L'ossp-pkg/var/expand-character-class.c' 2>/dev/null --- ossp-pkg/var/expand-character-class.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,48 +0,0 @@ -#include "internal.h" - -static void expand_range(char a, char b, char class[256]) - { - assert(a <= b); - assert(class != NULL); - - do - { - class[(int)a] = 1; - } - while (++a <= b); - } - - -var_rc_t expand_character_class(const char* desc, char class[256]) - { - size_t i; - - assert(desc != NULL); - assert(class != NULL); - - /* Clear the class array. */ - - for (i = 0; i < 256; ++i) - class[i] = 0; - - /* Walk through the class description and set the appropriate - entries in the array. */ - - while(*desc != '\0') - { - if (desc[1] == '-' && desc[2] != '\0') - { - if (desc[0] > desc[2]) - return VAR_INCORRECT_CLASS_SPEC; - expand_range(desc[0], desc[2], class); - desc += 3; - } - else - { - class[(int)*desc] = 1; - ++desc; - } - } - - return VAR_OK; - } Index: ossp-pkg/var/expand-named-characters.c RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/expand-named-characters.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/Attic/expand-named-characters.c,v' | diff -u - /dev/null -L'ossp-pkg/var/expand-named-characters.c' 2>/dev/null --- ossp-pkg/var/expand-named-characters.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,177 +0,0 @@ -#include "internal.h" - -/* Internal parsing code for octal. */ - -static int isoct(char c) - { - if (c >= '0' && c <= '7') - return 1; - else - return 0; - } - -static var_rc_t expand_octal(const char** src, char** dst, const char* end) - { - unsigned char c; - - if (end - *src < 3) - return VAR_INCOMPLETE_OCTAL; - if (!isoct(**src) || !isoct((*src)[1]) || !isoct((*src)[2])) - return VAR_INVALID_OCTAL; - - c = **src - '0'; - if (c > 3) - return VAR_OCTAL_TOO_LARGE; - c *= 8; - ++(*src); - - c += **src - '0'; - c *= 8; - ++(*src); - - c += **src - '0'; - - **dst = (char)c; - ++(*dst); - return VAR_OK; - } - -static int ishex(char c) - { - if ((c >= '0' && c <= '9') || - (c >= 'a' && c <= 'f') || - (c >= 'A' && c <= 'F')) - return 1; - else - return 0; - } - -/* Internal parsing code for hex. */ - -static var_rc_t expand_simple_hex(const char** src, char** dst, const char* end) - { - unsigned char c = 0; - - if (end - *src < 2) - return VAR_INCOMPLETE_HEX; - if (!ishex(**src) || !ishex((*src)[1])) - return VAR_INVALID_HEX; - - if (**src >= '0' && **src <= '9') - c = **src - '0'; - else if (c >= 'a' && c <= 'f') - c = **src - 'a' + 10; - else if (c >= 'A' && c <= 'F') - c = **src - 'A' + 10; - - c = c << 4; - ++(*src); - - if (**src >= '0' && **src <= '9') - c += **src - '0'; - else if (**src >= 'a' && **src <= 'f') - c += **src - 'a' + 10; - else if (**src >= 'A' && **src <= 'F') - c += **src - 'A' + 10; - - **dst = (char)c; - ++(*dst); - return VAR_OK; - } - -static var_rc_t expand_grouped_hex(const char** src, char** dst, const char* end) - { - var_rc_t rc; - - while (*src < end && **src != '}') - { - if ((rc = expand_simple_hex(src, dst, end)) != 0) - return rc; - ++(*src); - } - if (*src == end) - return VAR_INCOMPLETE_GROUPED_HEX; - - return VAR_OK; - } - -static var_rc_t expand_hex(const char** src, char** dst, const char* end) - { - if (*src == end) - return VAR_INCOMPLETE_HEX; - if (**src == '{') - { - ++(*src); - return expand_grouped_hex(src, dst, end); - } - else - return expand_simple_hex(src, dst, end); - } - -/* - Expand the following named characters in the buffer: - - \t tab - \n newline - \r return - \033 octal char - \x1B hex char - \x{263a} wide hex char - - Any other character quoted by a backslash is copied verbatim. -*/ - -var_rc_t expand_named_characters(const char* src, size_t len, char* dst) - { - const char* end = src + len; - var_rc_t rc; - - assert(src != NULL); - assert(dst != NULL); - - while (src < end) - { - if (*src == '\\') - { - if (++src == end) - return VAR_INCOMPLETE_NAMED_CHARACTER; - switch (*src) - { - case 'n': - *dst++ = '\n'; - break; - case 't': - *dst++ = '\t'; - break; - case 'r': - *dst++ = '\r'; - break; - case 'x': - ++src; - if ((rc = expand_hex(&src, &dst, end)) != 0) - return rc; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if ((rc = expand_octal(&src, &dst, end)) != 0) - return rc; - break; - default: - *dst++ = *src; - } - ++src; - } - else - *dst++ = *src++; - } - *dst = '\0'; - return VAR_OK; - } Index: ossp-pkg/var/expand.c RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/expand.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/Attic/expand.c,v' | diff -u - /dev/null -L'ossp-pkg/var/expand.c' 2>/dev/null --- ossp-pkg/var/expand.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,60 +0,0 @@ -#include "internal.h" - -const var_config_t var_config_default = - { - '$', /* varinit */ - '{', /* startdelim */ - '}', /* enddelim */ - '\\', /* escape */ - "a-zA-Z0-9_" /* namechars */ - }; - -var_rc_t var_expand(const char* input_buf, size_t input_len, - char** result, size_t* result_len, - var_cb_t lookup, void* lookup_context, - const var_config_t* config, int force_expand) - { - char nameclass[256]; - var_rc_t rc; - tokenbuf output; - - /* Assert everything is as we expect it. */ - - assert(input != NULL); - assert(result != NULL); - assert(result_len != NULL); - assert(lookup != NULL); - - /* Expand the class description for valid variable names. */ - - if (config == NULL) - config = &var_config_default; - rc = expand_character_class(config->namechars, nameclass); - if (rc != VAR_OK) - return rc; - - /* Make sure that the specials defined in the configuration do not - appear in the character name class. */ - - if (nameclass[(int)config->varinit] || - nameclass[(int)config->startdelim] || - nameclass[(int)config->enddelim] || - nameclass[(int)config->escape]) - return VAR_INVALID_CONFIGURATION; - - /* Call the parser. */ - - output.begin = output.end = NULL; - output.buffer_size = 0; - rc = input(input_buf, input_buf + input_len, config, nameclass, - lookup, lookup_context, force_expand, &output); - if (rc != VAR_OK) - { - free_tokenbuf(&output); - return rc; - } - *result = (char*)output.begin; - *result_len = output.end - output.begin; - - return VAR_OK; - } Index: ossp-pkg/var/expression.c RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/expression.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/Attic/expression.c,v' | diff -u - /dev/null -L'ossp-pkg/var/expression.c' 2>/dev/null --- ossp-pkg/var/expression.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,163 +0,0 @@ -#include "internal.h" - -int expression(const char* begin, const char* end, const var_config_t* config, - const char nameclass[256], var_cb_t lookup, void* lookup_context, - int force_expand, tokenbuf* result) - { - const char* p = begin; - const char* data; - size_t len, buffer_size; - int failed = 0; - int rc; - tokenbuf name; - tokenbuf tmp; - - /* Clear the tokenbufs to make sure we have a defined state. */ - - init_tokenbuf(&name); - init_tokenbuf(&tmp); - init_tokenbuf(result); - - /* Expect STARTDELIM. */ - - if (p == end || *p != config->startdelim) - return 0; - - if (++p == end) - return VAR_INCOMPLETE_VARIABLE_SPEC; - - /* Get the name of the variable to expand. The name may consist of - an arbitrary number of VARNAMEs and VARIABLEs. */ - - do - { - rc = varname(p, end, nameclass); - if (rc < 0) - goto error_return; - else if (rc > 0) - { - if (!append_to_tokenbuf(&name, p, rc)) - { - rc = VAR_OUT_OF_MEMORY; - goto error_return; - } - else - p += rc; - } - - rc = variable(p, end, config, nameclass, lookup, lookup_context, force_expand, &tmp); - if (rc < 0) - goto error_return; - else if (rc > 0) - { - if (!append_to_tokenbuf(&name, tmp.begin, tmp.end - tmp.begin)) - { - rc = VAR_OUT_OF_MEMORY; - goto error_return; - } - else - p += rc; - } - } - while (rc > 0); - - /* We must have the complete variable name now, so make sure we - do. */ - - if (name.begin == name.end) - { - rc = VAR_INCOMPLETE_VARIABLE_SPEC; - goto error_return; - } - - /* Now we have the name of the variable stored in "name". We - expect an ENDDELIM here. */ - - if (p == end || (*p != config->enddelim && *p != ':')) - { - rc = VAR_INCOMPLETE_VARIABLE_SPEC; - goto error_return; - } - else - ++p; - - /* Use the lookup callback to get the variable's contents. */ - - rc = (*lookup)(lookup_context, name.begin, name.end - name.begin, &data, &len, &buffer_size); - if (rc < 0) - goto error_return; - else if (rc == 0) - { - /* The variable is undefined. What we'll do now depends on the - force_expand flag. */ - - if (force_expand) - { - rc = VAR_UNDEFINED_VARIABLE; - goto error_return; - } - else - { - /* Initialize result to point back to the original text in - the buffer. */ - - result->begin = begin-1; - result->end = p; - result->buffer_size = 0; - failed = 1; - } - } - else - { - /* The preliminary result is the contents of the variable. - This may be modified by the commands that may follow. */ - - result->begin = data; - result->end = data + len; - result->buffer_size = buffer_size; - } - - if (p[-1] == ':') - { - /* Parse and execute commands. */ - - free_tokenbuf(&tmp); - --p; - while (p != end && *p == ':') - { - ++p; - if (!failed) - rc = command(p, end, config, nameclass, lookup, lookup_context, force_expand, result); - else - rc = command(p, end, config, nameclass, lookup, lookup_context, force_expand, &tmp); - if (rc < 0) - goto error_return; - p += rc; - if (failed) - result->end += rc; - } - - if (p == end || *p != config->enddelim) - { - rc = VAR_INCOMPLETE_VARIABLE_SPEC; - goto error_return; - } - ++p; - if (failed) - ++result->end; - } - - /* Exit gracefully. */ - - free_tokenbuf(&name); - free_tokenbuf(&tmp); - return p - begin; - - /* Exit in case of an error. */ - - error_return: - free_tokenbuf(&name); - free_tokenbuf(&tmp); - free_tokenbuf(result); - return rc; - } Index: ossp-pkg/var/input.c RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/input.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/Attic/input.c,v' | diff -u - /dev/null -L'ossp-pkg/var/input.c' 2>/dev/null --- ossp-pkg/var/input.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,54 +0,0 @@ -#include "internal.h" - -var_rc_t input(const char* begin, const char* end, const var_config_t* config, - const char nameclass[256], var_cb_t lookup, void* lookup_context, - int force_expand, tokenbuf* output) - { - int rc; - tokenbuf result; - - init_tokenbuf(&result); - - do - { - rc = text(begin, end, config->varinit, config->escape); - if (rc > 0) - { - if (!append_to_tokenbuf(output, begin, rc)) - { - rc = VAR_OUT_OF_MEMORY; - goto error_return; - } - begin += rc; - } - else if (rc < 0) - goto error_return; - - rc = variable(begin, end, config, nameclass, lookup, lookup_context, force_expand, &result); - if (rc > 0) - { - if (!append_to_tokenbuf(output, result.begin, result.end - result.begin)) - { - rc = VAR_OUT_OF_MEMORY; - goto error_return; - } - else - begin += rc; - } - else if (rc < 0) - goto error_return; - } - while (rc > 0); - - if (begin != end) - { - rc = VAR_INPUT_ISNT_TEXT_NOR_VARIABLE; - goto error_return; - } - - return VAR_OK; - - error_return: - free_tokenbuf(&result); - return rc; - } Index: ossp-pkg/var/internal.h RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/internal.h,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/Attic/internal.h,v' | diff -u - /dev/null -L'ossp-pkg/var/internal.h' 2>/dev/null --- ossp-pkg/var/internal.h +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,86 +0,0 @@ -#ifndef INTERNAL_H -#define INTERNAL_H - -#include -#include -#include -#include -#include -#include "varexp.h" - -#ifdef DMALLOC -# define DMALLOC_FUNC_CHECK -# include -#endif - -/* Turn character class descriptions into a lookup-array. */ - -var_rc_t expand_character_class(const char* desc, char class[256]); - -/* - The tokenbuf structure is used by the parser routines. If - buffer_size is >0, it means that the buffer has been allocated by - malloc(3) and must be free(3)ed when not used anymore. -*/ - -typedef struct - { - const char* begin; - const char* end; - size_t buffer_size; - } -tokenbuf; - -int append_to_tokenbuf(tokenbuf* output, const char* begin, size_t rc); -void free_tokenbuf(tokenbuf* buf); -void init_tokenbuf(tokenbuf* buf); -int assign_to_tokenbuf(tokenbuf* buf, const char* data, size_t len); -void move_tokenbuf(tokenbuf* src, tokenbuf* dst); - -var_rc_t input(const char* begin, const char* end, const var_config_t* config, - const char nameclass[256], var_cb_t lookup, void* lookup_context, - int force_expand, tokenbuf* output); - -int variable(const char* begin, const char* end, const var_config_t* config, - const char nameclass[256], var_cb_t lookup, void* lookup_context, - int force_expand, tokenbuf* result); - - -int command(const char* begin, const char* end, const var_config_t* config, - const char nameclass[256], var_cb_t lookup, void* lookup_context, - int force_expand, tokenbuf* result); - -int exptext(const char* begin, const char* end, const var_config_t* config); - -int exptext_or_variable(const char* begin, const char* end, const var_config_t* config, - const char nameclass[256], var_cb_t lookup, void* lookup_context, - int force_expand, tokenbuf* result); - - -int substext_or_variable(const char* begin, const char* end, const var_config_t* config, - const char nameclass[256], var_cb_t lookup, void* lookup_context, - int force_expand, tokenbuf* result); - -int substext(const char* begin, const char* end, const var_config_t* config); - -int search_and_replace(tokenbuf* data, tokenbuf* search, tokenbuf* replace, tokenbuf* flags); - -int varname(const char* begin, const char* end, const char nameclass[256]); - -int expression(const char* begin, const char* end, const var_config_t* config, - const char nameclass[256], var_cb_t lookup, void* lookup_context, - int force_expand, tokenbuf* result); - -int text(const char* begin, const char* end, char varinit, char escape); - -int number(const char* begin, const char* end); - -int cut_out_offset(tokenbuf* data, tokenbuf* number1, tokenbuf* number2, int isrange); - -int transpose(tokenbuf* data, tokenbuf* search, tokenbuf* replace); - -int padding(tokenbuf* data, tokenbuf* width, tokenbuf* fill, char position); - -size_t tokenbuf2int(tokenbuf* number); - -#endif /* !defined(INTERNAL_H) */ Index: ossp-pkg/var/padding.c RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/padding.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/Attic/padding.c,v' | diff -u - /dev/null -L'ossp-pkg/var/padding.c' 2>/dev/null --- ossp-pkg/var/padding.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,139 +0,0 @@ -#include -#include -#include "internal.h" - -int padding(tokenbuf* data, tokenbuf* widthstr, tokenbuf* fill, char position) - { - tokenbuf result; - size_t width = tokenbuf2int(widthstr); - int i; - - printf("Padding data '%s' to width '%d' by filling in '%s' to position '%c'.\n", - data->begin, width, fill->begin, position); - - if (fill->begin == fill->end) - return VAR_EMPTY_PADDING_FILL_STRING; - - init_tokenbuf(&result); - - if (position == 'l') - { - i = width - (data->end - data->begin); - if (i > 0) - { - printf("Missing %d characters at the end of the data string.\n", i); - i = i / (fill->end - fill->begin); - printf("That's %d times the padding string.\n", i); - while(i > 0) - { - if (!append_to_tokenbuf(data, fill->begin, fill->end - fill->begin)) - return VAR_OUT_OF_MEMORY; - --i; - } - i = (width - (data->end - data->begin)) % (fill->end - fill->begin); - printf("Plus a remainder of %d characters.\n", i); - if (!append_to_tokenbuf(data, fill->begin, i)) - return VAR_OUT_OF_MEMORY; - } - } - else if (position == 'r') - { - i = width - (data->end - data->begin); - if (i > 0) - { - printf("Missing %d characters at the beginning of the data string.\n", i); - i = i / (fill->end - fill->begin); - printf("That's %d times the padding string.\n", i); - while(i > 0) - { - if (!append_to_tokenbuf(&result, fill->begin, fill->end - fill->begin)) - { - free_tokenbuf(&result); - return VAR_OUT_OF_MEMORY; - } - --i; - } - i = (width - (data->end - data->begin)) % (fill->end - fill->begin); - printf("Plus a remainder of %d characters.\n", i); - if (!append_to_tokenbuf(&result, fill->begin, i)) - { - free_tokenbuf(&result); - return VAR_OUT_OF_MEMORY; - } - if (!append_to_tokenbuf(&result, data->begin, data->end - data->begin)) - { - free_tokenbuf(&result); - return VAR_OUT_OF_MEMORY; - } - - free_tokenbuf(data); - move_tokenbuf(&result, data); - } - } - else if (position == 'c') - { - i = (width - (data->end - data->begin)) / 2; - if (i > 0) - { - /* Create the prefix. */ - - printf("Missing %d characters at the beginning of the data string.\n", i); - i = i / (fill->end - fill->begin); - printf("That's %d times the padding string.\n", i); - while(i > 0) - { - if (!append_to_tokenbuf(&result, fill->begin, fill->end - fill->begin)) - { - free_tokenbuf(&result); - return VAR_OUT_OF_MEMORY; - } - --i; - } - i = ((width - (data->end - data->begin)) / 2) % (fill->end - fill->begin); - printf("Plus a remainder of %d characters.\n", i); - if (!append_to_tokenbuf(&result, fill->begin, i)) - { - free_tokenbuf(&result); - return VAR_OUT_OF_MEMORY; - } - - /* Append the actual data string. */ - - if (!append_to_tokenbuf(&result, data->begin, data->end - data->begin)) - { - free_tokenbuf(&result); - return VAR_OUT_OF_MEMORY; - } - - /* Append the suffix. */ - - i = width - (result.end - result.begin); - printf("Missing %d characters at the end of the data string.\n", i); - i = i / (fill->end - fill->begin); - printf("That's %d times the padding string.\n", i); - while(i > 0) - { - if (!append_to_tokenbuf(&result, fill->begin, fill->end - fill->begin)) - { - free_tokenbuf(&result); - return VAR_OUT_OF_MEMORY; - } - --i; - } - i = width - (result.end - result.begin); - printf("Plus a remainder of %d characters.\n", i); - if (!append_to_tokenbuf(&result, fill->begin, i)) - { - free_tokenbuf(&result); - return VAR_OUT_OF_MEMORY; - } - - /* Move string from temporary buffer to data buffer. */ - - free_tokenbuf(data); - move_tokenbuf(&result, data); - } - } - - return VAR_OK; - } Index: ossp-pkg/var/regression-tests/.run-tests RCS File: /v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/.run-tests,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/.run-tests,v' | diff -u - /dev/null -L'ossp-pkg/var/regression-tests/.run-tests' 2>/dev/null --- ossp-pkg/var/regression-tests/.run-tests +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,44 +0,0 @@ -#! /bin/sh - -if [ $# -lt 1 ]; then - echo "Usage: $0 test1.exe [...]" - exit 1 -fi - -RESCOLUMN=50 -numTests=0 -numFails=0 - -echo "Running test suite:" - -pad='' -n=$RESCOLUMN -while [ $n -gt 0 ]; do - pad="$pad." - n=`expr $n - 1` -done -for suite in "$@"; do - name=`basename "${suite}"` - name=`expr "${name}" : '\(.*\)\.exe$'` - echo "$name$pad" | awk '{ printf("%s ", substr($0, 0, n)); }' n=$RESCOLUMN - export DMALLOC_OPTIONS=debug=0x4f47d03,inter=1,log=/tmp/$name.dmalloc - numTests=`expr $numTests + 1` - eval ./$suite >/dev/null 2>&1 - if [ $? -eq 0 ]; then - echo "OK" - else - numFails=`expr $numFails + 1` - echo "FAILED" - fi -done - -echo -if [ $numFails -eq 0 ]; then - echo "Summary: All tests succeeded." - exit 0 -else - percent=`expr $numFails \* 100` - percent=`expr $percent / $numTests` - echo "Summary: $numFails of $numTests tests failed ($percent%)." - exit 1 -fi Index: ossp-pkg/var/regression-tests/Makefile RCS File: /v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/Makefile,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/Makefile,v' | diff -u - /dev/null -L'ossp-pkg/var/regression-tests/Makefile' 2>/dev/null --- ossp-pkg/var/regression-tests/Makefile +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,44 +0,0 @@ -# Regression tests for libvarexp. - -CC = gcc -AR = ar -RANLIB = ranlib - -WARNFLAGS = -Wall -pedantic -OPTFLAGS = -O3 -pipe - -CPPFLAGS = -CFLAGS = -LDFLAGS = - -.SUFFIXES: .exe - -TESTS = expand-named-characters.exe expand-character-class.exe \ - expand1.exe expand2.exe force-expand.exe expand3.exe \ - expand4.exe expand5.exe expand6.exe empty-search-pattern.exe \ - offset-failure.exe - -.c.exe: - $(CC) $(CPPFLAGS) $(WARNFLAGS) $(OPTFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $< -L.. -lvarexp - -check: - @(cd .. && $(MAKE) libvarexp.a) - @$(MAKE) $(TESTS) - @./.run-tests $(TESTS) - -clean:: - rm -f $(TESTS) - -# Dependencies - -empty-search-pattern.exe: ../internal.h ../varexp.h -expand-character-class.exe: ../internal.h ../varexp.h -expand-named-characters.exe: ../internal.h ../varexp.h -expand1.exe: ../internal.h ../varexp.h -expand2.exe: ../internal.h ../varexp.h -expand3.exe: ../internal.h ../varexp.h -expand4.exe: ../internal.h ../varexp.h -expand5.exe: ../internal.h ../varexp.h -expand6.exe: ../internal.h ../varexp.h -force-expand.exe: ../internal.h ../varexp.h -offset-failure.exe: ../internal.h ../varexp.h Index: ossp-pkg/var/regression-tests/Odinfile RCS File: /v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/Odinfile,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/Odinfile,v' | diff -u - /dev/null -L'ossp-pkg/var/regression-tests/Odinfile' 2>/dev/null --- ossp-pkg/var/regression-tests/Odinfile +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,81 +0,0 @@ -# Regression tests for libvarexp. - -%test == () +cmd='sh' (%run-tests) \ - (expand-named-characters.exe) \ - (expand-character-class.exe) \ - (expand1.exe) \ - (expand2.exe) \ - (force-expand.exe) \ - (expand3.exe) \ - (expand4.exe) \ - (expand5.exe) \ - (expand6.exe) \ - (empty-search-pattern.exe) \ - (offset-failure.exe) \ - +output_show \ - :stdout - -expand-named-characters.exe == expand-named-characters.c +(%test.flags) :exe -expand-character-class.exe == expand-character-class.c +(%test.flags) :exe -expand1.exe == expand1.c +(%test.flags) :exe -expand2.exe == expand2.c +(%test.flags) :exe -force-expand.exe == force-expand.c +(%test.flags) :exe -expand3.exe == expand3.c +(%test.flags) :exe -expand4.exe == expand4.c +(%test.flags) :exe -expand5.exe == expand5.c +(%test.flags) :exe -expand6.exe == expand6.c +(%test.flags) :exe -empty-search-pattern.exe == empty-search-pattern.c +(%test.flags) :exe -offset-failure.exe == offset-failure.c +(%test.flags) :exe - -%test.flags == << - +lib=(../libvarexp.a) - +cc='gcc -Wall -pedantic' - +debug - -%run-tests == <<[eof] - if [ $# -lt 1 ]; then - echo "Usage: $0 test1.exe [...]" - exit 1 - fi - - RESCOLUMN=50 - numTests=0 - numFails=0 - - echo "Running test suite:" - - pad='' - n=$RESCOLUMN - while [ $n -gt 0 ]; do - pad="$pad." - n=`expr $n - 1` - done - for suite in "$@"; do - name=`basename "${suite}"` - name=`expr "${name}" : '\(.*\)\.exe$'` - echo "$name$pad" | awk '{ printf("%s ", substr($0, 0, n)); }' n=$RESCOLUMN - export DMALLOC_OPTIONS=debug=0x4f47d03,inter=1,log=/tmp/$name.dmalloc - numTests=`expr $numTests + 1` - eval $suite >/dev/null 2>&1 - if [ $? -eq 0 ]; then - echo "OK" - else - numFails=`expr $numFails + 1` - echo "FAILED" - fi - done - - echo - if [ $numFails -eq 0 ]; then - echo "Summary: All tests succeeded." - exit 0 - else - percent=`expr $numFails \* 100` - percent=`expr $percent / $numTests` - echo "Summary: $numFails of $numTests tests failed ($percent%)." - exit 1 - fi -[eof] - -%clean ! == !<< - rm -f *.exe Index: ossp-pkg/var/regression-tests/empty-search-pattern.c RCS File: /v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/empty-search-pattern.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/empty-search-pattern.c,v' | diff -u - /dev/null -L'ossp-pkg/var/regression-tests/empty-search-pattern.c' 2>/dev/null --- ossp-pkg/var/regression-tests/empty-search-pattern.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,48 +0,0 @@ -#include "../internal.h" - -int env_lookup(void* context, - const char* varname, size_t name_len, - const char** data, size_t* data_len, size_t* buffer_size) - { - char tmp[256]; - - if (name_len > sizeof(tmp)-1) - { - printf("Callback can't expand variable names longer than %d characters.\n", sizeof(tmp-1)); - exit(1); - } - 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; - } - -int main(int argc, char** argv) - { - const char* input = "${HOME:s/$EMPTY/test/}"; - char* tmp; - size_t tmp_len; - var_rc_t rc; - - if (setenv("HOME", "/home/regression-tests", 1) != 0 || - setenv("EMPTY", "", 1) != 0) - { - printf("Failed to set the environment: %s.\n", strerror(errno)); - return 1; - } - rc = var_expand(input, strlen(input), - &tmp, &tmp_len, - &env_lookup, NULL, - NULL, 0); - if (rc != VAR_EMPTY_SEARCH_STRING) - { - printf("var_expand() should have failed with VAR_EMPTY_SEARCH_STRING but returned %d.\n", rc); - return 1; - } - - return 0; - } Index: ossp-pkg/var/regression-tests/expand-character-class.c RCS File: /v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/expand-character-class.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/expand-character-class.c,v' | diff -u - /dev/null -L'ossp-pkg/var/regression-tests/expand-character-class.c' 2>/dev/null --- ossp-pkg/var/regression-tests/expand-character-class.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,56 +0,0 @@ -#include "../internal.h" - -static void class2string(char class[256], char* buf) - { - size_t i; - for (i = 0; i < 256; ++i) - { - if (class[i]) - *buf++ = (char)i; - } - *buf = '\0'; - } - -struct test_case - { - const char* input; - const char* expected; - var_rc_t rc; - }; - -int main(int argc, char** argv) - { - struct test_case tests[] = - { - { "", "", VAR_OK }, - { "abcabc", "abc", VAR_OK }, - { "a-z", "abcdefghijklmnopqrstuvwxyz", VAR_OK }, - { "a-eA-Eabcdef-", "-ABCDEabcdef", VAR_OK }, - { "-a-eA-Eabcdef-", "-ABCDEabcdef", VAR_OK }, - { "0-9-", "-0123456789", VAR_OK }, - { "g-a", NULL, VAR_INCORRECT_CLASS_SPEC } - }; - size_t i; - char class[256]; - char tmp[1024]; - - for (i = 0; i < sizeof(tests) / sizeof(struct test_case); ++i) - { - if (expand_character_class(tests[i].input, class) != tests[i].rc) - { - printf("expand_character_class() failed test case %d.\n", i); - return 1; - } - if (tests[i].expected != NULL) - { - class2string(class, tmp); - if (strcmp(tmp, tests[i].expected) != 0) - { - printf("expand_character_class() failed test case %d.\n", i); - return 1; - } - } - } - - return 0; - } Index: ossp-pkg/var/regression-tests/expand-named-characters.c RCS File: /v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/expand-named-characters.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/expand-named-characters.c,v' | diff -u - /dev/null -L'ossp-pkg/var/regression-tests/expand-named-characters.c' 2>/dev/null --- ossp-pkg/var/regression-tests/expand-named-characters.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,49 +0,0 @@ -#include "../internal.h" - -struct test_case - { - const char* input; - const char* expected; - var_rc_t rc; - }; - -int main(int argc, char** argv) - { - struct test_case tests[] = - { - { "", "", VAR_OK }, - { "\\", NULL, VAR_INCOMPLETE_NAMED_CHARACTER }, - { "hello world", "hello world", VAR_OK }, - { "\\n", "\n", VAR_OK }, - {"\\t", "\t", VAR_OK }, - { "\\rhello\\tworld\\n", "\rhello\tworld\n", VAR_OK }, - { "\\x5a\\x5A", "ZZ", VAR_OK }, - { "\\x5g\\x5A", NULL, VAR_INVALID_HEX }, - { "\\x5", NULL, VAR_INCOMPLETE_HEX }, - { "\\033", "\033", VAR_OK }, - { "\\03", NULL, VAR_INCOMPLETE_OCTAL }, - { "\\038", NULL, VAR_INVALID_OCTAL }, - { "\\400", NULL, VAR_OCTAL_TOO_LARGE }, - { "\\x{4243}", "BC", VAR_OK }, - { "\\x{}", "", VAR_OK }, - { "\\x{5a5A5a5A}", "ZZZZ", VAR_OK }, - { "\\x{", NULL, VAR_INCOMPLETE_GROUPED_HEX }, - { "x\\x{5a5A5a5A}a", "xZZZZa", VAR_OK }, - { "x\\x{5a5A5a\\0015A}a", NULL, VAR_INVALID_HEX }, - { "x\\x{5a\\x{5a}5A}a", NULL, VAR_INVALID_HEX } - }; - size_t i; - char tmp[1024]; - - for (i = 0; i < sizeof(tests) / sizeof(struct test_case); ++i) - { - if (expand_named_characters(tests[i].input, strlen(tests[i].input), tmp) != tests[i].rc || - (tests[i].expected != NULL && strcmp(tmp, tests[i].expected) != 0)) - { - printf("expand_named_characters() failed test case %d.\n", i); - return 1; - } - } - - return 0; - } Index: ossp-pkg/var/regression-tests/expand1.c RCS File: /v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/expand1.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/expand1.c,v' | diff -u - /dev/null -L'ossp-pkg/var/regression-tests/expand1.c' 2>/dev/null --- ossp-pkg/var/regression-tests/expand1.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,45 +0,0 @@ -#include "../internal.h" - -int dummy(void* context, - const char* varname, size_t name_len, - const char** data, size_t* data_len, size_t* buffer_size) - { - printf("The dummy callback should not have been called!\n"); - exit(1); - } - -int main(int argc, char** argv) - { - const char* input = "This is a \\$test!"; - const char* output = "This is a \\$test!"; - char* tmp; - size_t tmp_len; - var_rc_t rc; - - rc = var_expand(input, strlen(input), - &tmp, &tmp_len, - &dummy, NULL, - NULL, 0); - if (rc != VAR_OK) - { - printf("var_expand() failed with error %d.\n", rc); - return 1; - } - - if (tmp_len != strlen(output)) - { - printf("The length of the output string is not what we expected: %d != %d.\n", - tmp_len, strlen(output)); - return 1; - } - - if (memcmp(tmp, output, tmp_len) != 0) - { - printf("The buffer returned by var_expand() is not what we expected.\n"); - return 1; - } - - free(tmp); - - return 0; - } Index: ossp-pkg/var/regression-tests/expand2.c RCS File: /v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/expand2.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/expand2.c,v' | diff -u - /dev/null -L'ossp-pkg/var/regression-tests/expand2.c' 2>/dev/null --- ossp-pkg/var/regression-tests/expand2.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,56 +0,0 @@ -#include "../internal.h" - -int dummy(void* context, - const char* varname, size_t name_len, - const char** data, size_t* data_len, size_t* buffer_size) - { - if (name_len != sizeof("test")-1) - { - printf("The the length of the variable name (%d) doesn't fit.\n", name_len); - exit(1); - } - if (memcmp(varname, "test", sizeof("test")-1) != 0) - { - printf("Callback called for unknown variable.\n"); - exit(1); - } - *data = "foobar"; - *data_len = sizeof("foobar")-1; - *buffer_size = 0; - - return 1; - } - -int main(int argc, char** argv) - { - const char* input = "This is a $test!"; - const char* output = "This is a foobar!"; - char* tmp; - size_t tmp_len; - var_rc_t rc; - - rc = var_expand(input, strlen(input), - &tmp, &tmp_len, - &dummy, NULL, - NULL, 0); - if (rc != VAR_OK) - { - printf("var_expand() failed with error %d.\n", rc); - return 1; - } - - if (tmp_len != strlen(output)) - { - printf("The length of the output string is not what we expected: %d != %d.\n", - tmp_len, strlen(output)); - return 1; - } - - if (memcmp(tmp, output, tmp_len) != 0) - { - printf("The buffer returned by var_expand() is not what we expected.\n"); - return 1; - } - - return 0; - } Index: ossp-pkg/var/regression-tests/expand3.c RCS File: /v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/expand3.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/expand3.c,v' | diff -u - /dev/null -L'ossp-pkg/var/regression-tests/expand3.c' 2>/dev/null --- ossp-pkg/var/regression-tests/expand3.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,81 +0,0 @@ -#include "../internal.h" - -int env_lookup(void* context, - const char* varname, size_t name_len, - const char** data, size_t* data_len, size_t* buffer_size) - { - char tmp[256]; - - if (name_len > sizeof(tmp)-1) - { - printf("Callback can't expand variable names longer than %d characters.\n", sizeof(tmp-1)); - exit(1); - } - 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; - } - -int main(int argc, char** argv) - { - const char* input = \ - "\\$HOME = '$HOME'\\n" \ - "\\$OSTYPE = '$OSTYPE'\\n" \ - "\\$UNDEFINED = '$UNDEFINED'\\n" \ - "\\$TERM = '$TERM'\\n"; - const char* output = \ - "$HOME = '/home/regression-tests'\n" \ - "$OSTYPE = 'regression-os'\n" \ - "$UNDEFINED = '$UNDEFINED'\n" \ - "$TERM = 'regression-term'\n"; - char* tmp; - size_t tmp_len; - var_rc_t rc; - - if (setenv("HOME", "/home/regression-tests", 1) != 0 || - setenv("OSTYPE", "regression-os", 1) != 0 || - setenv("TERM", "regression-term", 1) != 0) - { - printf("Failed to set the environment: %s.\n", strerror(errno)); - return 1; - } - unsetenv("UNDEFINED"); - rc = var_expand(input, strlen(input), - &tmp, &tmp_len, - &env_lookup, NULL, - NULL, 0); - if (rc != VAR_OK) - { - printf("var_expand() failed with error %d.\n", rc); - return 1; - } - - rc = expand_named_characters(tmp, tmp_len, tmp); - if (rc != VAR_OK) - { - printf("expand_named_characters() failed with error %d.\n", rc); - return 1; - } - else - tmp_len = strlen(tmp); - - if (tmp_len != strlen(output)) - { - printf("The length of the output string is not what we expected: %d != %d.\n", - tmp_len, strlen(output)); - return 1; - } - - if (memcmp(tmp, output, tmp_len) != 0) - { - printf("The buffer returned by var_expand() is not what we expected.\n"); - return 1; - } - - return 0; - } Index: ossp-pkg/var/regression-tests/expand4.c RCS File: /v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/expand4.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/expand4.c,v' | diff -u - /dev/null -L'ossp-pkg/var/regression-tests/expand4.c' 2>/dev/null --- ossp-pkg/var/regression-tests/expand4.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,81 +0,0 @@ -#include "../internal.h" - -int env_lookup(void* context, - const char* varname, size_t name_len, - const char** data, size_t* data_len, size_t* buffer_size) - { - char tmp[256]; - - if (name_len > sizeof(tmp)-1) - { - printf("Callback can't expand variable names longer than %d characters.\n", sizeof(tmp-1)); - exit(1); - } - 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; - } - -int main(int argc, char** argv) - { - const char* input = \ - "\\$HOME = '${HOME}'\\n" \ - "\\$OSTYPE = '${OSTYPE}'\\n" \ - "\\$UNDEFINED = '${UNDEFINED}'\\n" \ - "\\$TERM = '${TERM}'\\n"; - const char* output = \ - "$HOME = '/home/regression-tests'\n" \ - "$OSTYPE = 'regression-os'\n" \ - "$UNDEFINED = '${UNDEFINED}'\n" \ - "$TERM = 'regression-term'\n"; - char* tmp; - size_t tmp_len; - var_rc_t rc; - - if (setenv("HOME", "/home/regression-tests", 1) != 0 || - setenv("OSTYPE", "regression-os", 1) != 0 || - setenv("TERM", "regression-term", 1) != 0) - { - printf("Failed to set the environment: %s.\n", strerror(errno)); - return 1; - } - unsetenv("UNDEFINED"); - rc = var_expand(input, strlen(input), - &tmp, &tmp_len, - &env_lookup, NULL, - NULL, 0); - if (rc != VAR_OK) - { - printf("var_expand() failed with error %d.\n", rc); - return 1; - } - - rc = expand_named_characters(tmp, tmp_len, tmp); - if (rc != VAR_OK) - { - printf("expand_named_characters() failed with error %d.\n", rc); - return 1; - } - else - tmp_len = strlen(tmp); - - if (tmp_len != strlen(output)) - { - printf("The length of the output string is not what we expected: %d != %d.\n", - tmp_len, strlen(output)); - return 1; - } - - if (memcmp(tmp, output, tmp_len) != 0) - { - printf("The buffer returned by var_expand() is not what we expected.\n"); - return 1; - } - - return 0; - } Index: ossp-pkg/var/regression-tests/expand5.c RCS File: /v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/expand5.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/expand5.c,v' | diff -u - /dev/null -L'ossp-pkg/var/regression-tests/expand5.c' 2>/dev/null --- ossp-pkg/var/regression-tests/expand5.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,85 +0,0 @@ -#include "../internal.h" - -int env_lookup(void* context, - const char* varname, size_t name_len, - const char** data, size_t* data_len, size_t* buffer_size) - { - char tmp[256]; - - if (name_len > sizeof(tmp)-1) - { - printf("Callback can't expand variable names longer than %d characters.\n", sizeof(tmp-1)); - exit(1); - } - 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; - } - -int main(int argc, char** argv) - { - const char* input = \ - "\\$HOME = '${HOME}'\\n" \ - "\\$OSTYPE = '${$FOO${BAR}}'\\n" \ - "\\$UNDEFINED = '${UNDEFINED}'\\n" \ - "\\$TERM = '${TERM}'\\n"; - const char* output = \ - "$HOME = '/home/regression-tests'\n" \ - "$OSTYPE = 'regression-os'\n" \ - "$UNDEFINED = '${UNDEFINED}'\n" \ - "$TERM = 'regression-term'\n"; - char* tmp; - size_t tmp_len; - var_rc_t rc; - - 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) - { - printf("Failed to set the environment: %s.\n", strerror(errno)); - return 1; - } - unsetenv("UNDEFINED"); - rc = var_expand(input, strlen(input), - &tmp, &tmp_len, - &env_lookup, NULL, - NULL, 0); - if (rc != VAR_OK) - { - printf("var_expand() failed with error %d.\n", rc); - return 1; - } - - rc = expand_named_characters(tmp, tmp_len, tmp); - if (rc != VAR_OK) - { - printf("expand_named_characters() failed with error %d.\n", rc); - return 1; - } - else - tmp_len = strlen(tmp); - - printf("==================================================\n%s==================================================\n", tmp); - - if (tmp_len != strlen(output)) - { - printf("The length of the output string is not what we expected: %d != %d.\n", - tmp_len, strlen(output)); - return 1; - } - - if (memcmp(tmp, output, tmp_len) != 0) - { - printf("The buffer returned by var_expand() is not what we expected.\n"); - return 1; - } - - return 0; - } Index: ossp-pkg/var/regression-tests/expand6.c RCS File: /v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/expand6.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/expand6.c,v' | diff -u - /dev/null -L'ossp-pkg/var/regression-tests/expand6.c' 2>/dev/null --- ossp-pkg/var/regression-tests/expand6.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,121 +0,0 @@ -#include "../internal.h" - -int env_lookup(void* context, - const char* varname, size_t name_len, - const char** data, size_t* data_len, size_t* buffer_size) - { - char tmp[256]; - - if (name_len > sizeof(tmp)-1) - { - printf("Callback can't expand variable names longer than %d characters.\n", sizeof(tmp-1)); - exit(1); - } - 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; - } - -struct test_case - { - const char* input; - const char* expected; - }; - -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" } - }; - /* - { "${HOME:s/g(res)s/x\\\\1x/g}","/homE/rEgrEssion-tEsts" } - { "${HOME:s/\\x65/\\x45/g}", "/home/regression-tests" } - */ - char* tmp; - size_t tmp_len; - var_rc_t rc; - size_t i; - - 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"); - - for (i = 0; i < sizeof(tests) / sizeof(struct test_case); ++i) - { - rc = var_expand(tests[i].input, strlen(tests[i].input), - &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; - } - 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; - } - printf("Test case #%02d: '%s' --> '%s'.\n", i, tests[i].input, tmp); - free(tmp); - } - - return 0; - } Index: ossp-pkg/var/regression-tests/force-expand.c RCS File: /v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/force-expand.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/force-expand.c,v' | diff -u - /dev/null -L'ossp-pkg/var/regression-tests/force-expand.c' 2>/dev/null --- ossp-pkg/var/regression-tests/force-expand.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,65 +0,0 @@ -#include "../internal.h" - -int dummy(void* context, - const char* varname, size_t name_len, - const char** data, size_t* data_len, size_t* buffer_size) - { - if (name_len != sizeof("heinz_ist_doof")-1) - { - printf("The the length of the variable name (%d) doesn't fit.\n", name_len); - exit(1); - } - if (memcmp(varname, "heinz_ist_doof", sizeof("heinz_ist_doof")-1) != 0) - { - printf("Callback called for unknown variable.\n"); - exit(1); - } - return 0; /* say it's undefined */ - } - -int main(int argc, char** argv) - { - const char* input = "This is a $heinz_ist_doof!"; - char* tmp; - size_t tmp_len; - var_rc_t rc; - - /* Run var_expand() with force_expand and expect failure. */ - - rc = var_expand(input, strlen(input), - &tmp, &tmp_len, - &dummy, NULL, - NULL, 1); - if (rc != VAR_UNDEFINED_VARIABLE) - { - printf("var_expand() should have failed with error UNDEFINED_VARIABLE, but returned %d.\n", rc); - return 1; - } - - /* Run var_expand() without force_expand and expect input == output. */ - - rc = var_expand(input, strlen(input), - &tmp, &tmp_len, - &dummy, NULL, - NULL, 0); - if (rc != VAR_OK) - { - printf("var_expand() failed with error %d.\n", rc); - return 1; - } - - if (tmp_len != strlen(input)) - { - printf("The length of the input string is not what we expected: %d != %d.\n", - tmp_len, strlen(input)); - return 1; - } - - if (memcmp(tmp, input, tmp_len) != 0) - { - printf("The buffer returned by var_expand() is not what we expected.\n"); - return 1; - } - - return 0; - } Index: ossp-pkg/var/regression-tests/offset-failure.c RCS File: /v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/offset-failure.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/regression-tests/Attic/offset-failure.c,v' | diff -u - /dev/null -L'ossp-pkg/var/regression-tests/offset-failure.c' 2>/dev/null --- ossp-pkg/var/regression-tests/offset-failure.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,68 +0,0 @@ -#include "../internal.h" - -int env_lookup(void* context, - const char* varname, size_t name_len, - const char** data, size_t* data_len, size_t* buffer_size) - { - char tmp[256]; - - if (name_len > sizeof(tmp)-1) - { - printf("Callback can't expand variable names longer than %d characters.\n", sizeof(tmp-1)); - exit(1); - } - 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; - } - -int main(int argc, char** argv) - { - const char* input1 = "${HOME:o88,}"; - const char* input2 = "${HOME:o88-90}"; - const char* input3 = "${HOME:o8-90}"; - const char* input4 = "${HOME:o8,90}"; - const char* input5 = "${HOME:o8,4}"; - - char* tmp; - size_t tmp_len; - var_rc_t rc; - - if (setenv("HOME", "/home/regression-tests", 1) !=0) - { - printf("Failed to set the environment: %s.\n", strerror(errno)); - return 1; - } - if ((rc = var_expand(input1, strlen(input1), &tmp, &tmp_len, &env_lookup, NULL, NULL, 0)) != VAR_OFFSET_OUT_OF_BOUNDS) - { - printf("var_expand() should have failed with VAR_OFFSET_OUT_OF_BOUNDS but returned %d.\n", rc); - return 1; - } - if ((rc = var_expand(input2, strlen(input2), &tmp, &tmp_len, &env_lookup, NULL, NULL, 0)) != VAR_OFFSET_OUT_OF_BOUNDS) - { - printf("var_expand() should have failed with VAR_OFFSET_OUT_OF_BOUNDS but returned %d.\n", rc); - return 1; - } - if ((rc = var_expand(input3, strlen(input3), &tmp, &tmp_len, &env_lookup, NULL, NULL, 0)) != VAR_RANGE_OUT_OF_BOUNDS) - { - printf("var_expand() should have failed with VAR_RANGE_OUT_OF_BOUNDS but returned %d.\n", rc); - return 1; - } - if ((rc = var_expand(input4, strlen(input4), &tmp, &tmp_len, &env_lookup, NULL, NULL, 0)) != VAR_RANGE_OUT_OF_BOUNDS) - { - printf("var_expand() should have failed with VAR_RANGE_OUT_OF_BOUNDS but returned %d.\n", rc); - return 1; - } - if ((rc = var_expand(input5, strlen(input5), &tmp, &tmp_len, &env_lookup, NULL, NULL, 0)) != VAR_OFFSET_LOGIC_ERROR) - { - printf("var_expand() should have failed with VAR_OFFSET_LOGIC_ERROR but returned %d.\n", rc); - return 1; - } - - return 0; - } Index: ossp-pkg/var/search-and-replace.c RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/search-and-replace.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/Attic/search-and-replace.c,v' | diff -u - /dev/null -L'ossp-pkg/var/search-and-replace.c' 2>/dev/null --- ossp-pkg/var/search-and-replace.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,158 +0,0 @@ -#include -#include -#include "internal.h" - -int search_and_replace(tokenbuf* data, tokenbuf* search, tokenbuf* replace, tokenbuf* flags) - { - const char* p; - int case_insensitive = 0; - int global = 0; - int no_regex = 0; - int rc; - - if (search->begin == search->end) - return VAR_EMPTY_SEARCH_STRING; - - printf("Search '%s' in '%s' and replace it with '%s'.\n", - search->begin, data->begin, replace->begin); - - for (p = flags->begin; p != flags->end; ++p) - { - switch (tolower(*p)) - { - case 'i': - case_insensitive = 1; - printf("case_insensitive = 1;\n"); - break; - case 'g': - global = 1; - printf("global = 1;\n"); - break; - case 't': - no_regex = 1; - printf("no_regex = 1;\n"); - break; - default: - return VAR_UNKNOWN_REPLACE_FLAG; - } - } - - if (no_regex) - { - tokenbuf tmp; - init_tokenbuf(&tmp); - - for (p = data->begin; p != data->end; ) - { - if (case_insensitive) - rc = strncasecmp(p, search->begin, search->end - search->begin); - else - rc = strncmp(p, search->begin, search->end - search->begin); - if (rc != 0) - { /* no match, copy character */ - if (!append_to_tokenbuf(&tmp, p, 1)) - { - free_tokenbuf(&tmp); - return VAR_OUT_OF_MEMORY; - } - ++p; - } - else - { - append_to_tokenbuf(&tmp, replace->begin, replace->end - replace->begin); - p += search->end - search->begin; - if (!global) - { - if (!append_to_tokenbuf(&tmp, p, data->end - p)) - { - free_tokenbuf(&tmp); - return VAR_OUT_OF_MEMORY; - } - break; - } - } - } - - free_tokenbuf(data); - move_tokenbuf(&tmp, data); - } - else - { - tokenbuf tmp; - tokenbuf mydata; - regex_t preg; - regmatch_t pmatch[33]; - int regexec_flag; - - /* Copy the pattern and the data to our own buffer to make - sure they're terminated with a null byte. */ - - if (!assign_to_tokenbuf(&tmp, search->begin, search->end - search->begin)) - return VAR_OUT_OF_MEMORY; - if (!assign_to_tokenbuf(&mydata, data->begin, data->end - data->begin)) - { - free_tokenbuf(&tmp); - return VAR_OUT_OF_MEMORY; - } - - /* Compile the pattern. */ - - printf("data is.................: '%s'\n", mydata.begin); - printf("regex search pattern is.: '%s'\n", tmp.begin); - printf("regex replace pattern is: '%s'\n", replace->begin); - rc = regcomp(&preg, tmp.begin, REG_EXTENDED | ((case_insensitive) ? REG_ICASE : 0)); - free_tokenbuf(&tmp); - if (rc != 0) - { - free_tokenbuf(&mydata); - return VAR_INVALID_REGEX_IN_REPLACE; - } - printf("Subexpression in pattern: '%d'\n", preg.re_nsub); - - /* Match the pattern and create the result string in the tmp - buffer. */ - - for (p = mydata.begin; p != mydata.end; ) - { - if (p == mydata.begin || p[-1] == '\n') - regexec_flag = 0; - else - regexec_flag = REG_NOTBOL; - if (regexec(&preg, p, sizeof(pmatch) / sizeof(regmatch_t), pmatch, regexec_flag) == REG_NOMATCH) - { - printf("No match; appending remainder ('%s') to output string.\n", p); - append_to_tokenbuf(&tmp, p, mydata.end - p); - break; - } - else - { -#if 0 - printf("Match from offset %ld to %ld in string '%s'.\n", - pmatch[0].rm_so, pmatch[0].rm_eo, p); -#endif - if (!append_to_tokenbuf(&tmp, p, pmatch[0].rm_so) || - !append_to_tokenbuf(&tmp, replace->begin, replace->end - replace->begin)) - { - regfree(&preg); - free_tokenbuf(&tmp); - free_tokenbuf(&mydata); - return VAR_OUT_OF_MEMORY; - } - else - p += pmatch[0].rm_eo; - if (!global) - { - append_to_tokenbuf(&tmp, p, mydata.end - p); - break; - } - } - } - - regfree(&preg); - free_tokenbuf(data); - move_tokenbuf(&tmp, data); - free_tokenbuf(&mydata); - } - - return VAR_OK; - } Index: ossp-pkg/var/text.c RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/text.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/Attic/text.c,v' | diff -u - /dev/null -L'ossp-pkg/var/text.c' 2>/dev/null --- ossp-pkg/var/text.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,173 +0,0 @@ -#include "internal.h" - -int text(const char* begin, const char* end, char varinit, char escape) - { - const char* p; - for (p = begin; p != end && *p != varinit; ++p) - { - if (*p == escape) - { - if (p+1 == end) - return VAR_INCOMPLETE_QUOTED_PAIR; - else - ++p; - } - } - return p - begin; - } - -int varname(const char* begin, const char* end, const char nameclass[256]) - { - const char* p; - for (p = begin; p != end && nameclass[(int)*p]; ++p) - ; - return p - begin; - } - -int number(const char* begin, const char* end) - { - const char* p; - for (p = begin; p != end && isdigit(*p); ++p) - ; - return p - begin; - } - -int substext(const char* begin, const char* end, const var_config_t* config) - { - const char* p; - for (p = begin; p != end && *p != config->varinit && *p != '/'; ++p) - { - if (*p == config->escape) - { - if (p+1 == end) - return VAR_INCOMPLETE_QUOTED_PAIR; - else - ++p; - } - } - return p - begin; - } - -int exptext(const char* begin, const char* end, const var_config_t* config) - { - const char* p; - for (p = begin; p != end && *p != config->varinit && *p != config->enddelim && *p != ':'; ++p) - { - if (*p == config->escape) - { - if (p+1 == end) - return VAR_INCOMPLETE_QUOTED_PAIR; - else - ++p; - } - } - return p - begin; - } - -int exptext_or_variable(const char* begin, const char* end, const var_config_t* config, - const char nameclass[256], var_cb_t lookup, void* lookup_context, - int force_expand, tokenbuf* result) - { - const char* p = begin; - tokenbuf tmp; - int rc; - - init_tokenbuf(result); - init_tokenbuf(&tmp); - - if (begin == end) - return 0; - - do - { - rc = exptext(p, end, config); - if (rc < 0) - goto error_return; - else if (rc > 0) - { - if (!append_to_tokenbuf(result, p, rc)) - { - rc = VAR_OUT_OF_MEMORY; - goto error_return; - } - else - p += rc; - } - - rc = variable(p, end, config, nameclass, lookup, lookup_context, force_expand, &tmp); - if (rc < 0) - goto error_return; - else if (rc > 0) - { - p += rc; - if (!append_to_tokenbuf(result, tmp.begin, tmp.end - tmp.begin)) - { - rc = VAR_OUT_OF_MEMORY; - goto error_return; - } - } - } - while (rc > 0); - - free_tokenbuf(&tmp); - return p - begin; - - error_return: - free_tokenbuf(&tmp); - free_tokenbuf(result); - return rc; - } - -int substext_or_variable(const char* begin, const char* end, const var_config_t* config, - const char nameclass[256], var_cb_t lookup, void* lookup_context, - int force_expand, tokenbuf* result) - { - const char* p = begin; - tokenbuf tmp; - int rc; - - init_tokenbuf(result); - init_tokenbuf(&tmp); - - if (begin == end) - return 0; - - do - { - rc = substext(p, end, config); - if (rc < 0) - goto error_return; - else if (rc > 0) - { - if (!append_to_tokenbuf(result, p, rc)) - { - rc = VAR_OUT_OF_MEMORY; - goto error_return; - } - else - p += rc; - } - - rc = variable(p, end, config, nameclass, lookup, lookup_context, force_expand, &tmp); - if (rc < 0) - goto error_return; - else if (rc > 0) - { - p += rc; - if (!append_to_tokenbuf(result, tmp.begin, tmp.end - tmp.begin)) - { - rc = VAR_OUT_OF_MEMORY; - goto error_return; - } - } - } - while (rc > 0); - - free_tokenbuf(&tmp); - return p - begin; - - error_return: - free_tokenbuf(&tmp); - free_tokenbuf(result); - return rc; - } Index: ossp-pkg/var/tokenbuf.c RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/tokenbuf.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/Attic/tokenbuf.c,v' | diff -u - /dev/null -L'ossp-pkg/var/tokenbuf.c' 2>/dev/null --- ossp-pkg/var/tokenbuf.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,115 +0,0 @@ -#include "internal.h" - -#define VAR_INITIAL_BUFFER_SIZE 1 - -void init_tokenbuf(tokenbuf* buf) - { - buf->begin = buf->end = NULL; - buf->buffer_size = 0; - } - -void move_tokenbuf(tokenbuf* src, tokenbuf* dst) - { - dst->begin = src->begin; - dst->end = src->end; - dst->buffer_size = src->buffer_size; - init_tokenbuf(src); - } - -int assign_to_tokenbuf(tokenbuf* buf, const char* data, size_t len) - { - char* p = malloc(len+1); - if (p) - { - memcpy(p, data, len); - buf->begin = p; - buf->end = p + len; - buf->buffer_size = len + 1; - *((char*)(buf->end)) = '\0'; - return 1; - } - else - return 0; - } - -int append_to_tokenbuf(tokenbuf* output, const char* data, size_t len) - { - char* new_buffer; - size_t new_size; - - /* Is the tokenbuffer initialized at all? If not, allocate a - standard-sized buffer to begin with. */ - - if (output->begin == NULL) - { - if ((output->begin = output->end = malloc(VAR_INITIAL_BUFFER_SIZE)) == NULL) - return 0; - else - output->buffer_size = VAR_INITIAL_BUFFER_SIZE; - } - - /* Does the token contain text, but no buffer has been allocated - yet? */ - - if (output->buffer_size == 0) - { - /* Check whether data borders to output. If, we can append - simly by increasing the end pointer. */ - - if (output->end == data) - { - output->end += len; - return 1; - } - - /* OK, so copy the contents of output into an allocated buffer - so that we can append that way. */ - - else - { - char* tmp = malloc(output->end - output->begin + len + 1); - if (!tmp) - return 0; - memcpy(tmp, output->begin, output->end - output->begin); - output->buffer_size = output->end - output->begin; - output->begin = tmp; - output->end = tmp + output->buffer_size; - output->buffer_size += len + 1; - } - } - - /* Does the token fit into the current buffer? If not, realloc a - larger buffer that fits. */ - - if ((output->buffer_size - (output->end - output->begin)) <= len) - { - new_size = output->buffer_size; - do - { - new_size *= 2; - } - while ((new_size - (output->end - output->begin)) <= len); - new_buffer = realloc((char*)output->begin, new_size); - if (new_buffer == NULL) - return 0; - output->end = new_buffer + (output->end - output->begin); - output->begin = new_buffer; - output->buffer_size = new_size; - } - - /* Append the data at the end of the current buffer. */ - - memcpy((char*)output->end, data, len); - output->end += len; - *((char*)output->end) = '\0'; - return 1; - } - - -void free_tokenbuf(tokenbuf* buf) - { - if (buf->begin != NULL && buf->buffer_size > 0) - free((char*)buf->begin); - buf->begin = buf->end = NULL; - buf->buffer_size = 0; - } Index: ossp-pkg/var/transpose.c RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/transpose.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/Attic/transpose.c,v' | diff -u - /dev/null -L'ossp-pkg/var/transpose.c' 2>/dev/null --- ossp-pkg/var/transpose.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,97 +0,0 @@ -#include -#include -#include "internal.h" - -static int expand_class_description(tokenbuf* src, tokenbuf* dst) - { - unsigned char c, d; - const char* p = src->begin; - while(p != src->end) - { - if ((src->end - p) >= 3 && p[1] == '-') - { - printf("Expand class.\n"); - if (*p > p[2]) - return VAR_INCORRECT_TRANSPOSE_CLASS_SPEC; - for (c = *p, d = p[2]; c <= d; ++c) - { - if (!append_to_tokenbuf(dst, (char*)&c, 1)) - return VAR_OUT_OF_MEMORY; - } - p += 3; - } - else - { - printf("Copy verbatim.\n"); - if (!append_to_tokenbuf(dst, p, 1)) - return VAR_OUT_OF_MEMORY; - else - ++p; - } - } - return VAR_OK; - } - -int transpose(tokenbuf* data, tokenbuf* search, tokenbuf* replace) - { - tokenbuf srcclass, dstclass; - const char* p; - int rc; - size_t i; - - init_tokenbuf(&srcclass); - init_tokenbuf(&dstclass); - - if ((rc = expand_class_description(search, &srcclass)) != VAR_OK) - goto error_return; - if ((rc = expand_class_description(replace, &dstclass)) != VAR_OK) - goto error_return; - - printf("Transpose from '%s' to '%s'.\n", - srcclass.begin, dstclass.begin); - - if (srcclass.begin == srcclass.end) - { - rc = VAR_EMPTY_TRANSPOSE_CLASS; - goto error_return; - } - if ((srcclass.end - srcclass.begin) != (dstclass.end - dstclass.begin)) - { - rc = VAR_TRANSPOSE_CLASSES_MISMATCH; - goto error_return; - } - - if (data->buffer_size == 0) - { - tokenbuf tmp; - if (!assign_to_tokenbuf(&tmp, data->begin, data->end - data->begin)) - { - rc = VAR_OUT_OF_MEMORY; - goto error_return; - } - move_tokenbuf(&tmp, data); - } - - for (p = data->begin; p != data->end; ++p) - { - for (i = 0; i <= (srcclass.end - srcclass.begin); ++i) - { - if (*p == srcclass.begin[i]) - { - *((char*)p) = dstclass.begin[i]; - break; - } - } - } - - free_tokenbuf(&srcclass); - free_tokenbuf(&dstclass); - return VAR_OK; - - error_return: - free_tokenbuf(search); - free_tokenbuf(replace); - free_tokenbuf(&srcclass); - free_tokenbuf(&dstclass); - return rc; - } Index: ossp-pkg/var/var.c RCS File: /v/ossp/cvs/ossp-pkg/var/var.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/var.c,v' | diff -u /dev/null - -L'ossp-pkg/var/var.c' 2>/dev/null --- ossp-pkg/var/var.c +++ - 2024-05-02 01:54:42.620108024 +0200 @@ -0,0 +1,1708 @@ +/* +** VAR - OSSP variable expression library. +** Copyright (c) 2001 The OSSP Project (http://www.ossp.org/) +** Copyright (c) 2001 Cable & Wireless Deutschland (http://www.cw.com/de/) +** +** This file is part of OSSP VAR, an extensible data serialization +** library which can be found at http://www.ossp.org/pkg/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.h: VAR library API +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "var.h" + +/* The default configuration for the parser. */ + +const var_config_t var_config_default = + { + '$', /* varinit */ + '{', /* startdelim */ + '}', /* enddelim */ + '\\', /* escape */ + "a-zA-Z0-9_" /* namechars */ + }; + +/* Routines for manipulation of tokenbufs. */ + +#define VAR_INITIAL_BUFFER_SIZE 64 + +typedef struct + { + const char* begin; + const char* end; + size_t buffer_size; + } +tokenbuf; + +static void init_tokenbuf(tokenbuf* buf) + { + buf->begin = buf->end = NULL; + buf->buffer_size = 0; + } + +static void move_tokenbuf(tokenbuf* src, tokenbuf* dst) + { + dst->begin = src->begin; + dst->end = src->end; + dst->buffer_size = src->buffer_size; + init_tokenbuf(src); + } + +static int assign_to_tokenbuf(tokenbuf* buf, const char* data, size_t len) + { + char* p = malloc(len+1); + if (p) + { + memcpy(p, data, len); + buf->begin = p; + buf->end = p + len; + buf->buffer_size = len + 1; + *((char*)(buf->end)) = '\0'; + return 1; + } + else + return 0; + } + +static int append_to_tokenbuf(tokenbuf* output, const char* data, size_t len) + { + char* new_buffer; + size_t new_size; + + /* Is the tokenbuffer initialized at all? If not, allocate a + standard-sized buffer to begin with. */ + + if (output->begin == NULL) + { + if ((output->begin = output->end = malloc(VAR_INITIAL_BUFFER_SIZE)) == NULL) + return 0; + else + output->buffer_size = VAR_INITIAL_BUFFER_SIZE; + } + + /* Does the token contain text, but no buffer has been allocated + yet? */ + + if (output->buffer_size == 0) + { + /* Check whether data borders to output. If, we can append + simly by increasing the end pointer. */ + + if (output->end == data) + { + output->end += len; + return 1; + } + + /* OK, so copy the contents of output into an allocated buffer + so that we can append that way. */ + + else + { + char* tmp = malloc(output->end - output->begin + len + 1); + if (!tmp) + return 0; + memcpy(tmp, output->begin, output->end - output->begin); + output->buffer_size = output->end - output->begin; + output->begin = tmp; + output->end = tmp + output->buffer_size; + output->buffer_size += len + 1; + } + } + + /* Does the token fit into the current buffer? If not, realloc a + larger buffer that fits. */ + + if ((output->buffer_size - (output->end - output->begin)) <= len) + { + new_size = output->buffer_size; + do + { + new_size *= 2; + } + while ((new_size - (output->end - output->begin)) <= len); + new_buffer = realloc((char*)output->begin, new_size); + if (new_buffer == NULL) + return 0; + output->end = new_buffer + (output->end - output->begin); + output->begin = new_buffer; + output->buffer_size = new_size; + } + + /* Append the data at the end of the current buffer. */ + + memcpy((char*)output->end, data, len); + output->end += len; + *((char*)output->end) = '\0'; + return 1; + } + +static void free_tokenbuf(tokenbuf* buf) + { + if (buf->begin != NULL && buf->buffer_size > 0) + free((char*)buf->begin); + buf->begin = buf->end = NULL; + buf->buffer_size = 0; + } + +static size_t tokenbuf2int(tokenbuf* number) + { + const char* p; + size_t num = 0; + for (p = number->begin; p != number->end; ++p) + { + num *= 10; + num += *p - '0'; + } + return num; + } + +/* Routines for the expansion of quoted-pair expressions. */ + +static void expand_range(char a, char b, char class[256]) + { + assert(a <= b); + assert(class != NULL); + + do + { + class[(int)a] = 1; + } + while (++a <= b); + } + +static var_rc_t expand_character_class(const char* desc, char class[256]) + { + size_t i; + + assert(desc != NULL); + assert(class != NULL); + + /* Clear the class array. */ + + for (i = 0; i < 256; ++i) + class[i] = 0; + + /* Walk through the class description and set the appropriate + entries in the array. */ + + while(*desc != '\0') + { + if (desc[1] == '-' && desc[2] != '\0') + { + if (desc[0] > desc[2]) + return VAR_INCORRECT_CLASS_SPEC; + expand_range(desc[0], desc[2], class); + desc += 3; + } + else + { + class[(int)*desc] = 1; + ++desc; + } + } + + return VAR_OK; + } + +static int isoct(char c) + { + if (c >= '0' && c <= '7') + return 1; + else + return 0; + } + +static var_rc_t expand_octal(const char** src, char** dst, const char* end) + { + unsigned char c; + + if (end - *src < 3) + return VAR_INCOMPLETE_OCTAL; + if (!isoct(**src) || !isoct((*src)[1]) || !isoct((*src)[2])) + return VAR_INVALID_OCTAL; + + c = **src - '0'; + if (c > 3) + return VAR_OCTAL_TOO_LARGE; + c *= 8; + ++(*src); + + c += **src - '0'; + c *= 8; + ++(*src); + + c += **src - '0'; + + **dst = (char)c; + ++(*dst); + return VAR_OK; + } + +static int ishex(char c) + { + if ((c >= '0' && c <= '9') || + (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F')) + return 1; + else + return 0; + } + +static var_rc_t expand_simple_hex(const char** src, char** dst, const char* end) + { + unsigned char c = 0; + + if (end - *src < 2) + return VAR_INCOMPLETE_HEX; + if (!ishex(**src) || !ishex((*src)[1])) + return VAR_INVALID_HEX; + + if (**src >= '0' && **src <= '9') + c = **src - '0'; + else if (c >= 'a' && c <= 'f') + c = **src - 'a' + 10; + else if (c >= 'A' && c <= 'F') + c = **src - 'A' + 10; + + c = c << 4; + ++(*src); + + if (**src >= '0' && **src <= '9') + c += **src - '0'; + else if (**src >= 'a' && **src <= 'f') + c += **src - 'a' + 10; + else if (**src >= 'A' && **src <= 'F') + c += **src - 'A' + 10; + + **dst = (char)c; + ++(*dst); + return VAR_OK; + } + +static var_rc_t expand_grouped_hex(const char** src, char** dst, const char* end) + { + var_rc_t rc; + + while (*src < end && **src != '}') + { + if ((rc = expand_simple_hex(src, dst, end)) != 0) + return rc; + ++(*src); + } + if (*src == end) + return VAR_INCOMPLETE_GROUPED_HEX; + + return VAR_OK; + } + +static var_rc_t expand_hex(const char** src, char** dst, const char* end) + { + if (*src == end) + return VAR_INCOMPLETE_HEX; + if (**src == '{') + { + ++(*src); + return expand_grouped_hex(src, dst, end); + } + else + return expand_simple_hex(src, dst, end); + } + +var_rc_t expand_named_characters(const char* src, size_t len, char* dst) + { + const char* end = src + len; + var_rc_t rc; + + assert(src != NULL); + assert(dst != NULL); + + while (src < end) + { + if (*src == '\\') + { + if (++src == end) + return VAR_INCOMPLETE_NAMED_CHARACTER; + switch (*src) + { + case 'n': + *dst++ = '\n'; + break; + case 't': + *dst++ = '\t'; + break; + case 'r': + *dst++ = '\r'; + break; + case 'x': + ++src; + if ((rc = expand_hex(&src, &dst, end)) != 0) + return rc; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if ((rc = expand_octal(&src, &dst, end)) != 0) + return rc; + break; + default: + *dst++ = *src; + } + ++src; + } + else + *dst++ = *src++; + } + *dst = '\0'; + return VAR_OK; + } + +/* The recursive-descent parser for variable expressions. */ + +static int variable(const char*, const char*, const var_config_t*, + const char[256], var_cb_t, void*, int, tokenbuf*); +static int command(const char*, const char*, const var_config_t*, + const char[256], var_cb_t, void*, int, tokenbuf*); + +static int text(const char* begin, const char* end, char varinit, char escape) + { + const char* p; + for (p = begin; p != end && *p != varinit; ++p) + { + if (*p == escape) + { + if (p+1 == end) + return VAR_INCOMPLETE_QUOTED_PAIR; + else + ++p; + } + } + return p - begin; + } + +static int varname(const char* begin, const char* end, const char nameclass[256]) + { + const char* p; + for (p = begin; p != end && nameclass[(int)*p]; ++p) + ; + return p - begin; + } + +static int number(const char* begin, const char* end) + { + const char* p; + for (p = begin; p != end && isdigit(*p); ++p) + ; + return p - begin; + } + +static int substext(const char* begin, const char* end, const var_config_t* config) + { + const char* p; + for (p = begin; p != end && *p != config->varinit && *p != '/'; ++p) + { + if (*p == config->escape) + { + if (p+1 == end) + return VAR_INCOMPLETE_QUOTED_PAIR; + else + ++p; + } + } + return p - begin; + } + +static int exptext(const char* begin, const char* end, const var_config_t* config) + { + const char* p; + for (p = begin; p != end && *p != config->varinit && *p != config->enddelim && *p != ':'; ++p) + { + if (*p == config->escape) + { + if (p+1 == end) + return VAR_INCOMPLETE_QUOTED_PAIR; + else + ++p; + } + } + return p - begin; + } + + +static int expression(const char* begin, const char* end, const var_config_t* config, + const char nameclass[256], var_cb_t lookup, void* lookup_context, + int force_expand, tokenbuf* result) + { + const char* p = begin; + const char* data; + size_t len, buffer_size; + int failed = 0; + int rc; + tokenbuf name; + tokenbuf tmp; + + /* Clear the tokenbufs to make sure we have a defined state. */ + + init_tokenbuf(&name); + init_tokenbuf(&tmp); + init_tokenbuf(result); + + /* Expect STARTDELIM. */ + + if (p == end || *p != config->startdelim) + return 0; + + if (++p == end) + return VAR_INCOMPLETE_VARIABLE_SPEC; + + /* Get the name of the variable to expand. The name may consist of + an arbitrary number of VARNAMEs and VARIABLEs. */ + + do + { + rc = varname(p, end, nameclass); + if (rc < 0) + goto error_return; + else if (rc > 0) + { + if (!append_to_tokenbuf(&name, p, rc)) + { + rc = VAR_OUT_OF_MEMORY; + goto error_return; + } + else + p += rc; + } + + rc = variable(p, end, config, nameclass, lookup, lookup_context, force_expand, &tmp); + if (rc < 0) + goto error_return; + else if (rc > 0) + { + if (!append_to_tokenbuf(&name, tmp.begin, tmp.end - tmp.begin)) + { + rc = VAR_OUT_OF_MEMORY; + goto error_return; + } + else + p += rc; + } + } + while (rc > 0); + + /* We must have the complete variable name now, so make sure we + do. */ + + if (name.begin == name.end) + { + rc = VAR_INCOMPLETE_VARIABLE_SPEC; + goto error_return; + } + + /* Now we have the name of the variable stored in "name". We + expect an ENDDELIM here. */ + + if (p == end || (*p != config->enddelim && *p != ':')) + { + rc = VAR_INCOMPLETE_VARIABLE_SPEC; + goto error_return; + } + else + ++p; + + /* Use the lookup callback to get the variable's contents. */ + + rc = (*lookup)(lookup_context, name.begin, name.end - name.begin, &data, &len, &buffer_size); + if (rc < 0) + goto error_return; + else if (rc == 0) + { + /* The variable is undefined. What we'll do now depends on the + force_expand flag. */ + + if (force_expand) + { + rc = VAR_UNDEFINED_VARIABLE; + goto error_return; + } + else + { + /* Initialize result to point back to the original text in + the buffer. */ + + result->begin = begin-1; + result->end = p; + result->buffer_size = 0; + failed = 1; + } + } + else + { + /* The preliminary result is the contents of the variable. + This may be modified by the commands that may follow. */ + + result->begin = data; + result->end = data + len; + result->buffer_size = buffer_size; + } + + if (p[-1] == ':') + { + /* Parse and execute commands. */ + + free_tokenbuf(&tmp); + --p; + while (p != end && *p == ':') + { + ++p; + if (!failed) + rc = command(p, end, config, nameclass, lookup, lookup_context, force_expand, result); + else + rc = command(p, end, config, nameclass, lookup, lookup_context, force_expand, &tmp); + if (rc < 0) + goto error_return; + p += rc; + if (failed) + result->end += rc; + } + + if (p == end || *p != config->enddelim) + { + rc = VAR_INCOMPLETE_VARIABLE_SPEC; + goto error_return; + } + ++p; + if (failed) + ++result->end; + } + + /* Exit gracefully. */ + + free_tokenbuf(&name); + free_tokenbuf(&tmp); + return p - begin; + + /* Exit in case of an error. */ + + error_return: + free_tokenbuf(&name); + free_tokenbuf(&tmp); + free_tokenbuf(result); + return rc; + } + +static int variable(const char* begin, const char* end, const var_config_t* config, + const char nameclass[256], var_cb_t lookup, void* lookup_context, + int force_expand, tokenbuf* result) + { + const char* p = begin; + const char* data; + size_t len, buffer_size; + int rc, rc2; + + /* Clear the result tokenbuf to make sure we're in a defined + state. */ + + init_tokenbuf(result); + + /* Expect VARINIT. */ + + if (p == end || *p != config->varinit) + return 0; + + if (++p == end) + return VAR_INCOMPLETE_VARIABLE_SPEC; + + /* Try to read the variable name. If that fails, we're parsing a + complex expression. */ + + rc = varname(p, end, nameclass); + if (rc < 0) + return rc; + else if (rc > 0) + { + rc2 = (*lookup)(lookup_context, p, rc, &data, &len, &buffer_size); + if (rc2 < 0) + return rc2; + else if (rc2 == 0) + { + if (force_expand) + return VAR_UNDEFINED_VARIABLE; + else + { + result->begin = begin; + result->end = begin + 1 + rc; + result->buffer_size = 0; + return 1 + rc; + } + } + else + { + result->begin = data; + result->end = data + len; + result->buffer_size = buffer_size; + return 1 + rc; + } + } + + /* OK, we're dealing with a complex expression here. */ + + rc = expression(p, end, config, nameclass, lookup, lookup_context, force_expand, result); + if (rc > 0) + ++rc; + return rc; + } + +static int exptext_or_variable(const char* begin, const char* end, const var_config_t* config, + const char nameclass[256], var_cb_t lookup, void* lookup_context, + int force_expand, tokenbuf* result) + { + const char* p = begin; + tokenbuf tmp; + int rc; + + init_tokenbuf(result); + init_tokenbuf(&tmp); + + if (begin == end) + return 0; + + do + { + rc = exptext(p, end, config); + if (rc < 0) + goto error_return; + else if (rc > 0) + { + if (!append_to_tokenbuf(result, p, rc)) + { + rc = VAR_OUT_OF_MEMORY; + goto error_return; + } + else + p += rc; + } + + rc = variable(p, end, config, nameclass, lookup, lookup_context, force_expand, &tmp); + if (rc < 0) + goto error_return; + else if (rc > 0) + { + p += rc; + if (!append_to_tokenbuf(result, tmp.begin, tmp.end - tmp.begin)) + { + rc = VAR_OUT_OF_MEMORY; + goto error_return; + } + } + } + while (rc > 0); + + free_tokenbuf(&tmp); + return p - begin; + + error_return: + free_tokenbuf(&tmp); + free_tokenbuf(result); + return rc; + } + +static int substext_or_variable(const char* begin, const char* end, const var_config_t* config, + const char nameclass[256], var_cb_t lookup, void* lookup_context, + int force_expand, tokenbuf* result) + { + const char* p = begin; + tokenbuf tmp; + int rc; + + init_tokenbuf(result); + init_tokenbuf(&tmp); + + if (begin == end) + return 0; + + do + { + rc = substext(p, end, config); + if (rc < 0) + goto error_return; + else if (rc > 0) + { + if (!append_to_tokenbuf(result, p, rc)) + { + rc = VAR_OUT_OF_MEMORY; + goto error_return; + } + else + p += rc; + } + + rc = variable(p, end, config, nameclass, lookup, lookup_context, force_expand, &tmp); + if (rc < 0) + goto error_return; + else if (rc > 0) + { + p += rc; + if (!append_to_tokenbuf(result, tmp.begin, tmp.end - tmp.begin)) + { + rc = VAR_OUT_OF_MEMORY; + goto error_return; + } + } + } + while (rc > 0); + + free_tokenbuf(&tmp); + return p - begin; + + error_return: + free_tokenbuf(&tmp); + free_tokenbuf(result); + return rc; + } + + +static int expand_class_description(tokenbuf* src, tokenbuf* dst) + { + unsigned char c, d; + const char* p = src->begin; + while(p != src->end) + { + if ((src->end - p) >= 3 && p[1] == '-') + { + printf("Expand class.\n"); + if (*p > p[2]) + return VAR_INCORRECT_TRANSPOSE_CLASS_SPEC; + for (c = *p, d = p[2]; c <= d; ++c) + { + if (!append_to_tokenbuf(dst, (char*)&c, 1)) + return VAR_OUT_OF_MEMORY; + } + p += 3; + } + else + { + printf("Copy verbatim.\n"); + if (!append_to_tokenbuf(dst, p, 1)) + return VAR_OUT_OF_MEMORY; + else + ++p; + } + } + return VAR_OK; + } + +static int transpose(tokenbuf* data, tokenbuf* search, tokenbuf* replace) + { + tokenbuf srcclass, dstclass; + const char* p; + int rc; + size_t i; + + init_tokenbuf(&srcclass); + init_tokenbuf(&dstclass); + + if ((rc = expand_class_description(search, &srcclass)) != VAR_OK) + goto error_return; + if ((rc = expand_class_description(replace, &dstclass)) != VAR_OK) + goto error_return; + + printf("Transpose from '%s' to '%s'.\n", + srcclass.begin, dstclass.begin); + + if (srcclass.begin == srcclass.end) + { + rc = VAR_EMPTY_TRANSPOSE_CLASS; + goto error_return; + } + if ((srcclass.end - srcclass.begin) != (dstclass.end - dstclass.begin)) + { + rc = VAR_TRANSPOSE_CLASSES_MISMATCH; + goto error_return; + } + + if (data->buffer_size == 0) + { + tokenbuf tmp; + if (!assign_to_tokenbuf(&tmp, data->begin, data->end - data->begin)) + { + rc = VAR_OUT_OF_MEMORY; + goto error_return; + } + move_tokenbuf(&tmp, data); + } + + for (p = data->begin; p != data->end; ++p) + { + for (i = 0; i <= (srcclass.end - srcclass.begin); ++i) + { + if (*p == srcclass.begin[i]) + { + *((char*)p) = dstclass.begin[i]; + break; + } + } + } + + free_tokenbuf(&srcclass); + free_tokenbuf(&dstclass); + return VAR_OK; + + error_return: + free_tokenbuf(search); + free_tokenbuf(replace); + free_tokenbuf(&srcclass); + free_tokenbuf(&dstclass); + return rc; + } + +static int cut_out_offset(tokenbuf* data, tokenbuf* number1, tokenbuf* number2, int isrange) + { + tokenbuf res; + const char* p; + size_t num1 = tokenbuf2int(number1); + size_t num2 = tokenbuf2int(number2); + + /* Determine begin of result string. */ + + if ((data->end - data->begin) < num1) + return VAR_OFFSET_OUT_OF_BOUNDS; + else + p = data->begin + num1; + + /* If num2 is zero, we copy the rest from there. */ + + if (num2 == 0) + { + if (!assign_to_tokenbuf(&res, p, data->end - p)) + return VAR_OUT_OF_MEMORY; + } + else /* OK, then use num2. */ + { + if (isrange) + { + if ((p + num2) > data->end) + return VAR_RANGE_OUT_OF_BOUNDS; + if (!assign_to_tokenbuf(&res, p, num2)) + return VAR_OUT_OF_MEMORY; + } + else + { + if (num2 < num1) + return VAR_OFFSET_LOGIC_ERROR; + if ((data->begin + num2) > data->end) + return VAR_RANGE_OUT_OF_BOUNDS; + if (!assign_to_tokenbuf(&res, p, (data->begin + num2) - p)) + return VAR_OUT_OF_MEMORY; + } + } + free_tokenbuf(data); + move_tokenbuf(&res, data); + return VAR_OK; + } + +static int search_and_replace(tokenbuf* data, tokenbuf* search, tokenbuf* replace, tokenbuf* flags) + { + const char* p; + int case_insensitive = 0; + int global = 0; + int no_regex = 0; + int rc; + + if (search->begin == search->end) + return VAR_EMPTY_SEARCH_STRING; + + printf("Search '%s' in '%s' and replace it with '%s'.\n", + search->begin, data->begin, replace->begin); + + for (p = flags->begin; p != flags->end; ++p) + { + switch (tolower(*p)) + { + case 'i': + case_insensitive = 1; + printf("case_insensitive = 1;\n"); + break; + case 'g': + global = 1; + printf("global = 1;\n"); + break; + case 't': + no_regex = 1; + printf("no_regex = 1;\n"); + break; + default: + return VAR_UNKNOWN_REPLACE_FLAG; + } + } + + if (no_regex) + { + tokenbuf tmp; + init_tokenbuf(&tmp); + + for (p = data->begin; p != data->end; ) + { + if (case_insensitive) + rc = strncasecmp(p, search->begin, search->end - search->begin); + else + rc = strncmp(p, search->begin, search->end - search->begin); + if (rc != 0) + { /* no match, copy character */ + if (!append_to_tokenbuf(&tmp, p, 1)) + { + free_tokenbuf(&tmp); + return VAR_OUT_OF_MEMORY; + } + ++p; + } + else + { + append_to_tokenbuf(&tmp, replace->begin, replace->end - replace->begin); + p += search->end - search->begin; + if (!global) + { + if (!append_to_tokenbuf(&tmp, p, data->end - p)) + { + free_tokenbuf(&tmp); + return VAR_OUT_OF_MEMORY; + } + break; + } + } + } + + free_tokenbuf(data); + move_tokenbuf(&tmp, data); + } + else + { + tokenbuf tmp; + tokenbuf mydata; + regex_t preg; + regmatch_t pmatch[33]; + int regexec_flag; + + /* Copy the pattern and the data to our own buffer to make + sure they're terminated with a null byte. */ + + if (!assign_to_tokenbuf(&tmp, search->begin, search->end - search->begin)) + return VAR_OUT_OF_MEMORY; + if (!assign_to_tokenbuf(&mydata, data->begin, data->end - data->begin)) + { + free_tokenbuf(&tmp); + return VAR_OUT_OF_MEMORY; + } + + /* Compile the pattern. */ + + printf("data is.................: '%s'\n", mydata.begin); + printf("regex search pattern is.: '%s'\n", tmp.begin); + printf("regex replace pattern is: '%s'\n", replace->begin); + rc = regcomp(&preg, tmp.begin, REG_EXTENDED | ((case_insensitive) ? REG_ICASE : 0)); + free_tokenbuf(&tmp); + if (rc != 0) + { + free_tokenbuf(&mydata); + return VAR_INVALID_REGEX_IN_REPLACE; + } + printf("Subexpression in pattern: '%d'\n", preg.re_nsub); + + /* Match the pattern and create the result string in the tmp + buffer. */ + + for (p = mydata.begin; p != mydata.end; ) + { + if (p == mydata.begin || p[-1] == '\n') + regexec_flag = 0; + else + regexec_flag = REG_NOTBOL; + if (regexec(&preg, p, sizeof(pmatch) / sizeof(regmatch_t), pmatch, regexec_flag) == REG_NOMATCH) + { + printf("No match; appending remainder ('%s') to output string.\n", p); + append_to_tokenbuf(&tmp, p, mydata.end - p); + break; + } + else + { + if (!append_to_tokenbuf(&tmp, p, pmatch[0].rm_so) || + !append_to_tokenbuf(&tmp, replace->begin, replace->end - replace->begin)) + { + regfree(&preg); + free_tokenbuf(&tmp); + free_tokenbuf(&mydata); + return VAR_OUT_OF_MEMORY; + } + else + p += pmatch[0].rm_eo; + if (!global) + { + append_to_tokenbuf(&tmp, p, mydata.end - p); + break; + } + } + } + + regfree(&preg); + free_tokenbuf(data); + move_tokenbuf(&tmp, data); + free_tokenbuf(&mydata); + } + + return VAR_OK; + } + +static int padding(tokenbuf* data, tokenbuf* widthstr, tokenbuf* fill, char position) + { + tokenbuf result; + size_t width = tokenbuf2int(widthstr); + int i; + + printf("Padding data '%s' to width '%d' by filling in '%s' to position '%c'.\n", + data->begin, width, fill->begin, position); + + if (fill->begin == fill->end) + return VAR_EMPTY_PADDING_FILL_STRING; + + init_tokenbuf(&result); + + if (position == 'l') + { + i = width - (data->end - data->begin); + if (i > 0) + { + printf("Missing %d characters at the end of the data string.\n", i); + i = i / (fill->end - fill->begin); + printf("That's %d times the padding string.\n", i); + while(i > 0) + { + if (!append_to_tokenbuf(data, fill->begin, fill->end - fill->begin)) + return VAR_OUT_OF_MEMORY; + --i; + } + i = (width - (data->end - data->begin)) % (fill->end - fill->begin); + printf("Plus a remainder of %d characters.\n", i); + if (!append_to_tokenbuf(data, fill->begin, i)) + return VAR_OUT_OF_MEMORY; + } + } + else if (position == 'r') + { + i = width - (data->end - data->begin); + if (i > 0) + { + printf("Missing %d characters at the beginning of the data string.\n", i); + i = i / (fill->end - fill->begin); + printf("That's %d times the padding string.\n", i); + while(i > 0) + { + if (!append_to_tokenbuf(&result, fill->begin, fill->end - fill->begin)) + { + free_tokenbuf(&result); + return VAR_OUT_OF_MEMORY; + } + --i; + } + i = (width - (data->end - data->begin)) % (fill->end - fill->begin); + printf("Plus a remainder of %d characters.\n", i); + if (!append_to_tokenbuf(&result, fill->begin, i)) + { + free_tokenbuf(&result); + return VAR_OUT_OF_MEMORY; + } + if (!append_to_tokenbuf(&result, data->begin, data->end - data->begin)) + { + free_tokenbuf(&result); + return VAR_OUT_OF_MEMORY; + } + + free_tokenbuf(data); + move_tokenbuf(&result, data); + } + } + else if (position == 'c') + { + i = (width - (data->end - data->begin)) / 2; + if (i > 0) + { + /* Create the prefix. */ + + printf("Missing %d characters at the beginning of the data string.\n", i); + i = i / (fill->end - fill->begin); + printf("That's %d times the padding string.\n", i); + while(i > 0) + { + if (!append_to_tokenbuf(&result, fill->begin, fill->end - fill->begin)) + { + free_tokenbuf(&result); + return VAR_OUT_OF_MEMORY; + } + --i; + } + i = ((width - (data->end - data->begin)) / 2) % (fill->end - fill->begin); + printf("Plus a remainder of %d characters.\n", i); + if (!append_to_tokenbuf(&result, fill->begin, i)) + { + free_tokenbuf(&result); + return VAR_OUT_OF_MEMORY; + } + + /* Append the actual data string. */ + + if (!append_to_tokenbuf(&result, data->begin, data->end - data->begin)) + { + free_tokenbuf(&result); + return VAR_OUT_OF_MEMORY; + } + + /* Append the suffix. */ + + i = width - (result.end - result.begin); + printf("Missing %d characters at the end of the data string.\n", i); + i = i / (fill->end - fill->begin); + printf("That's %d times the padding string.\n", i); + while(i > 0) + { + if (!append_to_tokenbuf(&result, fill->begin, fill->end - fill->begin)) + { + free_tokenbuf(&result); + return VAR_OUT_OF_MEMORY; + } + --i; + } + i = width - (result.end - result.begin); + printf("Plus a remainder of %d characters.\n", i); + if (!append_to_tokenbuf(&result, fill->begin, i)) + { + free_tokenbuf(&result); + return VAR_OUT_OF_MEMORY; + } + + /* Move string from temporary buffer to data buffer. */ + + free_tokenbuf(data); + move_tokenbuf(&result, data); + } + } + + return VAR_OK; + } + +static int command(const char* begin, const char* end, const var_config_t* config, + const char nameclass[256], var_cb_t lookup, void* lookup_context, + int force_expand, tokenbuf* data) + { + const char* p = begin; + tokenbuf tmptokbuf; + tokenbuf search, replace, flags; + tokenbuf number1, number2; + int isrange; + int rc; + + init_tokenbuf(&tmptokbuf); + init_tokenbuf(&search); + init_tokenbuf(&replace); + init_tokenbuf(&flags); + init_tokenbuf(&number1); + init_tokenbuf(&number2); + + if (begin == end) + return 0; + + switch (tolower(*p)) + { + case 'l': /* Turn data to lowercase. */ + if (data->begin) + { + char* ptr; + /* If the buffer does not life in an allocated buffer, + we have to copy it before modifying the contents. */ + + if (data->buffer_size == 0) + { + if (!assign_to_tokenbuf(data, data->begin, data->end - data->begin)) + { + rc = VAR_OUT_OF_MEMORY; + goto error_return; + } + } + for (ptr = (char*)data->begin; ptr != data->end; ++ptr) + *ptr = tolower(*ptr); + } + ++p; + break; + + case 'u': /* Turn data to uppercase. */ + if (data->begin) + { + char* ptr; + if (data->buffer_size == 0) + { + if (!assign_to_tokenbuf(data, data->begin, data->end - data->begin)) + { + rc = VAR_OUT_OF_MEMORY; + goto error_return; + } + } + for (ptr = (char*)data->begin; ptr != data->end; ++ptr) + *ptr = toupper(*ptr); + } + ++p; + break; + + case 'o': /* Cut out substrings. */ + ++p; + rc = number(p, end); + if (rc == 0) + { + rc = VAR_MISSING_START_OFFSET; + goto error_return; + } + else + { + number1.begin = p; + number1.end = p + rc; + number1.buffer_size = 0; + p += rc; + } + + if (*p == ',') + { + isrange = 0; + ++p; + } + else if (*p == '-') + { + isrange = 1; + ++p; + } + else + { + rc = VAR_INVALID_OFFSET_DELIMITER; + goto error_return; + } + + rc = number(p, end); + number2.begin = p; + number2.end = p + rc; + number2.buffer_size = 0; + p += rc; + if (data->begin) + { + rc = cut_out_offset(data, &number1, &number2, isrange); + if (rc < 0) + goto error_return; + } + break; + + case '#': /* Substitute length of the string. */ + if (data->begin) + { + char buf[1024]; + sprintf(buf, "%d", data->end - data->begin); + free_tokenbuf(data); + if (!assign_to_tokenbuf(data, buf, strlen(buf))) + { + rc = VAR_OUT_OF_MEMORY; + goto error_return; + } + } + ++p; + break; + + case '-': /* Substitute parameter if data is empty. */ + ++p; + rc = exptext_or_variable(p, end, config, nameclass, lookup, lookup_context, + force_expand, &tmptokbuf); + if (rc < 0) + goto error_return; + else if (rc == 0) + { + rc = VAR_MISSING_PARAMETER_IN_COMMAND; + goto error_return; + } + else + p += rc; + if (data->begin != NULL && data->begin == data->end) + { + free_tokenbuf(data); + move_tokenbuf(&tmptokbuf, data); + } + break; + + case '*': /* Return "" if data is not empty, parameter otherwise. */ + ++p; + rc = exptext_or_variable(p, end, config, nameclass, lookup, lookup_context, + force_expand, &tmptokbuf); + if (rc < 0) + goto error_return; + else if (rc == 0) + { + rc = VAR_MISSING_PARAMETER_IN_COMMAND; + goto error_return; + } + else + p += rc; + if (data->begin != NULL) + { + if (data->begin == data->end) + { + free_tokenbuf(data); + move_tokenbuf(&tmptokbuf, data); + } + else + { + free_tokenbuf(data); + data->begin = data->end = ""; + data->buffer_size = 0; + } + } + break; + + case '+': /* Substitute parameter if data is not empty. */ + ++p; + rc = exptext_or_variable(p, end, config, nameclass, lookup, lookup_context, + force_expand, &tmptokbuf); + if (rc < 0) + goto error_return; + else if (rc == 0) + { + rc = VAR_MISSING_PARAMETER_IN_COMMAND; + goto error_return; + } + else + p += rc; + if (data->begin != NULL) + { + if (data->begin != data->end) + { + free_tokenbuf(data); + move_tokenbuf(&tmptokbuf, data); + } + } + break; + + case 's': /* Search and replace. */ + ++p; + + if (*p != '/') + return VAR_MALFORMATTED_REPLACE; + else + ++p; + + rc = substext_or_variable(p, end, config, nameclass, lookup, lookup_context, + force_expand, &search); + if (rc < 0) + goto error_return; + else + p += rc; + + if (*p != '/') + { + rc = VAR_MALFORMATTED_REPLACE; + goto error_return; + } + else + ++p; + + rc = substext_or_variable(p, end, config, nameclass, lookup, lookup_context, + force_expand, &replace); + if (rc < 0) + goto error_return; + else + p += rc; + + if (*p != '/') + { + rc = VAR_MALFORMATTED_REPLACE; + goto error_return; + } + else + ++p; + + rc = exptext(p, end, config); + if (rc < 0) + goto error_return; + else + { + flags.begin = p; + flags.end = p + rc; + flags.buffer_size = 0; + p += rc; + } + + if (data->begin) + { + rc = search_and_replace(data, &search, &replace, &flags); + if (rc < 0) + goto error_return; + } + break; + + case 'y': /* Transpose characters from class A to class B. */ + ++p; + + if (*p != '/') + return VAR_MALFORMATTED_TRANSPOSE; + else + ++p; + + rc = substext_or_variable(p, end, config, nameclass, lookup, lookup_context, + force_expand, &search); + if (rc < 0) + goto error_return; + else + p += rc; + + if (*p != '/') + { + rc = VAR_MALFORMATTED_TRANSPOSE; + goto error_return; + } + else + ++p; + + rc = substext_or_variable(p, end, config, nameclass, lookup, lookup_context, + force_expand, &replace); + if (rc < 0) + goto error_return; + else + p += rc; + + if (*p != '/') + { + rc = VAR_MALFORMATTED_TRANSPOSE; + goto error_return; + } + else + ++p; + + if (data->begin) + { + rc = transpose(data, &search, &replace); + if (rc < 0) + goto error_return; + } + break; + + + case 'p': /* Padding. */ + ++p; + + if (*p != '/') + return VAR_MALFORMATTED_PADDING; + else + ++p; + + rc = number(p, end); + if (rc == 0) + { + rc = VAR_MISSING_PADDING_WIDTH; + goto error_return; + } + else + { + number1.begin = p; + number1.end = p + rc; + number1.buffer_size = 0; + p += rc; + } + + if (*p != '/') + { + rc = VAR_MALFORMATTED_PADDING; + goto error_return; + } + else + ++p; + + rc = substext_or_variable(p, end, config, nameclass, lookup, lookup_context, + force_expand, &replace); + if (rc < 0) + goto error_return; + else + p += rc; + + if (*p != '/') + { + rc = VAR_MALFORMATTED_PADDING; + goto error_return; + } + else + ++p; + + if (*p != 'l' && *p != 'c' && *p != 'r') + { + rc = VAR_MALFORMATTED_PADDING; + goto error_return; + } + else + ++p; + + if (data->begin) + { + rc = padding(data, &number1, &replace, p[-1]); + if (rc < 0) + goto error_return; + } + break; + + default: + return VAR_UNKNOWN_COMMAND_CHAR; + } + + /* Exit gracefully. */ + + free_tokenbuf(&tmptokbuf); + free_tokenbuf(&search); + free_tokenbuf(&replace); + free_tokenbuf(&flags); + free_tokenbuf(&number1); + free_tokenbuf(&number2); + return p - begin; + + error_return: + free_tokenbuf(data); + free_tokenbuf(&tmptokbuf); + free_tokenbuf(&search); + free_tokenbuf(&replace); + free_tokenbuf(&flags); + free_tokenbuf(&number1); + free_tokenbuf(&number2); + return rc; + } + +static var_rc_t input(const char* begin, const char* end, const var_config_t* config, + const char nameclass[256], var_cb_t lookup, void* lookup_context, + int force_expand, tokenbuf* output) + { + int rc; + tokenbuf result; + + init_tokenbuf(&result); + + do + { + rc = text(begin, end, config->varinit, config->escape); + if (rc > 0) + { + if (!append_to_tokenbuf(output, begin, rc)) + { + rc = VAR_OUT_OF_MEMORY; + goto error_return; + } + begin += rc; + } + else if (rc < 0) + goto error_return; + + rc = variable(begin, end, config, nameclass, lookup, lookup_context, force_expand, &result); + if (rc > 0) + { + if (!append_to_tokenbuf(output, result.begin, result.end - result.begin)) + { + rc = VAR_OUT_OF_MEMORY; + goto error_return; + } + else + begin += rc; + } + else if (rc < 0) + goto error_return; + } + while (rc > 0); + + if (begin != end) + { + rc = VAR_INPUT_ISNT_TEXT_NOR_VARIABLE; + goto error_return; + } + + return VAR_OK; + + error_return: + free_tokenbuf(&result); + return rc; + } + +var_rc_t var_expand(const char* input_buf, size_t input_len, + char** result, size_t* result_len, + var_cb_t lookup, void* lookup_context, + const var_config_t* config, int force_expand) + { + char nameclass[256]; + var_rc_t rc; + tokenbuf output; + + /* Assert everything is as we expect it. */ + + assert(input_buf != NULL); + assert(result != NULL); + assert(result_len != NULL); + assert(lookup != NULL); + + /* Expand the class description for valid variable names. */ + + if (config == NULL) + config = &var_config_default; + rc = expand_character_class(config->namechars, nameclass); + if (rc != VAR_OK) + return rc; + + /* Make sure that the specials defined in the configuration do not + appear in the character name class. */ + + if (nameclass[(int)config->varinit] || + nameclass[(int)config->startdelim] || + nameclass[(int)config->enddelim] || + nameclass[(int)config->escape]) + return VAR_INVALID_CONFIGURATION; + + /* Call the parser. */ + + output.begin = output.end = NULL; + output.buffer_size = 0; + rc = input(input_buf, input_buf + input_len, config, nameclass, + lookup, lookup_context, force_expand, &output); + if (rc != VAR_OK) + { + free_tokenbuf(&output); + return rc; + } + *result = (char*)output.begin; + *result_len = output.end - output.begin; + + return VAR_OK; + } Index: ossp-pkg/var/var.h RCS File: /v/ossp/cvs/ossp-pkg/var/var.h,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/var.h,v' | diff -u /dev/null - -L'ossp-pkg/var/var.h' 2>/dev/null --- ossp-pkg/var/var.h +++ - 2024-05-02 01:54:42.628247567 +0200 @@ -0,0 +1,127 @@ +#ifndef LIB_VARIABLE_EXPAND_H +#define LIB_VARIABLE_EXPAND_H + +#include + +/* Error codes returned by the varexp library. */ + +typedef enum + { + VAR_EMPTY_PADDING_FILL_STRING = -32, + VAR_MISSING_PADDING_WIDTH = -31, + VAR_MALFORMATTED_PADDING = -30, + VAR_INCORRECT_TRANSPOSE_CLASS_SPEC = -29, + VAR_EMPTY_TRANSPOSE_CLASS = -28, + VAR_TRANSPOSE_CLASSES_MISMATCH = -27, + VAR_MALFORMATTED_TRANSPOSE = -26, + VAR_OFFSET_LOGIC_ERROR = -25, + VAR_OFFSET_OUT_OF_BOUNDS = -24, + VAR_RANGE_OUT_OF_BOUNDS = -23, + VAR_INVALID_OFFSET_DELIMITER = -22, + VAR_MISSING_START_OFFSET = -21, + VAR_EMPTY_SEARCH_STRING = -20, + VAR_MISSING_PARAMETER_IN_COMMAND = -19, + VAR_INVALID_REGEX_IN_REPLACE = -18, + VAR_UNKNOWN_REPLACE_FLAG = -17, + VAR_MALFORMATTED_REPLACE = -16, + VAR_UNKNOWN_COMMAND_CHAR = -14, + VAR_INPUT_ISNT_TEXT_NOR_VARIABLE = -13, + VAR_UNDEFINED_VARIABLE = -12, + VAR_INCOMPLETE_VARIABLE_SPEC = -11, + VAR_OUT_OF_MEMORY = -10, + VAR_INVALID_CONFIGURATION = -9, + VAR_INCORRECT_CLASS_SPEC = -8, + VAR_INCOMPLETE_GROUPED_HEX = -7, + VAR_INCOMPLETE_OCTAL = -6, + VAR_INVALID_OCTAL = -5, + VAR_OCTAL_TOO_LARGE = -4, + VAR_INVALID_HEX = -3, + VAR_INCOMPLETE_HEX = -2, + VAR_INCOMPLETE_NAMED_CHARACTER = -1, + VAR_INCOMPLETE_QUOTED_PAIR = -1, + VAR_OK = 0 + } +var_rc_t; + +/* + Expand the following named characters to their binary + representation: + + \t tab + \n newline + \r return + \033 octal char + \x1B hex char + \x{263a} wide hex char + + Any other character quoted by a backslash is copied verbatim. +*/ + +var_rc_t expand_named_characters(const char* src, size_t len, char* dst); + +/* + The callback will be called by variable_expand(), providing the + following parameterns: + + context - passed through from variable_expand()'s + parameters + varname - pointer to the name of the variable to + expand + name_len - length of the string starting at varname + data - location, where the callback should store + the pointer to the contents of the looked-up + variable + data_len - location, where the callback should store + the length of the data + malloced_buffer - location, where the callback should store + either TRUE or FALSE, telling the framework + whether the buffer must be free(3)ed. + + The return code is interpreted as follows: + >0 - OK + 0 - undefined variable + <0 - error +*/ + +typedef int (*var_cb_t)(void* context, + const char* varname, size_t name_len, + const char** data, size_t* data_len, size_t* buffer_size); + +/* + This structure configures the parser's specials. I think, the fields + are pretty self-explanatory. The only one worth mentioning is + force_expand, which is a boolean. If set to TRUE, variable_expand() + will fail with an error if the lookup callback returns "undefined + variable". If set to FALSE, variable_expand() will copy the + expression that failed verbatimly to the output so that another pass + may expand it. + + The comments after each field show the default configuration. +*/ + +typedef struct + { + char varinit; /* '$' */ + char startdelim; /* '{' */ + char enddelim; /* '}' */ + char escape; /* '\' */ + char* namechars; /* 'a-zA-Z0-9_' */ + } +var_config_t; +extern const var_config_t var_config_default; + +/* + variable_expand() will parse the contents of input for variable + expressions and expand them using the provided lookup callback. The + pointer to the resulting buffer is stored in result, its length in + result_len. The buffer is always terminated by a '\0' byte, which is + not included in the result_len count. The buffer must be free(3)ed + by the caller. +*/ + +var_rc_t var_expand(const char* input, size_t input_len, + char** result, size_t* result_len, + var_cb_t lookup, void* lookup_context, + const var_config_t* config, int force_expand); + +#endif /* !defined(LIB_VARIABLE_EXPAND_H) */ Index: ossp-pkg/var/var_test.c RCS File: /v/ossp/cvs/ossp-pkg/var/var_test.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/var_test.c,v' | diff -u /dev/null - -L'ossp-pkg/var/var_test.c' 2>/dev/null --- ossp-pkg/var/var_test.c +++ - 2024-05-02 01:54:42.631897887 +0200 @@ -0,0 +1,124 @@ +#include +#include +#include +#include "var.h" + +int env_lookup(void* context, + const char* varname, size_t name_len, + const char** data, size_t* data_len, size_t* buffer_size) + { + char tmp[256]; + + if (name_len > sizeof(tmp)-1) + { + printf("Callback can't expand variable names longer than %d characters.\n", sizeof(tmp-1)); + exit(1); + } + 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; + } + +struct test_case + { + const char* input; + const char* expected; + }; + +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" } + }; + /* + { "${HOME:s/g(res)s/x\\\\1x/g}","/homE/rEgrEssion-tEsts" } + { "${HOME:s/\\x65/\\x45/g}", "/home/regression-tests" } + */ + char* tmp; + size_t tmp_len; + var_rc_t rc; + size_t i; + + 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"); + + for (i = 0; i < sizeof(tests) / sizeof(struct test_case); ++i) + { + rc = var_expand(tests[i].input, strlen(tests[i].input), + &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; + } + 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; + } + printf("Test case #%02d: '%s' --> '%s'.\n", i, tests[i].input, tmp); + free(tmp); + } + + return 0; + } Index: ossp-pkg/var/varexp.h RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/varexp.h,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/Attic/varexp.h,v' | diff -u - /dev/null -L'ossp-pkg/var/varexp.h' 2>/dev/null --- ossp-pkg/var/varexp.h +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,127 +0,0 @@ -#ifndef LIB_VARIABLE_EXPAND_H -#define LIB_VARIABLE_EXPAND_H - -#include - -/* Error codes returned by the varexp library. */ - -typedef enum - { - VAR_EMPTY_PADDING_FILL_STRING = -32, - VAR_MISSING_PADDING_WIDTH = -31, - VAR_MALFORMATTED_PADDING = -30, - VAR_INCORRECT_TRANSPOSE_CLASS_SPEC = -29, - VAR_EMPTY_TRANSPOSE_CLASS = -28, - VAR_TRANSPOSE_CLASSES_MISMATCH = -27, - VAR_MALFORMATTED_TRANSPOSE = -26, - VAR_OFFSET_LOGIC_ERROR = -25, - VAR_OFFSET_OUT_OF_BOUNDS = -24, - VAR_RANGE_OUT_OF_BOUNDS = -23, - VAR_INVALID_OFFSET_DELIMITER = -22, - VAR_MISSING_START_OFFSET = -21, - VAR_EMPTY_SEARCH_STRING = -20, - VAR_MISSING_PARAMETER_IN_COMMAND = -19, - VAR_INVALID_REGEX_IN_REPLACE = -18, - VAR_UNKNOWN_REPLACE_FLAG = -17, - VAR_MALFORMATTED_REPLACE = -16, - VAR_UNKNOWN_COMMAND_CHAR = -14, - VAR_INPUT_ISNT_TEXT_NOR_VARIABLE = -13, - VAR_UNDEFINED_VARIABLE = -12, - VAR_INCOMPLETE_VARIABLE_SPEC = -11, - VAR_OUT_OF_MEMORY = -10, - VAR_INVALID_CONFIGURATION = -9, - VAR_INCORRECT_CLASS_SPEC = -8, - VAR_INCOMPLETE_GROUPED_HEX = -7, - VAR_INCOMPLETE_OCTAL = -6, - VAR_INVALID_OCTAL = -5, - VAR_OCTAL_TOO_LARGE = -4, - VAR_INVALID_HEX = -3, - VAR_INCOMPLETE_HEX = -2, - VAR_INCOMPLETE_NAMED_CHARACTER = -1, - VAR_INCOMPLETE_QUOTED_PAIR = -1, - VAR_OK = 0 - } -var_rc_t; - -/* - Expand the following named characters to their binary - representation: - - \t tab - \n newline - \r return - \033 octal char - \x1B hex char - \x{263a} wide hex char - - Any other character quoted by a backslash is copied verbatim. -*/ - -var_rc_t expand_named_characters(const char* src, size_t len, char* dst); - -/* - The callback will be called by variable_expand(), providing the - following parameterns: - - context - passed through from variable_expand()'s - parameters - varname - pointer to the name of the variable to - expand - name_len - length of the string starting at varname - data - location, where the callback should store - the pointer to the contents of the looked-up - variable - data_len - location, where the callback should store - the length of the data - malloced_buffer - location, where the callback should store - either TRUE or FALSE, telling the framework - whether the buffer must be free(3)ed. - - The return code is interpreted as follows: - >0 - OK - 0 - undefined variable - <0 - error -*/ - -typedef int (*var_cb_t)(void* context, - const char* varname, size_t name_len, - const char** data, size_t* data_len, size_t* buffer_size); - -/* - This structure configures the parser's specials. I think, the fields - are pretty self-explanatory. The only one worth mentioning is - force_expand, which is a boolean. If set to TRUE, variable_expand() - will fail with an error if the lookup callback returns "undefined - variable". If set to FALSE, variable_expand() will copy the - expression that failed verbatimly to the output so that another pass - may expand it. - - The comments after each field show the default configuration. -*/ - -typedef struct - { - char varinit; /* '$' */ - char startdelim; /* '{' */ - char enddelim; /* '}' */ - char escape; /* '\' */ - char* namechars; /* 'a-zA-Z0-9_' */ - } -var_config_t; -extern const var_config_t var_config_default; - -/* - variable_expand() will parse the contents of input for variable - expressions and expand them using the provided lookup callback. The - pointer to the resulting buffer is stored in result, its length in - result_len. The buffer is always terminated by a '\0' byte, which is - not included in the result_len count. The buffer must be free(3)ed - by the caller. -*/ - -var_rc_t var_expand(const char* input, size_t input_len, - char** result, size_t* result_len, - var_cb_t lookup, void* lookup_context, - const var_config_t* config, int force_expand); - -#endif /* !defined(LIB_VARIABLE_EXPAND_H) */ Index: ossp-pkg/var/variable.c RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/variable.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/Attic/variable.c,v' | diff -u - /dev/null -L'ossp-pkg/var/variable.c' 2>/dev/null --- ossp-pkg/var/variable.c +++ /dev/null 2024-05-02 01:52:11.000000000 +0200 @@ -1,63 +0,0 @@ -#include "internal.h" - -int variable(const char* begin, const char* end, const var_config_t* config, - const char nameclass[256], var_cb_t lookup, void* lookup_context, - int force_expand, tokenbuf* result) - { - const char* p = begin; - const char* data; - size_t len, buffer_size; - int rc, rc2; - - /* Clear the result tokenbuf to make sure we're in a defined - state. */ - - init_tokenbuf(result); - - /* Expect VARINIT. */ - - if (p == end || *p != config->varinit) - return 0; - - if (++p == end) - return VAR_INCOMPLETE_VARIABLE_SPEC; - - /* Try to read the variable name. If that fails, we're parsing a - complex expression. */ - - rc = varname(p, end, nameclass); - if (rc < 0) - return rc; - else if (rc > 0) - { - rc2 = (*lookup)(lookup_context, p, rc, &data, &len, &buffer_size); - if (rc2 < 0) - return rc2; - else if (rc2 == 0) - { - if (force_expand) - return VAR_UNDEFINED_VARIABLE; - else - { - result->begin = begin; - result->end = begin + 1 + rc; - result->buffer_size = 0; - return 1 + rc; - } - } - else - { - result->begin = data; - result->end = data + len; - result->buffer_size = buffer_size; - return 1 + rc; - } - } - - /* OK, we're dealing with a complex expression here. */ - - rc = expression(p, end, config, nameclass, lookup, lookup_context, force_expand, result); - if (rc > 0) - ++rc; - return rc; - }