/*
* Copyright (c) 2005 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*/
#include "sm/generic.h"
SM_RCSID("@(#)$Id: strexpmaccb.c,v 1.2 2005/07/05 17:20:49 ca Exp $")
#include "sm/assert.h"
#include "sm/magic.h"
#include "sm/ctype.h"
#include "sm/str-int.h"
#include "sm/strexp.h"
/*
** SM_STR_EXPMAC_CB -- Expand ${macro} in string
** \$ will be replaced by $ to suppress expansion of ${macro}
**
** Parameters:
** src -- str to expand (read)
** dst -- str into which the expanded sequence is written (output)
** flags -- flags (currently unused)
** expmac -- callback to expand macro
** ctx -- context for callback to expand macro
**
** Returns:
** ==0: no macro in src, NOTHING written to dst!
** >=0: number of replacements
** <0: usual sm_error code
*/
sm_ret_T
sm_str_expmac_cb(const sm_str_P src, sm_str_P dst, uint flags, sm_str_expmac_cb_F expmac, void *ctx)
{
uint i, len, idx, replacements, mac_begin;
uchar ch;
sm_ret_T ret;
bool backslash, found;
SM_IS_BUF(dst);
SM_IS_BUF(src);
SM_REQUIRE(expmac != NULL);
#define MACPUTCH(ch) \
do { \
ret = sm_str_put(dst, (ch)); \
if (sm_is_err(ret)) \
goto error; \
} while (0)
len = sm_str_getlen(src);
backslash = false;
found = false;
for (i = 0; i < len; i++)
{
ch = sm_str_rd_elem(src, i);
/* need at least ${A} */
if (!backslash &&
ch == '$' && i + 3 < len &&
(ch = sm_str_rd_elem(src, i + 1)) == '{')
{
found = true;
break;
}
if (!backslash)
backslash = ch == '\\';
else
{
/* \$ will be replaced */
if (ch == '$')
{
found = true;
break;
}
backslash = false;
}
}
if (!found)
return 0;
replacements = 0;
backslash = false;
for (i = 0; i < len; i++)
{
ch = sm_str_rd_elem(src, i);
/* need at least ${A} */
if (!backslash &&
ch == '$' && i + 3 < len &&
(ch = sm_str_rd_elem(src, i + 1)) == '{')
{
i += 2;
mac_begin = i;
for (;
i < len && (ch = sm_str_rd_elem(src, i)) != '}';
i++)
;
if (i < len && ch == '}')
{
ret = expmac(src, len, dst, mac_begin, i - 1,
ctx);
++replacements;
if (sm_is_err(ret))
continue;
}
else
{
/* copy "skipped" text over */
MACPUTCH('$');
MACPUTCH('{');
for (idx = mac_begin; idx < i; idx++)
{
ch = sm_str_rd_elem(src, idx);
MACPUTCH(ch);
}
}
}
else
{
if (!backslash)
{
backslash = ch == '\\';
if (backslash)
{
++replacements;
continue;
}
}
else
{
backslash = false;
if (ch != '$')
MACPUTCH('\\');
else
++replacements;
}
ret = sm_str_put(dst, ch);
if (sm_is_err(ret))
goto error;
}
}
if (backslash)
MACPUTCH('\\');
if (replacements > (uint)SM_RET_MAX)
replacements = SM_RET_MAX;
return (sm_ret_T) replacements;
error:
/* cleanup? */
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1