static void save_pointer(stream, void *ptr)
{
  save_bytes(stream, &ptr, sizeof(void *));
}

static void save_atom(stream, Atom at)
{
  if (IsWideAtom(at)) {
    UInt sz = wcslen(RepAtom(at)->WStrOfAE);
    save_tag(stream, QLF_WIDE_ATOM);
    save_uint(stream, sz);
    save_bytes(stream, RepAtom(at)->WStrOfAE, (sz+1)*sizeof(wchar_t));
  } else {
    save_tag(stream, QLF_ATOM);
    save_bytes(stream, RepAtom(at)->StrOfAE, (sz+1)*sizeof(char));
  }
}

static void save_Arity(IOSTREAM *stream, Int a)
{
  save_Integer(stream, a);
}

static void save_CellPtoHeap(IOSTREAM *stream, CELL *ptr)
{
  save_pointer(stream, ptr);
}

static void save_ConstantTerm(IOSTREAM *stream, Term t)
{
  if (IsIntTerm(t)) {
    save_int_tag(stream);
    save_Integer(stream, IntOfTerm(t));
  }
  save_atom_tag(stream);
  save_atom(stream, AtomOfTerm(t));
}

static void save_DoubleInCode(IOSTREAM *stream, Term t)
{
  save_pointer(stream, (void *)RepAppl(t));
}

static void save_DBGroundTerm(IOSTREAM *stream, Term t)
{
  save_term(stream, t);
}

static void save_Func(IOSTREAM *stream, Functor f)
{
  save_atom(stream, NameOfFunctor(f));
  save_Arity(stream, ArityOfFunctor(f));
}

static void save_ExternalFunction(IOSTREAM *stream, Functor f)
{
  Yap_Error(INTERNAL_ERROR, TermNil, "trying to save an ExternalFunction");
}

static void save_IntegerInCode(IOSTREAM *stream, Term t)
{
  save_pointer(stream, (void *)RepAppl(t));
}

static void save_PtoLUIndex(IOSTREAM *stream, Term t)
{
  Yap_Error(INTERNAL_ERROR, TermNil, "trying to save PtoLUIndex");
}

static void save_PtoOp(IOSTREAM *stream, yamop *l)
{
  save_pointer(stream, (void *)l);
}

static void save_PtoLUClause(IOSTREAM *stream, struct logic_upd_clause *t)
{
  Yap_Error(INTERNAL_ERROR, TermNil, "trying to save PtoLUIndex");
}

static void save_ConstantTerm(IOSTREAM *stream, Term t)
{
  save_atom(stream, AtomOfTerm(t));
}

static void save_BlobTermInCode(IOSTREAM *stream, Term t)
{
  save_pointer(stream, (void *)RepAppl(t));
}

static void save_Opcode(IOSTREAM *stream, OPCODE op)
{
  save_Integer(stream, Yap_op_from_opcode(op));
}

#ifdef YAPOR
static void save_OrArg(IOSTREAM *stream, unsigned int i)
{
  save_unsigned_int(stream, i);
}
#endif /* YAPOR */

#ifdef YAPOR
static void save_PtoPred(IOSTREAM *stream, struct pred_entry *ap)
{
  if (ap->ModuleOfPred) {
    save_atom(stream, AtomOfTerm(ap->ModuleOfPred));
  } else {
    save_atom(stream, AtomProlog);
  }
  if (ap->ArityOfPE) {
    saveInt(stream, ap->ArityOfPE);
    save_atom(stream, NameOfFunctor(ap->FunctorOfPred));
  } else {
    saveInt(stream, 0);
    save_atom(stream, (Atom)(ap->FunctorOfPred));
  }
}

static void save_Constant(IOSTREAM *stream, Term t)
{
  if (IsIntTerm(t)) {
    save_int_tag(stream);
    save_Integer(stream, IntOfTerm(t));
  }
  save_atom_tag(stream);
  save_atom(stream, AtomOfTerm(t));
}


