static void vport_print(ScmObj obj, ScmPort *port, ScmWriteContext *ctx) { Scm_Printf(port, "#<%A%s %A %p>", Scm__InternalClassName(Scm_ClassOf(obj)), SCM_PORT_CLOSED_P(obj)? "(closed)" : "", Scm_PortName(SCM_PORT(obj)), obj); }
ScmObj Scm_PortSeekUnsafe(ScmPort *p, ScmObj off, int whence) #endif { VMDECL; SHORTCUT(p, return Scm_PortSeekUnsafe(p, off, whence)); if (SCM_PORT_CLOSED_P(p)) { Scm_PortError(p, SCM_PORT_ERROR_CLOSED, "attempt to seek on closed port: %S", p); } off_t r = (off_t)-1; off_t o = Scm_IntegerToOffset(off); int is_telling = (whence == SEEK_CUR && o == 0); LOCK(p); off_t pending = port_pending_bytes(p); if (!is_telling) { /* Unless we're telling, we discard pending bytes. */ p->scrcnt = 0; p->ungotten = SCM_CHAR_INVALID; /* ... and adjust offset, when it's relative. */ if (whence == SEEK_CUR) o -= pending; } switch (SCM_PORT_TYPE(p)) { case SCM_PORT_FILE: /* NB: we might be able to skip calling seeker if we keep the # of bytes read or write so far, but such count may be off when the port has been experienced an error condition. */ /* NB: the following doesn't work if we have bidirectional port. In such case we need to keep whether the last call of buffer handling routine was input or output. */ if (!p->src.buf.seeker) break; if (is_telling) { SAFE_CALL(p, r = p->src.buf.seeker(p, 0, SEEK_CUR)); if (SCM_PORT_DIR(p)&SCM_PORT_INPUT) { r -= (off_t)(p->src.buf.end - p->src.buf.current); } else { r += (off_t)(p->src.buf.current - p->src.buf.buffer); } } else { /* NB: possible optimization: the specified position is within the current buffer, we can avoid calling seeker. */ if (SCM_PORT_DIR(p)&SCM_PORT_INPUT) { char *c = p->src.buf.current; /* save current ptr */ if (whence == SEEK_CUR) { o -= (off_t)(p->src.buf.end - c); } p->src.buf.current = p->src.buf.end; /* invalidate buffer */ SAFE_CALL(p, r = p->src.buf.seeker(p, o, whence)); if (r == (off_t)-1) { /* This may happend if seeker somehow gave up */ p->src.buf.current = c; } } else { SAFE_CALL(p, bufport_flush(p, 0, TRUE)); SAFE_CALL(p, r = p->src.buf.seeker(p, o, whence)); } } break; case SCM_PORT_ISTR: r = SEEK_ISTR(p, o, whence, is_telling); break; case SCM_PORT_OSTR: if (is_telling) { r = (off_t)Scm_DStringSize(&(p->src.ostr)); } else { /* Not supported yet */ r = (off_t)-1; } break; case SCM_PORT_PROC: if (p->src.vt.Seek) { SAFE_CALL(p, r = p->src.vt.Seek(p, o, whence)); } break; } UNLOCK(p); if (r == (off_t)-1) return SCM_FALSE; if (is_telling) r -= pending; return Scm_OffsetToInteger(r); }