diff options
Diffstat (limited to 'src/format.c')
-rw-r--r-- | src/format.c | 245 |
1 files changed, 243 insertions, 2 deletions
diff --git a/src/format.c b/src/format.c index 87ae640..c2e78ef 100644 --- a/src/format.c +++ b/src/format.c @@ -1,5 +1,7 @@ #include <sys/types.h> +#include <rpcsvc/yp.h> #include <stdlib.h> +#include "defaults.h" #include "format.h" void @@ -19,12 +21,12 @@ format_free_ndn_list(char **ndn_list) } static char * -format_format(Slapi_PBlock *pb, Slapi_Entry *e, const char *fmt, +format_single(Slapi_PBlock *pb, Slapi_Entry *e, const char *attr, char ***visited_ndns) { char **values, *ret; int count; - values = slapi_entry_attr_get_charray(e, fmt); + values = slapi_entry_attr_get_charray(e, attr); for (count = 0; (values != NULL) && (values[count] != NULL); count++) { continue; } @@ -37,6 +39,245 @@ format_format(Slapi_PBlock *pb, Slapi_Entry *e, const char *fmt, return ret; } +static const char * +format_find_closer(const char *pair, const char *pattern) +{ + int i, level = 0; + for (i = 0; pattern[i] != '\0'; i++) { + if (pattern[i] == pair[0]) { + level++; + } else { + if (pattern[i] == pair[1]) { + level--; + } + } + if (level == 0) { + return &pattern[i]; + } + } + return NULL; +} + +/* Recursively expand the expression into the output buffer, adding any entries + * we visit (other than e) to the list of visited NDNs. Unless it's a literal, + * treat the entire input format specifier as an expression. */ +static int +format_expand(Slapi_PBlock *pb, Slapi_Entry *e, + const char *fmt, + char *outbuf, int outbuf_len, + char ***visited_ndns, + PRBool literal) +{ + int i, j; + int exp_len, level; + const char *fmtstart, *fmtend, *match, *attribute; + char *tmp; + char exp[outbuf_len * 2]; + const char *default_value, *alternate_value; + size_t spn; + + slapi_log_error(SLAPI_LOG_PLUGIN, "nis-plugin", + "expanding %s\"%s\"%s\n", + literal ? "" : "%{", fmt, literal ? "" : "%{"); + + /* First, expand any subexpressions. */ + level = 0; + i = 0; + j = 0; + while (fmt[i] != '\0') { + switch (fmt[i]) { + case '%': + /* This might be a subexpression, or an escaped + * character. */ + switch (fmt[i + 1]) { + case '%': + /* It's just an escaped "%". */ + exp[j++] = '%'; + i += 2; + continue; + break; + case '{': + /* Find the beginning of the subexpression. */ + fmtstart = fmt + i; + /* Find the end of the subexpression. */ + match = format_find_closer("{}", fmtstart + 1); + if (match == NULL) { + slapi_log_error(SLAPI_LOG_PLUGIN, "nis-plugin", + "expansion failed: no closing brace (2)\n"); + return -1; + } else { + /* Mark the first character after the + * subexpression. */ + fmtend = match + 1; + /* Make a copy of the subexpression. */ + tmp = malloc(fmtend - fmtstart); + if (tmp == NULL) { + slapi_log_error(SLAPI_LOG_PLUGIN, "nis-plugin", + "expansion out of memory\n"); + return -1; + } + memcpy(tmp, fmtstart + 2, + fmtend - fmtstart - 3); + tmp[fmtend - fmtstart - 3] = '\0'; + /* Recursively expand the + * subexpression. */ + exp_len = format_expand(pb, e, + tmp, + exp + j, + sizeof(exp) - j, + visited_ndns, + FALSE); + free(tmp); + if ((exp_len < 0) || + (exp_len + j >= (int) sizeof(exp))) { + /* We'd be out of space, FAIL. */ + slapi_log_error(SLAPI_LOG_PLUGIN, "nis-plugin", + "expansion too big\n"); + return -1; + } else { + /* It fit, so keep going. */ + i = (match + 1) - fmt; + j += exp_len; + } + } + continue; + break; + } + break; + default: + /* Default is just a literal character. */ + exp[j++] = fmt[i++]; + break; + } + } + exp[j] = '\0'; + + if (literal) { + /* It's a literal string, so we're actually done. */ + i = strlen(exp); + if (i <= outbuf_len) { + memcpy(outbuf, exp, i); + } + slapi_log_error(SLAPI_LOG_PLUGIN, "nis-plugin", + "expanded to \"%s\"\n", exp); + return i; + } else { + /* It's an expression, so evaluate it. */ + slapi_log_error(SLAPI_LOG_PLUGIN, "nis-plugin", + "looking up simple expression \%\{\"%s\"}\n", exp); + /* Check if it uses a default/alternate value. */ + spn = strcspn(exp, ":"); + if (spn == strlen(exp)) { + /* Simple expression: expect it to be a single-valued + * attribute. */ + tmp = format_single(pb, e, exp, visited_ndns); + if (tmp != NULL) { + /* Copy the string to the output buffer if + * there's space for it. */ + i = strlen(tmp); + if (i <= outbuf_len) { + memcpy(outbuf, tmp, i); + } + slapi_log_error(SLAPI_LOG_PLUGIN, "nis-plugin", + "expanded to \"%s\"\n", tmp); + free(tmp); + /* Return the length of the expanded + * expression. */ + return i; + } else { + /* No value found? FAIL. */ + slapi_log_error(SLAPI_LOG_PLUGIN, "nis-plugin", + "no value for \"%s\"\n", exp); + return -1; + } + } else { + /* Make a copy of the attribute name. */ + exp[spn] = '\0'; + attribute = exp; + alternate_value = NULL; + default_value = NULL; + /* Figure out if there's an alternate or default value + * given. */ + switch (exp[spn + 1]) { + case '+': + alternate_value = exp + spn + 2; + break; + case '-': + default_value = exp + spn + 2; + break; + default: + default_value = exp + spn + 1; + break; + } + /* Retrieve the value. */ + tmp = format_single(pb, e, attribute, visited_ndns); + if (tmp == NULL) { + /* The attribute is undefined, or we're + * treating it as if it is. */ + if (default_value != NULL) { + /* Supply the default value. */ + i = strlen(default_value); + if (i <= outbuf_len) { + memcpy(outbuf, default_value, + i); + } + slapi_log_error(SLAPI_LOG_PLUGIN, "nis-plugin", + "expanded to \"%s\"\n", default_value); + return i; + } else { + /* No value, and no default: FAIL. */ + slapi_log_error(SLAPI_LOG_PLUGIN, "nis-plugin", + "failed to expand: no valid value, no default\n"); + return -1; + } + } else { + /* There's no value defined (or it's + * multi-valued, which is usually trouble). */ + if (alternate_value != NULL) { + /* Supply the alternate value. */ + i = strlen(alternate_value); + if (i <= outbuf_len) { + memcpy(outbuf, alternate_value, + i); + } + slapi_log_error(SLAPI_LOG_PLUGIN, "nis-plugin", + "expanded to \"%s\"\n", alternate_value); + free(tmp); + return i; + } else { + /* Supply the looked-up value. */ + i = strlen(tmp); + if (i <= outbuf_len) { + memcpy(outbuf, tmp, i); + } + slapi_log_error(SLAPI_LOG_PLUGIN, "nis-plugin", + "expanded to \"%s\"\n", tmp); + free(tmp); + return i; + } + } + } + } +} + +static char * +format_format(Slapi_PBlock *pb, Slapi_Entry *e, const char *fmt, + char ***visited_ndns) +{ + char buf[YPMAXRECORD], *tmp; + const char *match, *fmtstart, *fmtend; + unsigned int i, j; + int exp_len; + + i = format_expand(pb, e, fmt, buf, sizeof(buf), visited_ndns, TRUE); + if (i < sizeof(buf)) { + buf[i] = '\0'; + return strdup(buf); + } else { + return NULL; + } +} + char * format_get_data(Slapi_PBlock *pb, Slapi_Entry *e, const char *fmt, char ***visited_ndns) |