summaryrefslogtreecommitdiffstats
path: root/src/format.c
diff options
context:
space:
mode:
authorNalin Dahyabhai <nalin.dahyabhai@pobox.com>2008-11-04 17:19:33 -0500
committerNalin Dahyabhai <nalin.dahyabhai@pobox.com>2008-11-04 17:19:33 -0500
commitb3eec3cda6d609383d554d731c2da492046bd204 (patch)
treec655793271ec20d8badd2aea71948f8a4aba5177 /src/format.c
parent2cc6d75d32a5d7ae7f2f51fd67e66bb95826fa34 (diff)
- add a "link" function
Diffstat (limited to 'src/format.c')
-rw-r--r--src/format.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/format.c b/src/format.c
index 2f78ccd..ace8382 100644
--- a/src/format.c
+++ b/src/format.c
@@ -2314,6 +2314,186 @@ format_collect(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
return ret;
}
+/* Evaluate all of the arguments, and concatentate sets of entries from each
+ * list, separating them with an optional separator, padding the lists with a
+ * specified value until all of the elements of all lists have been used. */
+static int
+format_link(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
+ const char *group, const char *set,
+ const char *args, const char *disallowed,
+ char *outbuf, int outbuf_len,
+ struct format_choice **outbuf_choices,
+ char ***ref_attrs, struct format_inref_attr ***inref_attrs,
+ struct format_ref_attr_list ***ref_attr_list,
+ struct format_ref_attr_list ***inref_attr_list)
+{
+ int ret, argc, i, *j, l, n_lists, n_done;
+ unsigned int **lengths, length, max_length;
+ char **argv, ***values, *buffer, *p;
+ struct berval bv, **choices;
+ Slapi_Value *value;
+
+ ret = format_parse_args(state, args, &argc, &argv);
+ if (ret != 0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+ "link: error parsing arguments\n");
+ return -EINVAL;
+ }
+ if (argc < 1) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+ "link: error parsing arguments\n");
+ format_free_parsed_args(argv);
+ return -EINVAL;
+ }
+ if (((argc + 1) % 3) != 0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+ "link: wrong number of arguments\n");
+ format_free_parsed_args(argv);
+ return -EINVAL;
+ }
+
+ /* Allocate space to store the information. */
+ values = malloc(sizeof(char **) * ((argc + 1) / 3));
+ lengths = malloc(sizeof(int *) * ((argc + 1) / 3));
+ j = malloc(sizeof(int) * ((argc + 1) / 3));
+ if ((values == NULL) || (lengths == NULL)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+ "link: out of memory\n");
+ format_free_parsed_args(argv);
+ free(values);
+ free(lengths);
+ free(j);
+ return -ENOMEM;
+ }
+
+ /* Walk the list of the arguments, building a list of lists. */
+ choices = NULL;
+ n_lists = 0;
+ for (i = 0; i < argc; i += 3) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+ "link: evaluating \"%s\"\n", argv[i]);
+ values[i / 3] = format_get_data_set(state, e, group, set,
+ argv[i], disallowed,
+ ref_attrs, inref_attrs,
+ ref_attr_list,
+ inref_attr_list,
+ &lengths[i / 3]);
+ if (values[i / 3] != NULL) {
+ n_lists++;
+ }
+ }
+
+ /* If we got _no_ answers for anything, that's a NULL result. */
+ if (n_lists == 0) {
+ format_free_parsed_args(argv);
+ free(values);
+ free(lengths);
+ free(j);
+ return -ENOENT;
+ }
+
+ /* Walk the lists, building the output data items. */
+ n_lists = (argc + 1) / 3;
+ for (i = 0; i < n_lists; i++) {
+ j[i] = 0;
+ }
+ n_done = 0;
+ length = 0;
+ max_length = 0;
+ buffer = NULL;
+ do {
+ /* Calculate how much space we need. */
+ length = 0;
+ for (i = 0; i < n_lists; i++) {
+ if ((values[i] != NULL) && (values[i][j[i]] != NULL)) {
+ length += lengths[i][j[i]];
+ } else {
+ length += strlen(argv[i * 3 + 1]);
+ }
+ if (i < (n_lists - 1)) {
+ length += strlen(argv[i * 3 + 2]);
+ }
+ }
+ /* Make sure the buffer is large enough. */
+ if (length > max_length) {
+ free(buffer);
+ buffer = malloc(length);
+ if (buffer == NULL) {
+ format_free_bv_list(choices);
+ format_free_parsed_args(argv);
+ for (i = 0; i < n_lists; i += 3) {
+ format_free_data_set(values[i],
+ lengths[i]);
+ }
+ free(values);
+ free(lengths);
+ free(j);
+ return -ENOMEM;
+ }
+ max_length = length;
+ }
+ /* Build the output value. */
+ p = buffer;
+ for (i = 0; i < n_lists; i++) {
+ if ((values[i] != NULL) && (values[i][j[i]] != NULL)) {
+ l = lengths[i][j[i]];
+ memcpy(p, values[i][j[i]], l);
+ p += l;
+ (j[i])++;
+ } else {
+ l = strlen(argv[i * 3 + 1]);
+ memcpy(p, argv[i * 3 + 1], l);
+ p += l;
+ }
+ if (i < (n_lists - 1)) {
+ l = strlen(argv[i * 3 + 2]);
+ memcpy(p, argv[i * 3 + 2], l);
+ p += l;
+ }
+ }
+ /* Add it to the result list. */
+ bv.bv_val = buffer;
+ bv.bv_len = length;
+ if ((p - buffer) != length) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "link: internal error\n");
+ break;
+ } else {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "link: \"%.*s\"\n",
+ bv.bv_len, bv.bv_val);
+ format_add_bv_list(&choices, &bv);
+ }
+ /* Figure out if we're done yet. */
+ for (i = 0, n_done = 0; i < n_lists; i++) {
+ if ((values[i] == NULL) || (values[i][j[i]] == NULL)) {
+ n_done++;
+ }
+ }
+ } while (n_done != n_lists);
+
+ if (choices != NULL) {
+ format_add_choice(outbuf_choices, outbuf, choices);
+ format_free_bv_list(choices);
+ ret = 0;
+ } else {
+ ret = -ENOENT;
+ }
+
+ format_free_parsed_args(argv);
+ for (i = 0; i < argc; i += 3) {
+ format_free_data_set(values[i / 3], lengths[i / 3]);
+ }
+ free(buffer);
+ free(values);
+ free(lengths);
+ free(j);
+
+ return ret;
+}
+
/* Choose a formatting function by name. */
static void *
format_lookup_fn(const char *fnname)
@@ -2343,6 +2523,7 @@ format_lookup_fn(const char *fnname)
{"regsub", format_regsub},
{"ifeq", format_ifeq},
{"collect", format_collect},
+ {"link", format_link},
};
for (i = 0; i < sizeof(fns) / sizeof(fns[0]); i++) {
if ((fns[i].name != NULL) &&