Exemple #1
0
/*
 * Scm_Write - Standard Write.
 */
void Scm_Write(ScmObj obj, ScmObj p, int mode)
{
    if (!SCM_OPORTP(p)) Scm_Error("output port required, but got %S", p);

    ScmPort *port = SCM_PORT(p);
    ScmWriteContext ctx;
    write_context_init(&ctx, mode, 0, 0);
    ScmVM *vm = Scm_VM();

    if (PORT_LOCK_OWNER_P(port, vm) && PORT_RECURSIVE_P(port)) {
        /* Special treatment - if we're "display"-ing a string, we'll bypass
           walk path even if we're in the middle of write/ss.  Using srfi-38
           notation to show displayed strings doesn't make sense at all.
         */
        if (PORT_WALKER_P(port) &&
            !((mode == SCM_WRITE_DISPLAY) && SCM_STRINGP(obj))) {
            write_walk(obj, port);
        } else {
            write_rec(obj, port, &ctx);
        }
        return;
    }

    PORT_LOCK(port, vm);
    if (WRITER_NEED_2PASS(&ctx)) {
        PORT_SAFE_CALL(port, write_ss(obj, port, &ctx),
                       cleanup_port_write_state(port));
    } else {
        PORT_SAFE_CALL(port, write_rec(obj, port, &ctx), /*no cleanup*/);
    }
    PORT_UNLOCK(port);
}
Exemple #2
0
/*
 * Scm_WriteLimited - Write to limited length.
 *
 *  Characters exceeding WIDTH are truncated.
 *  If the output fits within WIDTH, # of characters actually written
 *  is returned.  Othewise, -1 is returned.
 *
 *  Currently this API is only used from Scm_Printf, for 'format' has been
 *  moved to libfmt.scm.  I don't like the way this is implemented and would
 *  like to share this with libfmt.scm eventually.
 */
int Scm_WriteLimited(ScmObj obj, ScmObj p, int mode, int width)
{
    if (!SCM_OPORTP(p)) {
        Scm_Error("output port required, but got %S", p);
    }

    ScmPort *port = SCM_PORT(p);

    /* The walk pass does not produce any output, so we don't bother to
       create an intermediate string port. */
    if (PORT_LOCK_OWNER_P(port, Scm_VM()) && PORT_WALKER_P(port)) {
        SCM_ASSERT(PORT_RECURSIVE_P(port));
        write_walk(obj, port);
        return 0;               /* doesn't really matter */
    }

    ScmObj out = Scm_MakeOutputStringPort(TRUE);
    SCM_PORT(out)->writeState = SCM_PORT(port)->writeState;
    ScmWriteContext ctx;
    write_context_init(&ctx, mode, 0, width);

    /* We don't need to lock 'out', nor clean it up, for it is private. */
    /* This part is a bit confusing - we only need to call write_ss
       if we're at the toplevel call.  */
    if (PORT_RECURSIVE_P(SCM_PORT(port))) {
        write_rec(obj, SCM_PORT(out), &ctx);
    } else if (WRITER_NEED_2PASS(&ctx)) {
        write_ss(obj, SCM_PORT(out), &ctx);
    } else {
        write_rec(obj, SCM_PORT(out), &ctx);
    }
    
    ScmString *str = SCM_STRING(Scm_GetOutputString(SCM_PORT(out), 0));
    int nc = SCM_STRING_BODY_LENGTH(SCM_STRING_BODY(str));
    if (nc > width) {
        ScmObj sub = Scm_Substring(str, 0, width, FALSE);
        SCM_PUTS(sub, port);    /* this locks port */
        return -1;
    } else {
        SCM_PUTS(str, port);    /* this locks port */
        return nc;
    }
}
Exemple #3
0
static inline void		write_rec(uint64_t nbr, char *buff, t_pfflags *flags,
							int *index)
{
	if (nbr > (size_t)(flags->base - 1))
		write_rec(nbr / flags->base, buff, flags, index);
	if (nbr % flags->base < 10)
		buff[++*index] = '0' + nbr % flags->base;
	else
		buff[++*index] = (BIT_VAL(flags->flg, 1) ? 'A' : 'a') + nbr %
			flags->base - 10;
}
Exemple #4
0
inline void				write_uint(uint64_t nbr, char *buff, t_pfflags *flags,
							int *index)
{
	int					n;

	if (BIT_VAL(flags->flg, 13))
	{
		n = flags->n_digits - 1;
		while (++n < flags->prec)
			buff[++*index] = '0';
	}
	write_rec(nbr, buff, flags, index);
}
Exemple #5
0
/* Write/ss main driver
   This should never be called recursively.
   We modify port->flags and port->writeState; they are cleaned up
   by the caller even if we throw an error during write. */
