+#ifndef COMPILE_UTILITY
+/*************************************************
+* Get a block annotated as being lookup-quoted *
+*************************************************/
+
+/* Allocate from pool a pool consistent with the proto_mem augmented by the
+requested quoter type.
+
+XXX currently not handling mark/release
+
+Args: size number of bytes to allocate
+ quoter id for the quoting type
+ func caller, for debug
+ linenumber caller, for debug
+
+Return: allocated memory block
+*/
+
+static void *
+store_force_get_quoted(int size, unsigned quoter, const uschar * quoter_name,
+ const char * func, int linenumber)
+{
+pooldesc * pp = pool_for_quoter(quoter, NULL);
+void * yield;
+
+DEBUG(D_memory)
+ debug_printf("allocating quoted-block for quoter %u (from %s %d)\n", quoter, func, linenumber);
+
+if (!pp) pp = quoted_pool_new(quoter, quoter_name);
+yield = pool_get(pp, size, FALSE, func, linenumber);
+
+DEBUG(D_memory)
+ debug_printf("---QQ Get %6p %5d %-14s %4d\n",
+ pp->store_last_get, size, func, linenumber);
+
+return yield;
+}
+
+/* Maybe get memory for the specified quoter, but only if the
+prototype memory is tainted. Otherwise, get plain memory.
+*/
+void *
+store_get_quoted_3(int size, const void * proto_mem, unsigned quoter,
+ const uschar * quoter_name, const char * func, int linenumber)
+{
+return is_tainted(proto_mem)
+ ? store_force_get_quoted(size, quoter, quoter_name, func, linenumber)
+ : store_get_3(size, proto_mem, func, linenumber);
+}
+
+/* Return quoter for given address, or -1 if not in a quoted-pool. */
+int
+quoter_for_address(const void * p, const uschar ** namep)
+{
+const quoted_pooldesc * qp;
+for (qp = quoted_pools; qp; qp = qp->next)
+ {
+ const pooldesc * pp = &qp->pool;
+ storeblock * b;
+
+ if (b = pp->current_block)
+ if (is_pointer_in_block(b, p))
+ goto found;
+
+ for (b = pp->chainbase; b; b = b->next)
+ if (is_pointer_in_block(b, p))
+ goto found;
+ }
+if (namep) *namep = NULL;
+return -1;
+
+found:
+ if (namep) *namep = qp->quoter_name;
+ return qp->quoter;
+}
+
+/* Return TRUE iff the given address is quoted for the given type.
+There is extra complexity to handle lookup providers with multiple
+find variants but shared quote functions. */
+BOOL
+is_quoted_like(const void * p, const void * v_q_li)
+{
+const uschar * p_name;
+const lookup_info * p_li, * q_li = v_q_li;
+void * p_qfn, * q_qfn;
+
+(void) quoter_for_address(p, &p_name);
+
+if (!p_name)
+ {
+ DEBUG(D_any) debug_printf("No quoter name for addr\n");
+ return FALSE;
+ }
+
+p_li = search_findtype(p_name, Ustrlen(p_name));
+p_qfn = p_li ? p_li->quote : NULL;
+q_qfn = q_li ? q_li->quote : NULL;
+
+BOOL y = p_qfn == q_qfn;
+
+/* debug_printf("is_quoted(%p, %u): %c\n", p, quoter, y?'T':'F'); */
+return y;
+}
+
+/* Return TRUE if the quoter value indicates an actual quoter */
+BOOL
+is_real_quoter(int quoter)
+{
+return quoter >= 0;
+}
+
+
+/* Return TRUE if the "new" data requires that the "old" data
+be recopied to new-class memory. We order the classes as
+
+ 2: tainted, not quoted
+ 1: quoted (which is also tainted)
+ 0: untainted
+
+If the "new" is higher-order than the "old", they are not compatible
+and a copy is needed. If both are quoted, but the quoters differ,
+not compatible. Otherwise they are compatible.
+*/
+BOOL
+is_incompatible_fn(const void * old, const void * new)
+{
+int oq, nq;
+unsigned oi, ni;
+
+ni = is_real_quoter(nq = quoter_for_address(new, NULL)) ? 1 : is_tainted(new) ? 2 : 0;
+oi = is_real_quoter(oq = quoter_for_address(old, NULL)) ? 1 : is_tainted(old) ? 2 : 0;
+return ni > oi || ni == oi && nq != oq;
+}
+
+#endif /*!COMPILE_UTILITY*/