/* * 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; }