static void write_ss(ScmObj obj, ScmPort *port, ScmWriteContext *ctx)
{
    SCM_ASSERT(port->writeState == NULL);

    /* pass 1 */
    port->flags |= SCM_PORT_WALKING;
    if (SCM_WRITE_MODE(ctx)==SCM_WRITE_SHARED) port->flags |= SCM_PORT_WRITESS;
    ScmWriteState *s = Scm_MakeWriteState(NULL);
    s->sharedTable = SCM_HASH_TABLE(Scm_MakeHashTableSimple(SCM_HASH_EQ, 0));
    port->writeState = s;

    write_walk(obj, port);
    port->flags &= ~(SCM_PORT_WALKING|SCM_PORT_WRITESS);

    /* pass 2 */
    write_rec(obj, port, ctx);
    cleanup_port_write_state(port);
}
Exemple #6
0
/*
 * Scm_WriteWithControls - the general entry
 */
void Scm_WriteWithControls(ScmObj obj, ScmObj p, int mode,
                           const ScmWriteControls *ctrl)
{
    if (!SCM_OPORTP(p)) Scm_Error("output port required, but got %S", p);

    ScmPort *port = SCM_PORT(p);
    ScmVM *vm = Scm_VM();
    if (ctrl == NULL) ctrl = Scm_DefaultWriteControls();

    if (PORT_LOCK_OWNER_P(port, vm) && PORT_RECURSIVE_P(port)) {
        /* We're in the recursive call, so we just recurse into write_walk
           or write_rec, according to the phase.   NB: The controls passed
           into the argument CTRL is ignored; the "root" control, passed
           to the toplevel write API, will be used.  */
        if (PORT_WALKER_P(port)) {
            /* Special treatment - if we're "display"-ing a string, we'll
               bypass walk path even if we're in the middle of write/ss.
               Using srfi-38 notation to show displayed strings doesn't
               make sense at all. */
            if (!((mode == SCM_WRITE_DISPLAY) && SCM_STRINGP(obj))) {
                write_walk(obj, port);
            }
        } else {
            ScmWriteContext ctx;
            write_context_init(&ctx, mode, 0, 0);
            write_rec(obj, port, &ctx);
        }

    } else {
        /* We're in the toplevel call.*/
        ScmWriteContext ctx;
        write_context_init(&ctx, mode, 0, 0);
        PORT_LOCK(port, vm);
        if (WRITER_NEED_2PASS(&ctx)) {
            ctx.controls = ctrl;
            PORT_SAFE_CALL(port, write_ss(obj, port, &ctx),
                           cleanup_port_write_state(port));
        } else {
            /* write-simple case.  CTRL is ignored. */
            PORT_SAFE_CALL(port, write_rec(obj, port, &ctx), /*no cleanup*/);
        }
        PORT_UNLOCK(port);
    }
}
Exemple #7
0
/*
 * Internal dhcptab record update routine, used to factor out the
 * common code between add_dt(), delete_dt(), and modify_dt().  If
 * `origp' is NULL, then act like add_dt(); if `newp' is NULL, then
 * act like delete_dt(); otherwise act like modify_dt().
 */
