var-expand.c revision 3e859421cc59d28d4ba99f32830e3d0531334813
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen#include "lib.h"
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen#include "array.h"
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen#include "md5.h"
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen#include "hash.h"
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen#include "hex-binary.h"
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen#include "str.h"
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen#include "strescape.h"
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen#include "var-expand.h"
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen#include <stdlib.h>
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainenstruct var_expand_context {
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen int offset;
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen unsigned int width;
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen bool zero_padding;
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen};
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainenstruct var_expand_modifier {
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen char key;
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen const char *(*func)(const char *, struct var_expand_context *);
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen};
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainenstatic const char *
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainenm_str_lcase(const char *str, struct var_expand_context *ctx __attr_unused__)
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen{
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen return t_str_lcase(str);
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen}
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainenstatic const char *
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainenm_str_ucase(const char *str, struct var_expand_context *ctx __attr_unused__)
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen{
cd700cc7be045389dd1c948b2372b30ee99c5795Timo Sirainen return t_str_ucase(str);
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen}
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainenstatic const char *
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainenm_str_escape(const char *str, struct var_expand_context *ctx __attr_unused__)
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen{
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen return str_escape(str);
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen}
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainenstatic const char *
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainenm_str_hex(const char *str, struct var_expand_context *ctx __attr_unused__)
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen{
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen unsigned long long l;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen l = strtoull(str, NULL, 10);
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen return t_strdup_printf("%llx", l);
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen}
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainenstatic const char *
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainenm_str_reverse(const char *str, struct var_expand_context *ctx __attr_unused__)
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen{
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen size_t len = strlen(str);
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen char *p, *rev;
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen rev = t_malloc(len + 1);
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen rev[len] = '\0';
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen for (p = rev + len - 1; *str != '\0'; str++)
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen *p-- = *str;
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen return rev;
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen}
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainenstatic const char *m_str_hash(const char *str, struct var_expand_context *ctx)
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen{
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen unsigned int value = str_hash(str);
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen string_t *hash = t_str_new(20);
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen if (ctx->width != 0) {
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen value %= ctx->width;
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen ctx->width = 0;
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen }
869b0fa6ef7fc0326c9f75ae449e5a9f97a796e2Timo Sirainen
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen str_printfa(hash, "%x", value);
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen while ((int)str_len(hash) < ctx->offset)
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen str_insert(hash, 0, "0");
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen ctx->offset = 0;
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen return str_c(hash);
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen}
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainenstatic const char *m_str_md5(const char *str, struct var_expand_context *ctx __attr_unused__)
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen{
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen unsigned char digest[16];
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen md5_get_digest(str, strlen(str), digest);
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen return binary_to_hex(digest, sizeof(digest));
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen}
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainenstatic const char *m_str_ldap_dn(const char *str, struct var_expand_context *ctx __attr_unused__)
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen{
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen string_t *ret = t_str_new(256);
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen while (*str) {
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen if (*str == '.')
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen str_append(ret, ",dc=");
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen else
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen str_append_c(ret, *str);
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen str++;
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen }
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen return str_free_without_data(&ret);
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen}
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen#define MAX_MODIFIER_COUNT 10
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainenstatic const struct var_expand_modifier modifiers[] = {
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen { 'L', m_str_lcase },
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen { 'U', m_str_ucase },
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen { 'E', m_str_escape },
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen { 'X', m_str_hex },
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen { 'R', m_str_reverse },
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen { 'H', m_str_hash },
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen { 'M', m_str_md5 },
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen { 'D', m_str_ldap_dn },
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen { '\0', NULL }
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen};
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainenvoid var_expand(string_t *dest, const char *str,
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen const struct var_expand_table *table)
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen{
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen const struct var_expand_modifier *m;
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen const struct var_expand_table *t;
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen const char *var;
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen struct var_expand_context ctx;
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen const char *(*modifier[MAX_MODIFIER_COUNT])
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen (const char *, struct var_expand_context *);
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen unsigned int i, modifier_count;
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen memset(&ctx, 0, sizeof(ctx));
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen for (; *str != '\0'; str++) {
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen if (*str != '%')
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen str_append_c(dest, *str);
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen else {
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen int sign = 1;
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen str++;
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen memset(&ctx, 0, sizeof(ctx));
55de1a4d11765e795ec96fddd4858b188be4b892Timo Sirainen
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen /* [<offset>.]<width>[<modifiers>]<variable> */
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen if (*str == '-') {
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen sign = -1;
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen str++;
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen }
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen if (*str == '0') {
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen ctx.zero_padding = TRUE;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen str++;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen }
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen while (*str >= '0' && *str <= '9') {
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen ctx.width = ctx.width*10 + (*str - '0');
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen str++;
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen }
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen if (*str == '.') {
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen ctx.offset = sign * (int)ctx.width;
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen ctx.width = 0;
55de1a4d11765e795ec96fddd4858b188be4b892Timo Sirainen str++;
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen /* if offset was prefixed with zero (or it was
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen plain zero), just ignore that. zero padding
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen is done with the width. */
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen ctx.zero_padding = FALSE;
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen if (*str == '0') {
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen ctx.zero_padding = TRUE;
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen str++;
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen }
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen
55de1a4d11765e795ec96fddd4858b188be4b892Timo Sirainen while (*str >= '0' && *str <= '9') {
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen ctx.width = ctx.width*10 + (*str - '0');
55de1a4d11765e795ec96fddd4858b188be4b892Timo Sirainen str++;
55de1a4d11765e795ec96fddd4858b188be4b892Timo Sirainen }
55de1a4d11765e795ec96fddd4858b188be4b892Timo Sirainen }
55de1a4d11765e795ec96fddd4858b188be4b892Timo Sirainen
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen modifier_count = 0;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen while (modifier_count < MAX_MODIFIER_COUNT) {
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen modifier[modifier_count] = NULL;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen for (m = modifiers; m->key != '\0'; m++) {
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen if (m->key == *str) {
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen /* @UNSAFE */
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen modifier[modifier_count] =
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen m->func;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen str++;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen break;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen }
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen }
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen if (modifier[modifier_count] == NULL)
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen break;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen modifier_count++;
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen }
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen if (*str == '\0')
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen break;
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen var = NULL;
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen for (t = table; t->key != '\0'; t++) {
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen if (t->key == *str) {
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen var = t->value != NULL ? t->value : "";
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen break;
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen }
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen }
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen if (var == NULL) {
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen /* not found */
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen if (*str == '%')
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen var = "%";
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen }
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen if (var != NULL) {
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen for (i = 0; i < modifier_count; i++)
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen var = modifier[i](var, &ctx);
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen if (ctx.offset < 0) {
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen /* if offset is < 0 then we want to
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen start at the end */
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen size_t len = strlen(var);
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen if (len > (size_t)-ctx.offset)
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen var += len + ctx.offset;
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen } else {
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen while (*var != '\0' && ctx.offset > 0) {
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen ctx.offset--;
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen var++;
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen }
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen }
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen if (ctx.width == 0)
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen str_append(dest, var);
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen else if (!ctx.zero_padding)
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen str_append_n(dest, var, ctx.width);
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen else {
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen /* %05d -like padding. no truncation. */
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen size_t len = strlen(var);
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen while (len < ctx.width) {
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen str_append_c(dest, '0');
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen ctx.width--;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen }
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen str_append(dest, var);
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen }
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen }
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen }
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen }
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen}
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainenchar var_get_key(const char *str)
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen{
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen const struct var_expand_modifier *m;
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen /* [<offset>.]<width>[<modifiers>]<variable> */
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen while ((*str >= '0' && *str <= '9') || *str == '-')
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen str++;
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen if (*str == '.') {
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen str++;
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen while (*str >= '0' && *str <= '9')
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen str++;
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen }
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen do {
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen for (m = modifiers; m->key != '\0'; m++) {
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen if (m->key == *str) {
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen str++;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen break;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen }
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen }
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen } while (m->key != '\0');
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen return *str;
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen}
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainenconst struct var_expand_table *
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainenvar_expand_table_build(char key, const char *value, char key2, ...)
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen{
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen ARRAY_DEFINE(variables, struct var_expand_table);
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen struct var_expand_table *var;
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen va_list args;
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen i_assert(key != '\0');
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen t_array_init(&variables, 16);
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen var = array_append_space(&variables);
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen var->key = key;
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen var->value = value;
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen va_start(args, key2);
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen for (key = key2; key != '\0'; key = va_arg(args, int)) {
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen var = array_append_space(&variables);
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen var->key = key;
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen var->value = va_arg(args, const char *);
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen }
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen va_end(args);
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen /* 0, NULL entry */
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen (void)array_append_space(&variables);
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen return array_idx(&variables, 0);
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen}