Index: ossp-pkg/var/var.c RCS File: /v/ossp/cvs/ossp-pkg/var/var.c,v rcsdiff -q -kk '-r1.70' '-r1.71' -u '/v/ossp/cvs/ossp-pkg/var/var.c,v' 2>/dev/null --- var.c 2002/02/28 20:28:14 1.70 +++ var.c 2002/03/01 20:28:33 1.71 @@ -79,9 +79,14 @@ }; /* the internal expansion context structure */ -typedef struct { - int force_expand; -} var_parse_t; +struct var_parse_st { + struct var_parse_st *lower; + int force_expand; + int rel_lookup_flag; + int rel_lookup_cnt; + int index_this; +}; +typedef struct var_parse_st var_parse_t; /* the default syntax configuration */ static const var_syntax_t var_syntax_default = { @@ -97,6 +102,32 @@ /* ** +** ==== PARSE CONTEXT FUNCTIONS ==== +** +*/ + +static var_parse_t * +var_parse_push( + var_parse_t *lower, var_parse_t *upper) +{ + if (upper == NULL) + return NULL; + memcpy(upper, lower, sizeof(var_parse_t)); + upper->lower = lower; + return upper; +} + +static var_parse_t * +var_parse_pop( + var_parse_t *upper) +{ + if (upper == NULL) + return NULL; + return upper->lower; +} + +/* +** ** ==== TOKEN BUFFER FUNCTIONS ==== ** */ @@ -228,6 +259,7 @@ class[(int)a] = 1; } while (++a <= b); + return; } static var_rc_t expand_character_class(const char *desc, char_class_t class) @@ -366,9 +398,9 @@ */ /* forward declarations */ -static int parse_variable(var_t *var, var_parse_t *ctx, const char *begin, const char *end, int force_expand, tokenbuf_t *result, int index_this, int* rel_lookup_flag); -static int parse_command (var_t *var, var_parse_t *ctx, const char *begin, const char *end, int force_expand, tokenbuf_t *data, int index_this, int* rel_lookup_flag); -static int parse_num_exp (var_t *var, var_parse_t *ctx, const char *begin, const char *end, int index_this, int* result, int* failed, int* rel_lookup_flag); +static int parse_variable(var_t *var, var_parse_t *ctx, const char *begin, const char *end, tokenbuf_t *result); +static int parse_command (var_t *var, var_parse_t *ctx, const char *begin, const char *end, tokenbuf_t *data); +static int parse_num_exp (var_t *var, var_parse_t *ctx, const char *begin, const char *end, int *result, int *failed); /* parse plain text */ static int @@ -484,11 +516,13 @@ parse_num_exp_operand( var_t *var, var_parse_t *ctx, const char *begin, const char *end, - int index_this, int *result, int *failed, int *rel_lookup_flag) + int *result, + int *failed) { const char *p; tokenbuf_t tmp; int rc; + var_parse_t myctx; p = begin; tokenbuf_init(&tmp); @@ -497,8 +531,7 @@ return VAR_ERR_INCOMPLETE_INDEX_SPEC; if (*p == '(') { - rc = parse_num_exp(var, ctx, ++p, end, index_this, result, failed, - rel_lookup_flag); + rc = parse_num_exp(var, ctx, ++p, end, result, failed); if (rc < 0) return rc; p += rc; @@ -509,12 +542,16 @@ ++p; } else if (*p == var->syntax.delim_init) { - rc = parse_variable(var, ctx, p, end, - 1, &tmp, index_this, rel_lookup_flag); + ctx = var_parse_push(ctx, &myctx); + ctx->force_expand = 1; + rc = parse_variable(var, ctx, p, end, &tmp); + ctx = var_parse_pop(ctx); if (rc == VAR_ERR_UNDEFINED_VARIABLE) { *failed = 1; - rc = parse_variable(var, ctx, p, end, - 0, &tmp, index_this, rel_lookup_flag); + ctx = var_parse_push(ctx, &myctx); + ctx->force_expand = 0; + rc = parse_variable(var, ctx, p, end, &tmp); + ctx = var_parse_pop(ctx); if (rc < 0) return rc; p += rc; @@ -524,8 +561,7 @@ if (rc < 0) return rc; p += rc; - rc = parse_num_exp(var, ctx, tmp.begin, tmp.end, index_this, result, - failed, rel_lookup_flag ); + rc = parse_num_exp(var, ctx, tmp.begin, tmp.end, result, failed); tokenbuf_free(&tmp); if (rc < 0) return rc; @@ -533,8 +569,9 @@ } else if (var->syntax.index_mark && *p == var->syntax.index_mark) { p++; - *result = index_this; - (*rel_lookup_flag)++; + *result = ctx->index_this; + if (ctx->rel_lookup_flag) + ctx->rel_lookup_cnt++; } else if (isdigit(*p)) { *result = convert_num_exp_read_int(&p, end); @@ -566,8 +603,7 @@ parse_num_exp( var_t *var, var_parse_t *ctx, const char *begin, const char *end, - int index_this, - int *result, int *failed, int *rel_lookup_flag) + int *result, int *failed) { const char *p = begin; char operator; @@ -577,8 +613,7 @@ if (begin == end) return VAR_ERR_INCOMPLETE_INDEX_SPEC; - rc = parse_num_exp_operand(var, ctx, p, end, index_this, result, - failed, rel_lookup_flag); + rc = parse_num_exp_operand(var, ctx, p, end, result, failed); if (rc < 0) return rc; p += rc; @@ -586,8 +621,7 @@ while (p != end) { if (*p == '+' || *p == '-') { operator = *p++; - rc = parse_num_exp(var, ctx, p, end, index_this, &right, failed, - rel_lookup_flag); + rc = parse_num_exp(var, ctx, p, end, &right, failed); if (rc < 0) return rc; p += rc; @@ -598,8 +632,7 @@ } else if (*p == '*' || *p == '/' || *p == '%') { operator = *p++; - rc = parse_num_exp_operand(var, ctx, p, end, index_this, &right, failed, - rel_lookup_flag); + rc = parse_num_exp_operand(var, ctx, p, end, &right, failed); if (rc < 0) return rc; p += rc; @@ -633,12 +666,39 @@ return p - begin; } +/* callback wrapper function */ +static int +lookup_value( + var_t *var, var_parse_t *ctx, + const char *var_ptr, size_t var_len, int var_idx, + const char **val_ptr, size_t *val_len, size_t *val_size) +{ + char buf[1]; + int rc; + + /* pass through to original callback */ + rc = (*var->cb_value_fct)(var, var->cb_value_ctx, + var_ptr, var_len, var_idx, + val_ptr, val_len, val_size); + + /* convert undefined variable into empty variable */ + if (ctx->rel_lookup_flag && rc == VAR_ERR_UNDEFINED_VARIABLE) { + ctx->rel_lookup_cnt--; + buf[0] = NUL; + *val_ptr = buf; + *val_len = 0; + *val_size = 0; + return VAR_OK; + } + + return rc; +} + static int parse_expression( var_t *var, var_parse_t *ctx, const char *begin, const char *end, - int force_expand, - tokenbuf_t *result, int index_this, int *rel_lookup_flag) + tokenbuf_t *result) { const char *p = begin; const char *data; @@ -678,8 +738,7 @@ p += rc; } - rc = parse_variable(var, ctx, p, end, - force_expand, &tmp, index_this, rel_lookup_flag); + rc = parse_variable(var, ctx, p, end, &tmp); if (rc < 0) goto error_return; if (rc > 0) { @@ -695,7 +754,7 @@ do. */ if (name.begin == name.end) { - if (force_expand) { + if (ctx->force_expand) { rc = VAR_ERR_INCOMPLETE_VARIABLE_SPEC; goto error_return; } @@ -715,8 +774,7 @@ /* If the next token is START-INDEX, read the index specification. */ if (var->syntax.index_open && *p == var->syntax.index_open) { - rc = parse_num_exp(var, ctx, ++p, end, index_this, &idx, &failed, - rel_lookup_flag); + rc = parse_num_exp(var, ctx, ++p, end, &idx, &failed); if (rc < 0) goto error_return; if (rc == 0) { @@ -753,12 +811,12 @@ result->buffer_size = 0; } else { - rc = (*var->cb_value_fct) (var, var->cb_value_ctx, name.begin, name.end - name.begin, idx, - &data, &len, &buffer_size); + rc = lookup_value(var, ctx, name.begin, name.end - name.begin, idx, + &data, &len, &buffer_size); if (rc == VAR_ERR_UNDEFINED_VARIABLE) { /* The variable is undefined. What we'll do now depends on the force_expand flag. */ - if (force_expand) + if (ctx->force_expand) goto error_return; /* Initialize result to point back to the original text in @@ -789,13 +847,9 @@ while (p != end && *p == ':') { p++; if (!failed) - rc = parse_command(var, ctx, p, end, - force_expand, result, - index_this, rel_lookup_flag); + rc = parse_command(var, ctx, p, end, result); else - rc = parse_command(var, ctx, p, end, - force_expand, &tmp, - index_this, rel_lookup_flag); + rc = parse_command(var, ctx, p, end, &tmp); if (rc < 0) goto error_return; p += rc; @@ -832,8 +886,7 @@ var_t *var, var_parse_t *ctx, const char *begin, const char *end, - int force_expand, tokenbuf_t *result, int index_this, - int *rel_lookup_flag) + tokenbuf_t *result) { const char *p = begin; const char *data; @@ -860,8 +913,8 @@ if (rc < 0) return rc; if (rc > 0) { - rc2 = (*var->cb_value_fct)(var, var->cb_value_ctx, p, rc, 0, &data, &len, &buffer_size); - if (rc2 == VAR_ERR_UNDEFINED_VARIABLE && !force_expand) { + rc2 = lookup_value(var, ctx, p, rc, 0, &data, &len, &buffer_size); + if (rc2 == VAR_ERR_UNDEFINED_VARIABLE && !ctx->force_expand) { result->begin = begin; result->end = begin + 1 + rc; result->buffer_size = 0; @@ -877,8 +930,7 @@ /* OK, we're dealing with a complex expression here. */ - rc = parse_expression(var, ctx, p, end, - force_expand, result, index_this, rel_lookup_flag); + rc = parse_expression(var, ctx, p, end, result); if (rc > 0) rc++; return rc; @@ -888,9 +940,7 @@ parse_exptext_or_variable( var_t *var, var_parse_t *ctx, const char *begin, const char *end, - int force_expand, - tokenbuf_t *result, int index_this, - int *rel_lookup_flag) + tokenbuf_t *result) { const char *p = begin; tokenbuf_t tmp; @@ -914,8 +964,7 @@ p += rc; } - rc = parse_variable(var, ctx, p, end, - force_expand, &tmp, index_this, rel_lookup_flag); + rc = parse_variable(var, ctx, p, end, &tmp); if (rc < 0) goto error_return; if (rc > 0) { @@ -941,9 +990,7 @@ parse_substext_or_variable( var_t *var, var_parse_t *ctx, const char *begin, const char *end, - int force_expand, - tokenbuf_t *result, int index_this, - int *rel_lookup_flag) + tokenbuf_t *result) { const char *p = begin; tokenbuf_t tmp; @@ -967,8 +1014,7 @@ p += rc; } - rc = parse_variable(var, ctx, p, end, - force_expand, &tmp, index_this, rel_lookup_flag); + rc = parse_variable(var, ctx, p, end, &tmp); if (rc < 0) goto error_return; if (rc > 0) { @@ -990,7 +1036,8 @@ return rc; } -static int parse_class_description(tokenbuf_t *src, tokenbuf_t *dst) +static int +parse_class_description(tokenbuf_t *src, tokenbuf_t *dst) { unsigned char c, d; const char *p = src->begin; @@ -1013,8 +1060,11 @@ return VAR_OK; } -static int transpose(tokenbuf_t *data, tokenbuf_t *search, - tokenbuf_t *replace) +static int +op_transpose( + tokenbuf_t *data, + tokenbuf_t *search, + tokenbuf_t *replace) { tokenbuf_t srcclass, dstclass; const char *p; @@ -1050,7 +1100,7 @@ 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]; + *((char *)p) = dstclass.begin[i]; break; } } @@ -1068,8 +1118,12 @@ return rc; } -static int cut_out_offset(tokenbuf_t *data, tokenbuf_t *number1, - tokenbuf_t *number2, int isrange) +static int +op_cut_out_offset( + tokenbuf_t *data, + tokenbuf_t *number1, + tokenbuf_t *number2, + int isrange) { tokenbuf_t res; const char *p; @@ -1112,8 +1166,12 @@ return VAR_OK; } -static int parse_regex_replace(const char *data, tokenbuf_t *orig, - regmatch_t *pmatch, tokenbuf_t *expanded) +static int +parse_regex_replace( + const char *data, + tokenbuf_t *orig, + regmatch_t *pmatch, + tokenbuf_t *expanded) { const char *p = orig->begin; size_t i; @@ -1162,8 +1220,12 @@ return VAR_OK; } -static int search_and_replace(tokenbuf_t *data, tokenbuf_t *search, - tokenbuf_t *replace, tokenbuf_t *flags) +static int +op_search_and_replace( + tokenbuf_t *data, + tokenbuf_t *search, + tokenbuf_t *replace, + tokenbuf_t *flags) { const char *p; int case_insensitive = 0; @@ -1316,8 +1378,12 @@ return VAR_OK; } -static int padding(tokenbuf_t *data, tokenbuf_t *widthstr, tokenbuf_t *fill, - char position) +static int +op_padding( + tokenbuf_t *data, + tokenbuf_t *widthstr, + tokenbuf_t *fill, + char position) { tokenbuf_t result; size_t width = tokenbuf_toint(widthstr); @@ -1428,8 +1494,7 @@ parse_command( var_t *var, var_parse_t *ctx, const char *begin, const char *end, - int force_expand, - tokenbuf_t *data, int index_this, int *rel_lookup_flag) + tokenbuf_t *data) { const char *p = begin; tokenbuf_t tmptokbuf; @@ -1449,281 +1514,272 @@ return 0; switch (tolower(*p)) { - case 'l': /* Turn data to lowercase. */ - if (data->begin) { - char *ptr; - /* If the buffer does not live in an allocated buffer, - we have to copy it before modifying the contents. */ + case 'l': /* Turn data to lowercase. */ + if (data->begin) { + char *ptr; + /* If the buffer does not live in an allocated buffer, + we have to copy it before modifying the contents. */ + + if (data->buffer_size == 0) { + if (!tokenbuf_assign(data, data->begin, data->end - data->begin)) { + rc = VAR_ERR_OUT_OF_MEMORY; + goto error_return; + } + } + for (ptr = (char *)data->begin; ptr != data->end; ++ptr) + *ptr = tolower(*ptr); + } + p++; + break; - if (data->buffer_size == 0) { - if (!tokenbuf_assign(data, data->begin, data->end - data->begin)) { - rc = VAR_ERR_OUT_OF_MEMORY; - goto error_return; + case 'u': /* Turn data to uppercase. */ + if (data->begin) { + char *ptr; + if (data->buffer_size == 0) { + if (!tokenbuf_assign + (data, data->begin, data->end - data->begin)) { + rc = VAR_ERR_OUT_OF_MEMORY; + goto error_return; + } } + for (ptr = (char *) data->begin; ptr != data->end; ++ptr) + *ptr = toupper(*ptr); } - for (ptr = (char *)data->begin; ptr != data->end; ++ptr) - *ptr = tolower(*ptr); - } - p++; - break; + ++p; + break; - case 'u': /* Turn data to uppercase. */ - if (data->begin) { - char *ptr; - if (data->buffer_size == 0) { - if (!tokenbuf_assign - (data, data->begin, data->end - data->begin)) { + case 'o': /* Cut out substrings. */ + ++p; + rc = parse_number(var, ctx, p, end); + if (rc == 0) { + rc = VAR_ERR_MISSING_START_OFFSET; + goto error_return; + } + 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_ERR_INVALID_OFFSET_DELIMITER; + goto error_return; + } + + rc = parse_number(var, ctx, p, end); + number2.begin = p; + number2.end = p + rc; + number2.buffer_size = 0; + p += rc; + if (data->begin) { + rc = op_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[((sizeof(int)*8)/3)+10]; /* sufficient size: <#bits> x log_10(2) + safety */ + sprintf(buf, "%d", (int)(data->end - data->begin)); + tokenbuf_free(data); + if (!tokenbuf_assign(data, buf, strlen(buf))) { rc = VAR_ERR_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 = parse_number(var, ctx, p, end); - if (rc == 0) { - rc = VAR_ERR_MISSING_START_OFFSET; - goto error_return; - } - 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_ERR_INVALID_OFFSET_DELIMITER; - goto error_return; - } + break; - rc = parse_number(var, ctx, 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); + case '-': /* Substitute parameter if data is empty. */ + p++; + rc = parse_exptext_or_variable(var, ctx, p, end, &tmptokbuf); if (rc < 0) goto error_return; - } - break; - - case '#': /* Substitute length of the string. */ - if (data->begin) { - char buf[((sizeof(int)*8)/3)+10]; /* sufficient size: <#bits> x log_10(2) + safety */ - sprintf(buf, "%d", (int)(data->end - data->begin)); - tokenbuf_free(data); - if (!tokenbuf_assign(data, buf, strlen(buf))) { - rc = VAR_ERR_OUT_OF_MEMORY; + if (rc == 0) { + rc = VAR_ERR_MISSING_PARAMETER_IN_COMMAND; goto error_return; } - } - ++p; - break; - - case '-': /* Substitute parameter if data is empty. */ - p++; - rc = parse_exptext_or_variable(var, ctx, p, end, - force_expand, &tmptokbuf, - index_this, rel_lookup_flag); - if (rc < 0) - goto error_return; - if (rc == 0) { - rc = VAR_ERR_MISSING_PARAMETER_IN_COMMAND; - goto error_return; - } - p += rc; - if (data->begin != NULL && data->begin == data->end) { - tokenbuf_free(data); - tokenbuf_move(&tmptokbuf, data); - } - break; - - case '*': /* Return "" if data is not empty, parameter otherwise. */ - p++; - rc = parse_exptext_or_variable(var, ctx, p, end, - force_expand, &tmptokbuf, index_this, rel_lookup_flag); - if (rc < 0) - goto error_return; - if (rc == 0) { - rc = VAR_ERR_MISSING_PARAMETER_IN_COMMAND; - goto error_return; - } - p += rc; - if (data->begin != NULL) { - if (data->begin == data->end) { + p += rc; + if (data->begin != NULL && data->begin == data->end) { tokenbuf_free(data); tokenbuf_move(&tmptokbuf, data); - } else { - tokenbuf_free(data); - data->begin = data->end = ""; - data->buffer_size = 0; } - } - break; + break; - case '+': /* Substitute parameter if data is not empty. */ - p++; - rc = parse_exptext_or_variable(var, ctx, p, end, - force_expand, &tmptokbuf, index_this, rel_lookup_flag); - if (rc < 0) - goto error_return; - if (rc == 0) { - rc = VAR_ERR_MISSING_PARAMETER_IN_COMMAND; - goto error_return; - } - p += rc; - if (data->begin != NULL && data->begin != data->end) { - tokenbuf_free(data); - tokenbuf_move(&tmptokbuf, data); - } - break; + case '*': /* Return "" if data is not empty, parameter otherwise. */ + p++; + rc = parse_exptext_or_variable(var, ctx, p, end, &tmptokbuf); + if (rc < 0) + goto error_return; + if (rc == 0) { + rc = VAR_ERR_MISSING_PARAMETER_IN_COMMAND; + goto error_return; + } + p += rc; + if (data->begin != NULL) { + if (data->begin == data->end) { + tokenbuf_free(data); + tokenbuf_move(&tmptokbuf, data); + } else { + tokenbuf_free(data); + data->begin = data->end = ""; + data->buffer_size = 0; + } + } + break; - case 's': /* Search and replace. */ - p++; + case '+': /* Substitute parameter if data is not empty. */ + p++; + rc = parse_exptext_or_variable(var, ctx, p, end, &tmptokbuf); + if (rc < 0) + goto error_return; + if (rc == 0) { + rc = VAR_ERR_MISSING_PARAMETER_IN_COMMAND; + goto error_return; + } + p += rc; + if (data->begin != NULL && data->begin != data->end) { + tokenbuf_free(data); + tokenbuf_move(&tmptokbuf, data); + } + break; - if (*p != '/') - return VAR_ERR_MALFORMATTED_REPLACE; - p++; + case 's': /* Search and replace. */ + p++; - rc = parse_substext_or_variable(var, ctx, p, end, - force_expand, &search, index_this, rel_lookup_flag); - if (rc < 0) - goto error_return; - p += rc; + if (*p != '/') + return VAR_ERR_MALFORMATTED_REPLACE; + p++; - if (*p != '/') { - rc = VAR_ERR_MALFORMATTED_REPLACE; - goto error_return; - } - p++; + rc = parse_substext_or_variable(var, ctx, p, end, &search); + if (rc < 0) + goto error_return; + p += rc; - rc = parse_substext_or_variable(var, ctx, p, end, - force_expand, &replace, index_this, rel_lookup_flag); - if (rc < 0) - goto error_return; - p += rc; + if (*p != '/') { + rc = VAR_ERR_MALFORMATTED_REPLACE; + goto error_return; + } + p++; - if (*p != '/') { - rc = VAR_ERR_MALFORMATTED_REPLACE; - goto error_return; - } - p++; + rc = parse_substext_or_variable(var, ctx, p, end, &replace); + if (rc < 0) + goto error_return; + p += rc; - rc = parse_exptext(var, ctx, p, end); - if (rc < 0) - goto error_return; - flags.begin = p; - flags.end = p + rc; - flags.buffer_size = 0; - p += rc; + if (*p != '/') { + rc = VAR_ERR_MALFORMATTED_REPLACE; + goto error_return; + } + p++; - if (data->begin) { - rc = search_and_replace(data, &search, &replace, &flags); + rc = parse_exptext(var, ctx, p, end); if (rc < 0) goto error_return; - } - break; - - case 'y': /* Transpose characters from class A to class B. */ - p++; + flags.begin = p; + flags.end = p + rc; + flags.buffer_size = 0; + p += rc; - if (*p != '/') - return VAR_ERR_MALFORMATTED_TRANSPOSE; - p++; + if (data->begin) { + rc = op_search_and_replace(data, &search, &replace, &flags); + if (rc < 0) + goto error_return; + } + break; - rc = parse_substext_or_variable(var, ctx, p, end, - force_expand, &search, index_this, rel_lookup_flag); - if (rc < 0) - goto error_return; - p += rc; + case 'y': /* Transpose characters from class A to class B. */ + p++; - if (*p != '/') { - rc = VAR_ERR_MALFORMATTED_TRANSPOSE; - goto error_return; - } - p++; + if (*p != '/') + return VAR_ERR_MALFORMATTED_TRANSPOSE; + p++; - rc = parse_substext_or_variable(var, ctx, p, end, - force_expand, &replace, index_this, rel_lookup_flag); - if (rc < 0) - goto error_return; - p += rc; + rc = parse_substext_or_variable(var, ctx, p, end, &search); + if (rc < 0) + goto error_return; + p += rc; - if (*p != '/') { - rc = VAR_ERR_MALFORMATTED_TRANSPOSE; - goto error_return; - } else - ++p; + if (*p != '/') { + rc = VAR_ERR_MALFORMATTED_TRANSPOSE; + goto error_return; + } + p++; - if (data->begin) { - rc = transpose(data, &search, &replace); + rc = parse_substext_or_variable(var, ctx, p, end, &replace); if (rc < 0) goto error_return; - } - break; - + p += rc; - case 'p': /* Padding. */ - p++; + if (*p != '/') { + rc = VAR_ERR_MALFORMATTED_TRANSPOSE; + goto error_return; + } else + ++p; - if (*p != '/') - return VAR_ERR_MALFORMATTED_PADDING; - p++; + if (data->begin) { + rc = op_transpose(data, &search, &replace); + if (rc < 0) + goto error_return; + } + break; - rc = parse_number(var, ctx, p, end); - if (rc == 0) { - rc = VAR_ERR_MISSING_PADDING_WIDTH; - goto error_return; - } - number1.begin = p; - number1.end = p + rc; - number1.buffer_size = 0; - p += rc; - if (*p != '/') { - rc = VAR_ERR_MALFORMATTED_PADDING; - goto error_return; - } - p++; + case 'p': /* Padding. */ + p++; - rc = parse_substext_or_variable(var, ctx, p, end, - force_expand, &replace, index_this, rel_lookup_flag); - if (rc < 0) - goto error_return; - p += rc; + if (*p != '/') + return VAR_ERR_MALFORMATTED_PADDING; + p++; - if (*p != '/') { - rc = VAR_ERR_MALFORMATTED_PADDING; - goto error_return; - } - p++; + rc = parse_number(var, ctx, p, end); + if (rc == 0) { + rc = VAR_ERR_MISSING_PADDING_WIDTH; + goto error_return; + } + number1.begin = p; + number1.end = p + rc; + number1.buffer_size = 0; + p += rc; - if (*p != 'l' && *p != 'c' && *p != 'r') { - rc = VAR_ERR_MALFORMATTED_PADDING; - goto error_return; - } - p++; + if (*p != '/') { + rc = VAR_ERR_MALFORMATTED_PADDING; + goto error_return; + } + p++; - if (data->begin) { - rc = padding(data, &number1, &replace, p[-1]); + rc = parse_substext_or_variable(var, ctx, p, end, &replace); if (rc < 0) goto error_return; - } - break; + p += rc; - default: - return VAR_ERR_UNKNOWN_COMMAND_CHAR; + if (*p != '/') { + rc = VAR_ERR_MALFORMATTED_PADDING; + goto error_return; + } + p++; + + if (*p != 'l' && *p != 'c' && *p != 'r') { + rc = VAR_ERR_MALFORMATTED_PADDING; + goto error_return; + } + p++; + + if (data->begin) { + rc = op_padding(data, &number1, &replace, p[-1]); + if (rc < 0) + goto error_return; + } + break; + + default: + return VAR_ERR_UNKNOWN_COMMAND_CHAR; } /* Exit gracefully. */ @@ -1753,12 +1809,12 @@ var_t *var, var_parse_t *ctx, const char *begin, const char *end, - int* start, int* step, int* stop, int* open_end) + int *start, int *step, int *stop, + int *open_end) { const char *p; int rc; int failed; - int dummy; p = begin; if (begin == end) @@ -1770,7 +1826,7 @@ /* Read start value for the loop. */ failed = 0; - rc = parse_num_exp(var, ctx, p, end, 0, start, &failed, &dummy); + rc = parse_num_exp(var, ctx, p, end, start, &failed); if (rc == VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC) *start = 0; /* use default */ else if (rc < 0) @@ -1787,7 +1843,7 @@ /* Read step value for the loop. */ failed = 0; - rc = parse_num_exp(var, ctx, p, end, 0, step, &failed, &dummy); + rc = parse_num_exp(var, ctx, p, end, step, &failed); if (rc == VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC) *step = 1; /* use default */ else if (rc < 0) @@ -1815,7 +1871,7 @@ /* Read stop value for the loop. */ failed = 0; - rc = parse_num_exp(var, ctx, p, end, 0, stop, &failed, &dummy); + rc = parse_num_exp(var, ctx, p, end, stop, &failed); if (rc == VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC) { *stop = 0; /* use default */ *open_end = 1; @@ -1834,51 +1890,14 @@ return ++p - begin; } -/* callback wrapper context */ -typedef struct { - var_cb_value_t cb_value_fct; - void *cb_value_ctx; - int *rel_lookup_flag; -} var_wrapper_t; - -/* callback wrapper function */ -static int -lookup_wrapper( - var_t *var, void *ctx, - const char *var_ptr, size_t var_len, int var_idx, - const char **val_ptr, size_t *val_len, size_t *val_size) -{ - char buf[1]; - var_wrapper_t *wcon = (var_wrapper_t *)ctx; - int rc; - - /* pass through to original callback */ - rc = (*wcon->cb_value_fct)(var, wcon->cb_value_ctx, - var_ptr, var_len, var_idx, - val_ptr, val_len, val_size); - - /* convert undefined variable into empty variable */ - if (rc == VAR_ERR_UNDEFINED_VARIABLE) { - (*wcon->rel_lookup_flag)--; - buf[0] = NUL; - *val_ptr = buf; - *val_len = 0; - *val_size = 0; - return VAR_OK; - } - - return rc; -} - /* expand input in general */ static var_rc_t parse_input( var_t *var, var_parse_t *ctx, const char *begin, const char *end, - int force_expand, - tokenbuf_t *output, int index_this, - size_t recursion_level, int *rel_lookup_flag) + tokenbuf_t *output, + int recursion_level) { const char *p = begin; int rc, rc2; @@ -1886,21 +1905,18 @@ int start, step, stop, open_end; int i; int output_backup; - var_wrapper_t wcon; - int my_rel_lookup_flag; - int original_rel_lookup_state; + int rel_lookup_cnt; int loop_limit_length; + var_parse_t myctx; tokenbuf_init(&result); - if (rel_lookup_flag == NULL) { - rel_lookup_flag = &my_rel_lookup_flag; - *rel_lookup_flag = 0; - } - do { - if (begin != end && var->syntax.index_open && *begin == var->syntax.index_open) { - original_rel_lookup_state = *rel_lookup_flag; + /* try to parse a loop construct */ + if ( begin != end + && var->syntax.index_open != NUL + && *begin == var->syntax.index_open) { + loop_limit_length = -1; begin++; start = 0; @@ -1909,27 +1925,31 @@ open_end = 1; rc = 0; output_backup = 0; - re_loop: + rel_lookup_cnt = ctx->rel_lookup_cnt; + + re_loop: for (i = start; - (open_end && (loop_limit_length < 0 || *rel_lookup_flag > original_rel_lookup_state)) || - (!open_end && i <= stop); + ( ( open_end + && ( loop_limit_length < 0 + || rel_lookup_cnt > ctx->rel_lookup_cnt)) + || ( !open_end + && i <= stop) ); i += step) { - *rel_lookup_flag = original_rel_lookup_state; + /* remember current state for backing off */ output_backup = output->end - output->begin; - /* activate callback wrapper */ - wcon.cb_value_fct = var->cb_value_fct; - wcon.cb_value_ctx = var->cb_value_ctx; - wcon.rel_lookup_flag = rel_lookup_flag; - var->cb_value_fct = lookup_wrapper; - var->cb_value_ctx = &wcon; + /* open temporary context for recursion */ + ctx = var_parse_push(ctx, &myctx); + ctx->force_expand = 1; + ctx->rel_lookup_flag = 1; + ctx->index_this = i; rc = parse_input(var, ctx, begin, end, - 1, output, i, recursion_level+1, rel_lookup_flag); + output, recursion_level+1); - /* deactivate callback wrapper */ - var->cb_value_fct = wcon.cb_value_fct; - var->cb_value_ctx = wcon.cb_value_ctx; + /* retrieve info and close temporary context */ + rel_lookup_cnt = ctx->rel_lookup_cnt; + ctx = var_parse_pop(ctx); if (rc < 0) goto error_return; @@ -1955,13 +1975,14 @@ if (open_end) output->end = output->begin + output_backup; else - *rel_lookup_flag = original_rel_lookup_state; + rel_lookup_cnt = ctx->rel_lookup_cnt; begin += rc; begin++; begin += loop_limit_length; continue; } + /* try to parse plain text */ rc = parse_text(var, ctx, begin, end); if (rc > 0) { if (!tokenbuf_append(output, begin, rc)) { @@ -1973,9 +1994,8 @@ } else if (rc < 0) goto error_return; - rc = parse_variable(var, ctx, begin, end, - force_expand, &result, - index_this, rel_lookup_flag); + /* try to parse a variable construct */ + rc = parse_variable(var, ctx, begin, end, &result); if (rc > 0) { if (!tokenbuf_append(output, result.begin, result.end - result.begin)) { rc = VAR_ERR_OUT_OF_MEMORY; @@ -1986,6 +2006,7 @@ } if (rc < 0) goto error_return; + } while (begin != end && rc > 0); if (recursion_level == 0 && begin != end) { @@ -2164,7 +2185,11 @@ return VAR_RC(VAR_ERR_INVALID_ARGUMENT); /* prepare internal expansion context */ + ctx.lower = NULL; ctx.force_expand = force_expand; + ctx.rel_lookup_flag = 0; + ctx.rel_lookup_cnt = 0; + ctx.index_this = 0; /* set the dst_ptr pointer to the src_ptr so that it is correctly initialized in case we fail with an error later. */ @@ -2172,9 +2197,7 @@ /* call the parsing */ tokenbuf_init(&output); - rc = parse_input(var, &ctx, - src_ptr, src_ptr + src_len, - ctx.force_expand, &output, 0, 0, NULL); + rc = parse_input(var, &ctx, src_ptr, src_ptr + src_len, &output, 0); /* post-process output */ if (rc >= 0) {