static int
update_dt(const dt_handle_t *dhp, const dt_rec_t *origp, dt_rec_t *newp)
{
	char		dtpath[MAXPATHLEN], newpath[MAXPATHLEN];
	int		retval = DSVC_SUCCESS;
	off_t		recoff, recnext;
	dt_rec_list_t	*reclist;
	FILE		*fp;
	int		newfd;
	uint_t		found;
	int		query;
	struct stat	st;

	if ((dhp->dh_oflags & DSVC_WRITE) == 0)
		return (DSVC_ACCESS);

	/*
	 * Open the container to update and a new container file which we
	 * will store the updated version of the container in.  When the
	 * update is done, rename the new file to be the real container.
	 */
	dt2path(dtpath, MAXPATHLEN, dhp->dh_location, "");
	fp = fopen(dtpath, "r");
	if (fp == NULL)
		return (syserr_to_dsvcerr(errno));

	dt2path(newpath, MAXPATHLEN, dhp->dh_location, ".new");
	(void) unlink(newpath);
	newfd = open(newpath, O_CREAT|O_EXCL|O_WRONLY, 0644);
	if (newfd == -1) {
		(void) fclose(fp);
		return (syserr_to_dsvcerr(errno));
	}

	DSVC_QINIT(query);
	DSVC_QEQ(query, DT_QKEY|DT_QTYPE);

	/*
	 * If we're adding a new record or changing a key for an existing
	 * record, bail if the record we want to add already exists.
	 */
	if (newp != NULL) {
		if (origp == NULL || origp->dt_type != newp->dt_type ||
		    strcmp(origp->dt_key, newp->dt_key) != 0) {
			retval = find_dt(fp, 0, query, 1, newp, NULL, &found);
			if (retval != DSVC_SUCCESS)
				goto out;
			if (found != 0) {
				retval = DSVC_EXISTS;
				goto out;
			}
		}
	}

	/*
	 * If we're deleting or modifying record, make sure the record
	 * still exists.  Note that we don't check signatures because this
	 * is a legacy format that has no signatures.
	 */
	if (origp != NULL) {
		retval = find_dt(fp, FIND_POSITION, query, 1, origp, &reclist,
		    &found);
		if (retval != DSVC_SUCCESS)
			goto out;
		if (found == 0) {
			retval = DSVC_NOENT;
			goto out;
		}

		/*
		 * Note the offset of the record we're modifying or deleting
		 * for use down below.
		 */
		recoff  = ((dt_recpos_t *)reclist->dtl_rec)->dtp_off;
		recnext = recoff + ((dt_recpos_t *)reclist->dtl_rec)->dtp_size;

		free_dtrec_list(reclist);
	} else {
		/*
		 * No record to modify or delete, so set `recoff' and
		 * `recnext' appropriately.
		 */
		recoff = 0;
		recnext = 0;
	}

	/*
	 * Make a new copy of the container.  If we're deleting or
	 * modifying a record, don't copy that record to the new container.
	 */
	if (fstat(fileno(fp), &st) == -1) {
		retval = DSVC_INTERNAL;
		goto out;
	}

	retval = copy_range(fileno(fp), 0, newfd, 0, recoff);
	if (retval != DSVC_SUCCESS)
		goto out;

	retval = copy_range(fileno(fp), recnext, newfd, recoff,
	    st.st_size - recnext);
	if (retval != DSVC_SUCCESS)
		goto out;

	/*
	 * If there's a new record, append it to the new container.
	 */
	if (newp != NULL) {
		retval = write_rec(newfd, newp, recoff + st.st_size - recnext);
		if (retval != DSVC_SUCCESS)
			goto out;
	}

	/*
	 * Note: we close these descriptors before the rename(2) (rather
	 * than just having the `out:' label clean them up) to save NFS
	 * some work (otherwise, NFS has to save `dtpath' to an alternate
	 * name since its vnode would still be active).
	 */
	(void) fclose(fp);
	(void) close(newfd);

	if (rename(newpath, dtpath) == -1)
		retval = syserr_to_dsvcerr(errno);

	return (retval);
out:
	(void) fclose(fp);
	(void) close(newfd);
	(void) unlink(newpath);
	return (retval);
}
Exemple #8
0
/*
 * Internal dhcp_network record update routine, used to factor out the
 * common code between add_dn(), delete_dn(), and modify_dn().  If
 * `origp' is NULL, then act like add_dn(); if `newp' is NULL, then
 * act like delete_dn(); otherwise act like modify_dn().
 */
