+mp *mp_dest(mp *m, size_t sz, unsigned f)
+{
+ /* --- If no destination, make one --- */
+
+ if (m == MP_NEWSEC)
+ m = mp_new(sz, f | MP_UNDEF | MP_BURN);
+ else if (m == MP_NEW)
+ m = mp_new(sz, f | MP_UNDEF);
+ else {
+ size_t len = MP_LEN(m);
+ unsigned undef = (m->f | f) & MP_UNDEF;
+
+ /* --- If the value must be preserved, the block can't shrink --- */
+
+ if (!undef && sz < len)
+ sz = len;
+
+ /* --- Otherwise check whether the destination is suitable --- */
+
+ if (m->ref > 1 || (m->f & MP_CONST) ||
+ m->sz > len || !((f & ~m->f) & MP_BURN)) {
+
+ /* --- No -- allocate a new buffer --- *
+ *
+ * The buffer must be secure if (a) the caller requested a secure
+ * buffer, or (b) the old buffer is secure and I'm not allowed to
+ * discard the old contents.
+ */
+
+ mparena *a;
+ mpw *v;
+
+ if ((f & MP_BURN) || (!undef && (m->f & MP_BURN)))
+ a = MPARENA_SECURE;
+ else
+ a = MPARENA_GLOBAL;
+ v = mpalloc(a, sz);
+
+ /* --- Copy the data over --- */
+
+ if (!undef) {
+ memcpy(v, m->v, MPWS(len));
+ if (sz - len > 0)
+ memset(v + len, 0, MPWS(sz - len));
+ }
+
+ /* --- If @m@ has other references, make a new node --- *
+ *
+ * Otherwise dispose of the old buffer.
+ */
+
+ if (!(m->f & MP_CONST) && m->ref == 1) {
+ if (m->f & MP_BURN)
+ memset(m->v, 0, MPWS(m->sz));
+ mpfree(m->a, m->v);
+ } else {
+ mp *mm = CREATE(mp);
+ mm->ref = 1;
+ mm->f = m->f;
+ m->ref--;
+ m = mm;
+ }
+
+ /* --- Fix up the node --- */
+
+ m->v = v;
+ m->vl = v + sz;
+ m->sz = sz;
+ m->f = ((m->f & ~(MP_CONST | MP_BURN)) |
+ (f & (MP_BURN | MP_UNDEF)));
+ m->a = a;
+ }
+
+ /* --- If the number is growing in its buffer, fix it up --- */
+
+ else if (sz > len) {
+ if (!undef)
+ memset(m->vl, 0, MPWS(sz - len));
+ m->vl = m->v + sz;
+ }
+ }
+
+ /* --- Done --- */
+
+ return (m);
+}