#ifdef TABLING
static void save_TabEntry(IOSTREAM *stream, struct table_entry *ap)
{
  save_pointer(stream, NULL);
}
#endif

#if PRECOMPUTE_REGADDRESS
#define arg_from_x(I)		(((CELL *)(I))-XREGS)
#else
#define arg_from_x(I)		(I)
#endif /* PRECOMPUTE_REGADDRESS */

static void save_X(IOSTREAM *stream, XREG reg)
{
  save_Int(stream, arg_from_x(reg));
}

static void save_Y(IOSTREAM *stream, YREG reg)
{
  save_Int(stream, reg);
}


save_code(IOSTREAM *stream, yamop *pc, yamop *max) {
#include "saveclause.h"
  if (max && max > pc) {
    save_bits(stream, pc, max);
  }
}

static void
save_lu_clause(IOSTREAM *stream, LogUpdate *cl) {
  save_new_clause_marker(stream);
  save_term(stream, cl->ClSource);
  save_code(stream, cl->ClCode, cl->ClSource);
}

static void
save_dynamic_clause(IOSTREAM *stream, DynamicUpdate *cl) {
  save_new_clause_marker(stream);
  save_term(stream, cl->ClSource);
  save_code(stream, cl->ClCode, cl->ClSource);
}

static void
save_static_clause(IOSTREAM *stream, LogUpdate *cl) {
  save_new_clause_marker(stream);
  if (!(cl->ClFlags & FactMask)) {
    save_term(stream, cl->usc.ClSource);
    save_code(stream, cl->ClCode, cl->usc.ClSource);
  } else {
    save_code(stream, cl->ClCode, NULL);
  }
}

static void
save_mega_clause(IOSTREAM *stream, LogUpdate *cl) {
  UInt i;
  yamop *ptr;
  UInt ncls = cl->ClPred->cs.p_code.NOfClauses;

  for (i = 0, ptr = cl->ClCode; i < ncls; i++) {
    yamop *nextptr = (yamop *)((char *)ptr + cl->ClItemSize);
    save_new_clause_marker(stream);
    save_code(stream, ptr, nextptr);
    ptr = nextptr;
  }
}

static void
save_clauses(IOSTREAM *stream, PredEntry *pp) {
  yamop        *FirstC, *LastC;

  FirstC = pp->cs.p_code.FirstClause;
  LastC = pp->cs.p_code.LastClause;
  if (FirstC == NULL && LastC == NULL) {
    save_end_clauses_marker(stream);
    return;
  }
  if (pp->PredFlags & LogUpdatePredFlag) {
    LogUpdClause *cl = ClauseCodeToLogUpdClause(First);

    while (cl != NULL) {
      save_lu_clause(stream, cl);
      cl = cl->ClNext;
    }
  } else if (pp->PredFlags & MegaClausePredFlag) {
    MegaClause *cl = ClauseCodeToMegaClause(First);

    save_mega_clause(stream, cl);
  } else if (pp->PredFlags & DynamicPredFlag) {
    yamop *cl = First;

    do {
      save_dynamic_clause(stream, ClauseCodeToDynamicClause(cl));
      if (cl == Last) return;
      cl = NextDynamicClause(cl);
    } while (TRUE);
  } else {
    StaticClause *cl = ClauseCodeToStaticClause(First);

    do {
      save_static_clause(stream, cl);
      if (cl->ClCode == Last) return;
      cl = cl->ClNext;
    } while (TRUE);
  }
  save_end_clauses_marker(stream);
}

}

static void
save_pred(IOSTREAM *stream, PredEntry *ap) {
  save_atom(stream, ap->NameOfPE);
  save_uint(stream, ap->ArityOfPE);
  save_uint(stream, ap->PredFlags);
  save_uint(stream, ap->cs.p_code.NOfClauses);
  save_clauses(stream, ap);
}

static void
save_module(IOSTREAM *stream, Term mod) {
  PredEntry *ap = Yap_ModulePred(mod);
  while (ap) {
    save_pred(stream, ap);
    ap = ap->NextPredOfModule;
  }
}