static int
update_dn(const dn_handle_t *dhp, const dn_rec_t *origp, dn_rec_t *newp)
{
	char		dnpath[MAXPATHLEN], newpath[MAXPATHLEN];
	int		retval = DSVC_SUCCESS;
	off_t		recoff, recnext;
	dn_rec_list_t	*reclist;
	int		fd, newfd;
	uint_t		found;
	int		query;
	struct stat	st;


	if ((dhp->dh_oflags & DSVC_WRITE) == 0)
		return (DSVC_ACCESS);

	/*
	 * Open the container to update and a new container file which we
	 * will store the updated version of the container in.  When the
	 * update is done, rename the new file to be the real container.
	 */
	net2path(dnpath, MAXPATHLEN, dhp->dh_location, dhp->dh_net, "");
	fd = open(dnpath, O_RDONLY);
	if (fd == -1)
		return (syserr_to_dsvcerr(errno));

	net2path(newpath, MAXPATHLEN, dhp->dh_location, dhp->dh_net, ".new");
	newfd = open(newpath, O_CREAT|O_TRUNC|O_WRONLY, 0644);
	if (newfd == -1) {
		(void) close(fd);
		return (syserr_to_dsvcerr(errno));
	}

	DSVC_QINIT(query);
	DSVC_QEQ(query, DN_QCIP);

	/*
	 * If we're changing the key for this record, make sure the key
	 * we're changing to doesn't already exist.
	 */
	if (origp != NULL && newp != NULL) {
		if (origp->dn_cip.s_addr != newp->dn_cip.s_addr) {
			retval = find_dn(fd, 0, query, 1, newp, NULL, &found);
			if (retval != DSVC_SUCCESS)
				goto out;
			if (found != 0) {
				retval = DSVC_EXISTS;
				goto out;
			}
		}
	}

	/*
	 * If we're adding a new record, make sure the record doesn't
	 * already exist.
	 */
	if (newp != NULL && origp == NULL) {
		retval = find_dn(fd, 0, query, 1, newp, NULL, &found);
		if (retval != DSVC_SUCCESS)
			goto out;
		if (found != 0) {
			retval = DSVC_EXISTS;
			goto out;
		}
	}

	/*
	 * If we're deleting or modifying record, make sure the record
	 * still exists and that our copy isn't stale.  Note that we don't
	 * check signatures if we're deleting the record and origp->dn_sig
	 * is zero, so that records that weren't looked up can be deleted.
	 */
	if (origp != NULL) {
		retval = find_dn(fd, FIND_POSITION, query, 1, origp, &reclist,
		    &found);
		if (retval != DSVC_SUCCESS)
			goto out;
		if (found == 0) {
			retval = DSVC_NOENT;
			goto out;
		}

		if (reclist->dnl_rec->dn_sig != origp->dn_sig) {
			if (newp != NULL || origp->dn_sig != 0) {
				free_dnrec_list(reclist);
				retval = DSVC_COLLISION;
				goto out;
			}
		}

		/*
		 * Note the offset of the record we're modifying or deleting
		 * for use down below.
		 */
		recoff  = ((dn_recpos_t *)reclist->dnl_rec)->dnp_off;
		recnext = recoff + ((dn_recpos_t *)reclist->dnl_rec)->dnp_size;

		free_dnrec_list(reclist);
	} else {
		/*
		 * No record to modify or delete, so set `recoff' and
		 * `recnext' appropriately.
		 */
		recoff = 0;
		recnext = 0;
	}

	/*
	 * Make a new copy of the container.  If we're deleting or
	 * modifying a record, don't copy that record to the new container.
	 */
	if (fstat(fd, &st) == -1) {
		retval = DSVC_INTERNAL;
		goto out;
	}

	retval = copy_range(fd, 0, newfd, 0, recoff);
	if (retval != DSVC_SUCCESS)
		goto out;

	retval = copy_range(fd, recnext, newfd, recoff, st.st_size - recnext);
	if (retval != DSVC_SUCCESS)
		goto out;

	/*
	 * If there's a new/modified record, append it to the new container.
	 */
	if (newp != NULL) {
		if (origp == NULL)
			newp->dn_sig = gensig();
		else
			newp->dn_sig = origp->dn_sig + 1;

		retval = write_rec(newfd, newp, recoff + st.st_size - recnext);
		if (retval != DSVC_SUCCESS)
			goto out;
	}

	/*
	 * Note: we close these descriptors before the rename(2) (rather
	 * than just having the `out:' label clean them up) to save NFS
	 * some work (otherwise, NFS has to save `dnpath' to an alternate
	 * name since its vnode would still be active).
	 */
	(void) close(fd);
	(void) close(newfd);

	if (rename(newpath, dnpath) == -1)
		retval = syserr_to_dsvcerr(errno);

	return (retval);
out:
	(void) close(fd);
	(void) close(newfd);
	(void) unlink(newpath);
	return (retval);
}
Exemple #9
0
/* Trick: The hashtable contains positive integer after the walk pass.
   If we emit a reference tag N, we replace the entry's value to -N,
   so that we can distinguish whether we've already emitted the object
   or not. */
