diff options
author | Nalin Dahyabhai <nalin.dahyabhai@pobox.com> | 2008-06-26 17:19:26 -0400 |
---|---|---|
committer | Nalin Dahyabhai <nalin.dahyabhai@pobox.com> | 2008-06-26 17:19:26 -0400 |
commit | cb5d7d97e85557873445d605681f94b1c01858ba (patch) | |
tree | acd11d091baecaec46edb3ad9766b6d8ce2afef6 /src/format.c | |
parent | 8bdafe29900349b315bf37da112e1a3f6f680d34 (diff) | |
download | slapi-nis-cb5d7d97e85557873445d605681f94b1c01858ba.tar.gz slapi-nis-cb5d7d97e85557873445d605681f94b1c01858ba.tar.xz slapi-nis-cb5d7d97e85557873445d605681f94b1c01858ba.zip |
- dup_strlist: calculate string list sizes correctly when duplicating them
- expand: we don't need to support simple expressions directly any more
- expand: stop using a scratch buffer for expansion
- format: reset choice offset pointers when returning them
- match_generic: clean up to free the valueset in one place rather than possibly
four different places
- match_generic: free the whole list of matches if we don't end up using it
- single: return values correctly
- xstrndup: terminate at the first nul
- trim_value: drop support for '!' modifier
- get_data_set: return the data we compute
Diffstat (limited to 'src/format.c')
-rw-r--r-- | src/format.c | 421 |
1 files changed, 223 insertions, 198 deletions
diff --git a/src/format.c b/src/format.c index 7e980fc..d7e570c 100644 --- a/src/format.c +++ b/src/format.c @@ -50,9 +50,11 @@ #define MAX_BUFFER_SIZE 0x100000 struct format_choice { char *offset; + int n_values; char **values; struct format_choice *next; }; + static int format_expand(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, const char *domain, const char *map, @@ -60,8 +62,7 @@ static int format_expand(struct plugin_state *state, char *outbuf, int outbuf_len, struct format_choice **outbuf_choices, char ***ref_attrs, - struct format_inref_attr ***inref_attrs, - bool_t is_simple_expression); + struct format_inref_attr ***inref_attrs); char ** format_dup_attr_list(char **attr_list) @@ -72,7 +73,7 @@ format_dup_attr_list(char **attr_list) elements = 0; if (*attr_list != NULL) { for (i = 0; attr_list[i] != NULL; i++) { - length += (strlen(attr_list[i] + 1)); + length += (strlen(attr_list[i]) + 1); } elements = i; } @@ -108,7 +109,7 @@ format_add_attr_list(char ***attr_list, const char *value) if (strcmp(value, (*attr_list)[i]) == 0) { return; } - length += (strlen((*attr_list)[i] + 1)); + length += (strlen((*attr_list)[i]) + 1); elements++; } } @@ -167,7 +168,8 @@ format_dup_inref_attrs(struct format_inref_attr **attrs) ret[j]->map = strdup(attrs[i]->map); ret[j]->attribute = strdup(attrs[i]->attribute); - if ((ret[j]->map != NULL) && + if ((ret[j]->domain != NULL) && + (ret[j]->map != NULL) && (ret[j]->attribute != NULL)) { j++; } @@ -227,7 +229,21 @@ format_free_inref_attrs(struct format_inref_attr **attrs) } } -/* Add a new entry to the "choice" list. */ +/* Maintain "choices" lists. */ +static void +format_retarget_choicesp(struct format_choice **choices, char *oldt, char *newt) +{ + struct format_choice *this_choice; + int offset; + if (choices != NULL) { + for (this_choice = *choices; + this_choice != NULL; + this_choice = this_choice->next) { + offset = this_choice->offset - oldt; + this_choice->offset = newt + offset; + } + } +} static void format_free_choices(struct format_choice *choices) { @@ -240,6 +256,14 @@ format_free_choices(struct format_choice *choices) } } static void +format_free_choicesp(struct format_choice **choices) +{ + if (choices) { + format_free_choices(*choices); + *choices = NULL; + } +} +static void format_append_choice(struct format_choice **choices, struct format_choice *choice) { @@ -254,18 +278,31 @@ format_append_choice(struct format_choice **choices, while (here->next != NULL) { here = here->next; } + choice->next = here->next; here->next = choice; } } static void format_add_choice(struct format_choice **choices, char *offset, char **values) { - struct format_choice *choice, *here; - choice = malloc(sizeof(*choice)); - if (choice != NULL) { - choice->offset = offset; - choice->values = format_dup_strlist(values); - format_append_choice(choices, choice); + struct format_choice *choice; + int i; + if (values != NULL) { + choice = malloc(sizeof(*choice)); + if (choice != NULL) { + choice->offset = offset; + choice->values = format_dup_strlist(values); + choice->next = NULL; + if (choice->values != NULL) { + for (i = 0; choice->values[i] != NULL; i++) { + continue; + } + choice->n_values = i; + format_append_choice(choices, choice); + } else { + free(choice); + } + } } } @@ -652,7 +689,7 @@ format_deref(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, return ret; } -/* Look up entries in the map named by the second argument, which have the +/* Look up entries in the map named by the second argument, which have this * entry's DN stored in the attribute named by the third argument, pull out the * values for the attribute named by the fourth argument, and create a list * separated by the first argument. */ @@ -859,7 +896,7 @@ format_referred(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, backend_free_map_config(map_bases, map_filter); slapi_pblock_destroy(local_pb); format_free_parsed_args(argv); - return cbdata.outbuf - outbuf; + return cbdata.ret ? cbdata.ret : cbdata.outbuf - outbuf; } /* Evaluate each argument, after the first, in turn, and merge them, using the @@ -898,7 +935,7 @@ format_merge(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, outbuf + ret + (count ? slen : 0), outbuf_len - (ret + (count ? slen : 0)), &these_choices, - ref_attrs, inref_attrs, FALSE); + ref_attrs, inref_attrs); if (len < 0) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, @@ -1000,6 +1037,7 @@ format_match_generic(struct plugin_state *state, } matches[count] = NULL; } + slapi_vattr_values_free(&values, &actual_attr, buffer_flags); } /* Make sure matched is either the single match, the default, or NULL * if we had no default. */ @@ -1016,11 +1054,6 @@ format_match_generic(struct plugin_state *state, if (len > outbuf_len) { slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id, "%s: out of space\n", fnname); - if (values != NULL) { - slapi_vattr_values_free(&values, - &actual_attr, - buffer_flags); - } free(matches); format_free_parsed_args(argv); return -ENOBUFS; @@ -1031,11 +1064,6 @@ format_match_generic(struct plugin_state *state, "%s: no matching values for " "\"%s\", and no default value\n", fnname, argv[1]); - if (values != NULL) { - slapi_vattr_values_free(&values, - &actual_attr, - buffer_flags); - } free(matches); format_free_parsed_args(argv); return -ENOENT; @@ -1047,11 +1075,6 @@ format_match_generic(struct plugin_state *state, if (len > outbuf_len) { slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id, "%s: out of space\n", fnname); - if (values != NULL) { - slapi_vattr_values_free(&values, - &actual_attr, - buffer_flags); - } free(matches[0]); free(matches); format_free_parsed_args(argv); @@ -1075,10 +1098,8 @@ format_match_generic(struct plugin_state *state, plugin_id, "%s: out of space\n", fnname); - if (values != NULL) { - slapi_vattr_values_free(&values, - &actual_attr, - buffer_flags); + for (i = 0; i < count; i++) { + free(matches[i]); } free(matches); format_free_parsed_args(argv); @@ -1110,9 +1131,6 @@ format_match_generic(struct plugin_state *state, } break; } - if (values != NULL) { - slapi_vattr_values_free(&values, &actual_attr, buffer_flags); - } if (matches != NULL) { for (i = 0; i < count; i++) { free(matches[i]); @@ -1336,7 +1354,8 @@ format_lookup_fn(const char *fnname) } /* Retrieve a single value for an attribute. If there are no values, or more - * than one, fail. */ + * than one, return NULL. If there's more than one, store the values in the + * array argument. */ static char * format_single(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, const char *attr, const char *disallowed, char ***values) @@ -1363,7 +1382,8 @@ format_single(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, state->plugin_desc->spd_id, "value for \"%s\" " "contains disallowed " - "character %c\n", + "character \"%c\", " + "ignoring\n", attr, *d); } else { ret = strdup(cret); @@ -1378,7 +1398,7 @@ format_single(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, } else { /* Return the list of values. */ tmp_values = malloc(sizeof(char *) * (count + 1)); - if (*values != NULL) { + if (tmp_values != NULL) { j = 0; for (i = slapi_valueset_first_value(value_set, &value); @@ -1386,7 +1406,11 @@ format_single(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, i = slapi_valueset_next_value(value_set, i, &value)) { cret = slapi_value_get_string(value); - tmp_values[j++] = strdup(cret); + if ((disallowed == NULL) || + (strpbrk(cret, + disallowed) == NULL)) { + tmp_values[j++] = strdup(cret); + } } tmp_values[j] = NULL; *values = format_dup_strlist(tmp_values); @@ -1435,7 +1459,11 @@ format_find_closer(const char *pair, const char *pattern) static char * xstrndup(const char *start, size_t length) { - char *ret; + char *ret, *end; + end = memchr(start, '\0', length); + if (end != NULL) { + length = end - start; + } ret = malloc(length + 1); if (ret != NULL) { memcpy(ret, start, length); @@ -1446,14 +1474,7 @@ xstrndup(const char *start, size_t length) static char * xstrndupp(const char *start, const char *end) { - char *ret; - size_t length = end - start; - ret = malloc(length + 1); - if (ret != NULL) { - memcpy(ret, start, length); - ret[length] = '\0'; - } - return ret; + return xstrndup(start, end - start); } /* Trim off prefixes or suffixes which match the given patterns, free the @@ -1463,33 +1484,13 @@ format_trim_value(struct plugin_state *state, char *input, const char *shortstart, const char *longstart, const char *shortend, const char *longend, const char *replace, const char *replaceall, - const char *replaceval, const char *forbidden) + const char *replaceval) { char *ret; int i, j, k, len; ret = strdup(input); len = strlen(input); if (ret != NULL) { - if (forbidden) { - /* Any forbidden character rejects this value. */ - if (strcspn(input, forbidden) != (size_t) len) { - slapi_log_error(SLAPI_LOG_PLUGIN, - state->plugin_desc->spd_id, - "trim-f: value \"%s\" contains " - "forbidden character '%c'\n", - input, - input + strcspn(input, - forbidden)); - free(ret); - free(input); - return NULL; - } else { - slapi_log_error(SLAPI_LOG_PLUGIN, - state->plugin_desc->spd_id, - "trim-f: ->%s<- => ->%s<-\n", - input, input); - } - } if (shortstart) { /* The shortest initial substring which matches gets * skipped. */ @@ -1642,7 +1643,7 @@ format_expand_simple(struct plugin_state *state, char ***ref_attrs, struct format_inref_attr ***inref_attrs) { char *shortstart, *longstart, *shortend, *longend, **value_list; - char *replace, *replaceall, *replaceval, *forbidden, *tmp, *expr, *p; + char *replace, *replaceall, *replaceval, *tmp, *expr, *p; const char *attribute, *default_value, *alternate_value; size_t spn; int i; @@ -1653,7 +1654,6 @@ format_expand_simple(struct plugin_state *state, replace = NULL; replaceall = NULL; replaceval = NULL; - forbidden = NULL; expr = strdup(fmt); /* It's a simple expression, so evaluate it. Check for substitutions * and text to be stripped if the magic character occurs before the @@ -1679,9 +1679,6 @@ format_expand_simple(struct plugin_state *state, else if (strncmp(p, "/", 1) == 0) { replace = p + 1; } - else if (strncmp(p, "!", 1) == 0) { - forbidden = p + 1; - } expr[spn] = '\0'; if ((replace != NULL) || (replaceall != NULL)) { replaceval = NULL; @@ -1747,8 +1744,7 @@ format_expand_simple(struct plugin_state *state, default_value, NULL, outbuf, outbuf_len, outbuf_choices, - ref_attrs, inref_attrs, - FALSE); + ref_attrs, inref_attrs); free(expr); return i; } else { @@ -1771,7 +1767,7 @@ format_expand_simple(struct plugin_state *state, i = format_expand(state, pb, e, domain, map, alternate_value, NULL, outbuf, outbuf_len, outbuf_choices, - ref_attrs, inref_attrs, FALSE); + ref_attrs, inref_attrs); free(tmp); free(expr); return i; @@ -1781,7 +1777,7 @@ format_expand_simple(struct plugin_state *state, shortstart, longstart, shortend, longend, replace, replaceall, - replaceval, forbidden); + replaceval); /* Supply the looked-up value. */ if (tmp != NULL) { i = strlen(tmp); @@ -1801,27 +1797,23 @@ format_expand_simple(struct plugin_state *state, /* not reached */ } -/* Recursively expand the expression into the output buffer. adding any entries - * we visit (other than e) to the list of visited NDNs. If the result will - * also be an expression, treat the entire result as an attribute specifier and - * evaluate it, otherwise return it. */ +/* Recursively expand the expression into the output buffer. If the result + * will also be an expression, treat the entire result as an attribute + * specifier and evaluate it, otherwise return it. */ static int format_expand(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, const char *domain, const char *map, const char *fmt, const char *disallowed, char *outbuf, int outbuf_len, struct format_choice **outbuf_choices, - char ***ref_attrs, struct format_inref_attr ***inref_attrs, - bool_t is_simple_expression) + char ***ref_attrs, struct format_inref_attr ***inref_attrs) { - int i, j; - int exp_used, exp_size, level; - const char *fmtstart, *fmtend, *match, *attribute; - char *tmp, *fnname, *spd_id, *p; - char *expr; + int i, j, used; + const char *fmtstart, *fmtend, *match, *attribute, *pair; + char *subexp, *fnname, *params, *spd_id, *p; const char *default_value, *alternate_value, *paramstart, *paramend; char *shortstart, *longstart, *shortend, *longend; - char *replace, *replaceall, *replaceval, *forbidden; + char *replace, *replaceall, *replaceval; size_t spn; int (*formatfn)(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, @@ -1833,19 +1825,11 @@ format_expand(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, struct format_inref_attr ***inref_attrs); spd_id = state->plugin_desc->spd_id; - exp_size = outbuf_len * 2; - expr = malloc(exp_size); - if (expr == NULL) { - slapi_log_error(SLAPI_LOG_PLUGIN, spd_id, - "expansion failed: out of memory\n"); - return -ENOMEM; - } /* Expand any subexpressions and call any "functions". */ - level = 0; i = 0; j = 0; - while ((fmt[i] != '\0') && (j < exp_size)) { + while ((fmt[i] != '\0') && (j < outbuf_len)) { switch (fmt[i]) { case '%': /* This might be a subexpression, a "function" call, or @@ -1853,7 +1837,7 @@ format_expand(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, switch (fmt[i + 1]) { case '%': /* It's just an escaped "%". */ - expr[j++] = '%'; + outbuf[j++] = '%'; i += 2; continue; break; @@ -1868,67 +1852,64 @@ format_expand(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, spd_id, "expansion failed: " "no closing brace\n"); - free(expr); return -EINVAL; } else { - /* Mark the first character after the + /* Track the first character after the * simple expression. */ fmtend = match + 1; /* Make a copy of the simple * expression. */ - tmp = xstrndupp(fmtstart + 2, - fmtend - 1); - if (tmp == NULL) { + subexp = xstrndupp(fmtstart + 2, + fmtend - 1); + if (subexp == NULL) { slapi_log_error(SLAPI_LOG_PLUGIN, spd_id, "expansion " "failed: out " "of memory\n"); - free(expr); return -ENOMEM; } /* Expand the simple expression. */ - exp_used = format_expand_simple(state, - pb, e, - domain, - map, - tmp, - disallowed, - expr + j, - exp_size - j, - outbuf_choices, - ref_attrs, - inref_attrs); - if (exp_used < 0) { - /* Miscellaneous failure, FAIL. - */ + used = format_expand_simple(state, + pb, e, + domain, + map, + subexp, + disallowed, + outbuf + j, + outbuf_len - j, + outbuf_choices, + ref_attrs, + inref_attrs); + if (used < 0) { + /* Some failure, FAIL. */ slapi_log_error(SLAPI_LOG_PLUGIN, spd_id, "error " "expanding " "expression " "->%s<-: %s\n", - tmp, - strerror(-exp_used)); - free(tmp); - free(expr); - return exp_used; + subexp, + strerror(-used)); + free(subexp); + return used; } - free(tmp); - if (exp_used + j >= exp_size) { - /* Out of space, FAIL. */ + free(subexp); + subexp = NULL; + if (used + j >= outbuf_len) { + /* Out of space, or would be, + * so return a failure. */ slapi_log_error(SLAPI_LOG_PLUGIN, spd_id, "expansion " "failed: result" " would be too " "big\n"); - free(expr); return -ENOBUFS; } else { /* It fit, so keep going. */ i = (match + 1) - fmt; - j += exp_used; + j += used; } } continue; @@ -1936,7 +1917,7 @@ format_expand(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, default: /* Assume it's a "function" call. Pick out the * name of the function. */ - paramstart = strpbrk(fmt + i, "{("); + paramstart = strpbrk(fmt + i + 1, "{("); if (paramstart == NULL) { /* No start? Bad format. */ slapi_log_error(SLAPI_LOG_PLUGIN, @@ -1944,16 +1925,14 @@ format_expand(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, "expansion failed: " "bad function " "invocation\n"); - free(expr); return -EINVAL; } if (*paramstart == '{') { - paramend = format_find_closer("{}", - paramstart); + pair = "{}"; } else { - paramend = format_find_closer("()", - paramstart); + pair = "()"; } + paramend = format_find_closer(pair, paramstart); if (paramend == NULL) { /* No matching end? Bad format. */ slapi_log_error(SLAPI_LOG_PLUGIN, @@ -1961,7 +1940,6 @@ format_expand(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, "expansion failed: " "bad function " "invocation\n"); - free(expr); return -EINVAL; } fnname = xstrndupp(fmt + i + 1, paramstart); @@ -1971,19 +1949,17 @@ format_expand(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, spd_id, "expansion failed: " "out of memory\n"); - free(expr); return -ENOMEM; } - /* Isolate the parameter string. */ - tmp = xstrndupp(paramstart + 1, paramend); - if (tmp == NULL) { + /* Pick out the parameter list. */ + params = xstrndupp(paramstart + 1, paramend); + if (params == NULL) { /* Out of memory, FAIL. */ slapi_log_error(SLAPI_LOG_PLUGIN, spd_id, "expansion failed: " "out of memory\n"); free(fnname); - free(expr); return -ENOMEM; } /* Find the "function". */ @@ -1996,19 +1972,19 @@ format_expand(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, "named \"%s\" is " "defined\n", fnname); free(fnname); - free(tmp); - free(expr); + free(params); return -ENOSYS; } /* Call the "function". */ - exp_used = (*formatfn)(state, pb, e, - domain, map, - tmp, disallowed, - expr + j, exp_size - j, - outbuf_choices, - ref_attrs, inref_attrs); - free(tmp); - if (exp_used < 0) { + used = (*formatfn)(state, pb, e, + domain, map, + params, disallowed, + outbuf + j, outbuf_len - j, + outbuf_choices, + ref_attrs, inref_attrs); + free(params); + params = NULL; + if (used < 0) { /* Error in function, FAIL. */ slapi_log_error(SLAPI_LOG_PLUGIN, spd_id, @@ -2016,59 +1992,40 @@ format_expand(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, "failed: function " "'%s' failed: %s\n", fnname, - strerror(-exp_used)); + strerror(-used)); free(fnname); - free(expr); - return exp_used; + return used; } free(fnname); - if (exp_used + j >= exp_size) { - /* We'd be out of space, FAIL. */ + fnname = NULL; + if (used + j >= outbuf_len) { + /* We'd be out of space, fail. */ slapi_log_error(SLAPI_LOG_PLUGIN, spd_id, "expansion " "failed: result" " would be too " "big\n"); - free(expr); return -ENOBUFS; } i = (paramend - fmt) + 1; - j += exp_used; + j += used; continue; break; } break; default: /* Default is just a literal character. */ - expr[j++] = fmt[i++]; + outbuf[j++] = fmt[i++]; break; } } - expr[j] = '\0'; + outbuf[j] = '\0'; - if (is_simple_expression) { - exp_used = format_expand_simple(state, pb, e, domain, map, - expr, disallowed, - outbuf, outbuf_len, - outbuf_choices, - ref_attrs, inref_attrs); - if (exp_used < 0) { - free(expr); - return exp_used; - } else { - free(expr); - return j + exp_used; - } + if (j > outbuf_len) { + return -ENOBUFS; } else { - if (outbuf_len < j) { - free(expr); - return -ENOBUFS; - } else { - memcpy(outbuf, expr, j); - free(expr); - return j; - } + return j; } } @@ -2080,6 +2037,7 @@ format_format(struct plugin_state *state, Slapi_Entry *e, char ***ref_attrs, struct format_inref_attr ***inref_attrs) { Slapi_PBlock *pb; + struct format_choice *this_choice; char *buf, *tmp, *ret, *spd_id; const char *match, *fmtstart, *fmtend; int i, buflen, exp_len; @@ -2100,12 +2058,14 @@ format_format(struct plugin_state *state, Slapi_Entry *e, return NULL; } - i = format_expand(state, pb, e, domain, map, fmt, disallowed, + i = format_expand(state, pb, e, domain, map, + fmt, disallowed, buf, buflen, choices, - ref_attrs, inref_attrs, FALSE); + ref_attrs, inref_attrs); if ((i >= 0) && (i < buflen)) { buf[i] = '\0'; ret = strdup(buf); + format_retarget_choicesp(choices, buf, ret); } else { if (i == -ENOBUFS) { if (buflen < MAX_BUFFER_SIZE) { @@ -2137,10 +2097,7 @@ format_format(struct plugin_state *state, Slapi_Entry *e, fmt, slapi_entry_get_ndn(e), strerror(-i)); } - if (choices != NULL) { - format_free_choices(*choices); - *choices = NULL; - } + format_free_choicesp(choices); ret = NULL; } free(buf); @@ -2158,7 +2115,6 @@ format_free_data(char *data) free(data); } } - char * format_get_data(struct plugin_state *state, Slapi_Entry *e, const char *domain, const char *map, @@ -2173,8 +2129,14 @@ format_get_data(struct plugin_state *state, Slapi_Entry *e, void format_free_data_set(char **data) { + int i; + if (data != NULL) { + for (i = 0; data[i] != NULL; i++) { + free(data[i]); + } + free(data); + } } - char ** format_get_data_set(struct plugin_state *state, Slapi_Entry *e, const char *domain, const char *map, @@ -2182,18 +2144,81 @@ format_get_data_set(struct plugin_state *state, Slapi_Entry *e, char ***ref_attrs, struct format_inref_attr ***inref_attrs) { - struct format_choice *choices; - char **ret, *template; + struct format_choice *choices, *this_choice; + char **ret, *template, *s, *p, *q; + int combinations, group, nth, i, j, k, offset, length, template_len; choices = NULL; - return NULL; -#if 0 template = format_format(state, e, domain, map, fmt, disallowed, &choices, ref_attrs, inref_attrs); if (template == NULL) { + format_free_choices(choices); return NULL; } - return NULL; -#endif + /* Figure out how many results we're going to have. */ + combinations = 1; + for (this_choice = choices; + this_choice != NULL; + this_choice = this_choice->next) { + for (i = 0; i < this_choice->n_values; i++) { + slapi_log_error(SLAPI_LOG_PLUGIN, + state->plugin_desc->spd_id, + "choice: \"%s\" %d\n", + this_choice->values[i], + this_choice->offset - template); + } + combinations *= this_choice->n_values; + } + template_len = strlen(template); + ret = malloc((combinations + 1) * sizeof(char *)); + if (ret != NULL) { + /* Work out all of the results. */ + for (i = 0, j = 0; i < combinations; i++) { + /* First figure out how long this result will be. */ + group = combinations; + length = template_len; + for (this_choice = choices; + this_choice != NULL; + this_choice = this_choice->next) { + /* Add the length of the value used here. */ + group /= this_choice->n_values; + s = this_choice->values[(i / group) % + this_choice->n_values]; + length += strlen(s); + } + /* Allocate memory for this result. */ + ret[j] = malloc(length + 1); + if (ret[j] == NULL) { + continue; + } + /* Build the result's value. */ + offset = 0; + k = 0; + group = combinations; + for (this_choice = choices; + this_choice != NULL; + this_choice = this_choice->next) { + /* Copy any part of the template that should be + * in the result by now. */ + length = (this_choice->offset - template) - + offset; + memcpy(ret[j] + k, template + offset, length); + k += length; + offset += length; + group /= this_choice->n_values; + s = this_choice->values[(i / group) % + this_choice->n_values]; + length = strlen(s); + memcpy(ret[j] + k, s, length); + k += length; + } + /* Copy any part of the template which trails the + * choices. */ + strcpy(ret[j] + k, template + offset); + j++; + } + ret[j] = NULL; + } + return ret; } char * |