static void write_rec(ScmObj obj, ScmPort *port, ScmWriteContext *ctx)
{
    char numbuf[50];  /* enough to contain long number */
    ScmObj stack = SCM_NIL;
    ScmWriteState *st = port->writeState;
    ScmHashTable *ht = (st? st->sharedTable : NULL);
    const ScmWriteControls *wp = Scm_GetWriteControls(ctx, st);
    int stack_depth = 0;        /* only used when !ht */

#define PUSH(elt)                                       \
    do {                                                \
        stack = Scm_Cons(elt, stack);                   \
        if (!ht && ++stack_depth > STACK_LIMIT) {       \
            Scm_Error("write recursed too deeply; "     \
                      "maybe a circular structure?");   \
        }                                               \
    } while (0)
#define POP()                                   \
    do {                                        \
        stack = SCM_CDR(stack);                 \
        if (!ht) stack_depth--;                 \
    } while (0)
#define CHECK_LEVEL()                                                   \
    do {                                                                \
        if (st) {                                                       \
            if (wp->printLevel >= 0 && st->currentLevel >= wp->printLevel) { \
                Scm_PutcUnsafe('#', port);                              \
                goto next;                                              \
            } else {                                                    \
                if (st) st->currentLevel++;                             \
            }                                                           \
        }                                                               \
    } while (0)
    

    for (;;) {
    write1:
        if (ctx->flags & WRITE_LIMITED) {
            if (port->src.ostr.length >= ctx->limit) return;
        }

        /* number may be heap allocated, but we don't use srfi-38 notation. */
        if (!SCM_PTRP(obj) || SCM_NUMBERP(obj)) {
            if (SCM_FALSEP(Scm__WritePrimitive(obj, port, ctx))) {
                Scm_Panic("write: got a bogus object: %08x", SCM_WORD(obj));
            }
            goto next;
        }
        if ((SCM_STRINGP(obj) && SCM_STRING_SIZE(obj) == 0)
            || (SCM_VECTORP(obj) && SCM_VECTOR_SIZE(obj) == 0)) {
            /* we don't put a reference tag for these */
            write_general(obj, port, ctx);
            goto next;
        }

        /* obj is heap allocated and we may use label notation. */
        if (ht) {
            ScmObj e = Scm_HashTableRef(ht, obj, SCM_MAKE_INT(1));
            long k = SCM_INT_VALUE(e);
            if (k <= 0) {
                /* This object is already printed. */
                snprintf(numbuf, 50, "#%ld#", -k);
                Scm_PutzUnsafe(numbuf, -1, port);
                goto next;
            } else if (k > 1) {
                /* This object will be seen again. Put a reference tag. */
                ScmWriteState *s = port->writeState;
                snprintf(numbuf, 50, "#%d=", s->sharedCounter);
                Scm_HashTableSet(ht, obj, SCM_MAKE_INT(-s->sharedCounter), 0);
                s->sharedCounter++;
                Scm_PutzUnsafe(numbuf, -1, port);
            }
        }

        /* Writes aggregates */
        if (SCM_PAIRP(obj)) {

            CHECK_LEVEL();

            /* special case for quote etc.
               NB: we need to check if we've seen SCM_CDR(obj), otherwise we'll
               get infinite recursion for the case like (cdr '#1='#1#). */
            if (SCM_PAIRP(SCM_CDR(obj)) && SCM_NULLP(SCM_CDDR(obj))
                && (!ht
                    || SCM_FALSEP(Scm_HashTableRef(ht, SCM_CDR(obj), SCM_FALSE)))){
                const char *prefix = NULL;
                if (SCM_CAR(obj) == SCM_SYM_QUOTE) {
                    prefix = "'";
                } else if (SCM_CAR(obj) == SCM_SYM_QUASIQUOTE) {
                    prefix = "`";
                } else if (SCM_CAR(obj) == SCM_SYM_UNQUOTE) {
                    prefix = ",";
                } else if (SCM_CAR(obj) == SCM_SYM_UNQUOTE_SPLICING) {
                    prefix = ",@";
                }
                if (prefix) {
                    Scm_PutzUnsafe(prefix, -1, port);
                    obj = SCM_CADR(obj);
                    goto write1;
                }
            }

            if (wp->printLength == 0) {
                /* in this case we don't print the elements at all, so we need
                   to treat this specially. */
                Scm_PutzUnsafe("(...)", -1, port);
                if (st) st->currentLevel--;
                goto next;
            }

            /* normal case */
            Scm_PutcUnsafe('(', port);
            PUSH(Scm_Cons(SCM_TRUE, Scm_Cons(SCM_MAKE_INT(1), SCM_CDR(obj))));
            obj = SCM_CAR(obj);
            goto write1;
        } else if (SCM_VECTORP(obj)) {

            CHECK_LEVEL();

            if (wp->printLength == 0) {
                /* in this case we don't print the elements at all, so we need
                   to treat this specially. */
                Scm_PutzUnsafe("#(...)", -1, port);
                if (st) st->currentLevel--;
                goto next;
            }
            Scm_PutzUnsafe("#(", -1, port);
            PUSH(Scm_Cons(SCM_MAKE_INT(1), obj));
            obj = SCM_VECTOR_ELEMENT(obj, 0);
            goto write1;
        } else if (Scm_ClassOf(obj)->flags & SCM_CLASS_AGGREGATE) {
            CHECK_LEVEL();
            write_general(obj, port, ctx);
            if (st) st->currentLevel--;
            goto next;
        } else {
            write_general(obj, port, ctx);
            goto next;
        }

    next:
        while (SCM_PAIRP(stack)) {
            ScmObj top = SCM_CAR(stack);
            SCM_ASSERT(SCM_PAIRP(top));
            if (SCM_INTP(SCM_CAR(top))) {
                /* we're processing a vector */
                ScmObj v = SCM_CDR(top);
                int i = SCM_INT_VALUE(SCM_CAR(top));
                int len = SCM_VECTOR_SIZE(v);

                if (i == len) { /* we've done this vector */
                    Scm_PutcUnsafe(')', port);
                    POP();
                } else if (wp->printLength >= 0 && wp->printLength <= i) {
                    Scm_PutzUnsafe(" ...)", -1, port);
                    POP();
                } else {
                    Scm_PutcUnsafe(' ', port);
                    obj = SCM_VECTOR_ELEMENT(v, i);
                    SCM_SET_CAR(top, SCM_MAKE_INT(i+1));
                    goto write1;
                }
            } else {
                /* we're processing a list */
                SCM_ASSERT(SCM_PAIRP(SCM_CDR(top)));
                long count = SCM_INT_VALUE(SCM_CADR(top));
                ScmObj v = SCM_CDDR(top);
                if (SCM_NULLP(v)) { /* we've done with this list */
                    Scm_PutcUnsafe(')', port);
                    POP();
                } else if (!SCM_PAIRP(v)) {
                    /* Improper list.  We treat aggregate types specially,
                       since such object at this position shouldn't increment
                       "level" - its content is regarded as the same level of
                       the current list.
                     */
                    Scm_PutzUnsafe(" . ", -1, port);
                    if (Scm_ClassOf(v)->flags & SCM_CLASS_AGGREGATE) {
                        if (st) st->currentLevel--;
                        write_rec(v, port, ctx);
                        if (st) st->currentLevel++;
                        Scm_PutcUnsafe(')', port);
                        POP();
                    } else {
                        obj = v;
                        SCM_SET_CAR(SCM_CDR(top), SCM_MAKE_INT(count+1));
                        SCM_SET_CDR(SCM_CDR(top), SCM_NIL);
                        goto write1;
                    }
                } else if (wp->printLength >= 0 && wp->printLength <= count) {
                    /* print-length limit reached */
                    Scm_PutzUnsafe(" ...)", -1, port);
                    POP();
                } else if (ht && !SCM_EQ(Scm_HashTableRef(ht, v, SCM_MAKE_INT(1)), SCM_MAKE_INT(1)))  {
                    /* cdr part is shared */
                    Scm_PutzUnsafe(" . ", -1, port);
                    obj = v;
                    SCM_SET_CAR(SCM_CDR(top), SCM_MAKE_INT(count+1));
                    SCM_SET_CDR(SCM_CDR(top), SCM_NIL);
                    goto write1;
                } else {
                    Scm_PutcUnsafe(' ', port);
                    obj = SCM_CAR(v);
                    SCM_SET_CAR(SCM_CDR(top), SCM_MAKE_INT(count+1));
                    SCM_SET_CDR(SCM_CDR(top), SCM_CDR(v));
                    goto write1;
                }
            }
            if (st) st->currentLevel--;
        }
        break;
    }

#undef PUSH
#undef POP
#undef CHECK_DEPTH
}