Exemplo n.º 1
0
/* generic routine to handle byte-stream */
static inline int getbytes(char *buf, int len, ScmPort *iport)
{
    int nread = 0, r;
    ENSURE_IPORT(iport);
    while (nread < len) {
        r = Scm_Getz(buf, len-nread, iport);
        if (r <= 0) return EOF;
        nread += r;
        buf += r;
    }
    return nread;
}
Exemplo n.º 2
0
static int getz_scratch_unsafe(char *buf, int buflen, ScmPort *p)
#endif
{
    if (p->scrcnt >= (u_int)buflen) {
        memcpy(buf, p->scratch, buflen);
        p->scrcnt -= buflen;
        shift_scratch(p, buflen);
        return buflen;
    } else {
        memcpy(buf, p->scratch, p->scrcnt);
        int i = p->scrcnt;
        p->scrcnt = 0;
        int n = 0;
        SAFE_CALL(p, n = Scm_Getz(buf+i, buflen-i, p));
        return i + n;
    }
}
Exemplo n.º 3
0
ScmObj Scm_MakeInputConversionPort(ScmPort *fromPort,
                                   const char *fromCode,
                                   const char *toCode,
                                   ScmObj handler,
                                   int bufsiz,
                                   int ownerp)
{
    char *inbuf = NULL;
    int preread = 0;

    if (!SCM_IPORTP(fromPort))
        Scm_Error("input port required, but got %S", fromPort);

    if (bufsiz <= 0) bufsiz = DEFAULT_CONVERSION_BUFFER_SIZE;
    if (bufsiz <= MINIMUM_CONVERSION_BUFFER_SIZE) {
        bufsiz = MINIMUM_CONVERSION_BUFFER_SIZE;
    }
    conv_guess *guess = findGuessingProc(fromCode);
    if (guess) {
        const char *guessed;

        inbuf = SCM_NEW_ATOMIC2(char *, bufsiz);
        preread = Scm_Getz(inbuf, bufsiz, fromPort);
        if (preread <= 0) {
            /* Input buffer is already empty or unreadable.
               Determining character code is not necessary.
               We just return a dummy empty port. */
            return Scm_MakeInputStringPort(SCM_STRING(SCM_MAKE_STR("")), FALSE);
        }
        guessed = guess->proc(inbuf, preread, guess->data);
        if (guessed == NULL)
            Scm_Error("%s: failed to guess input encoding", fromCode);
        fromCode = guessed;
    }

    ScmConvInfo *cinfo = jconv_open(toCode, fromCode);
    if (cinfo == NULL) {
        Scm_Error("conversion from code %s to code %s is not supported",
                  fromCode, toCode);
    }
    cinfo->remote = fromPort;
    cinfo->ownerp = ownerp;
    cinfo->bufsiz = bufsiz;
    cinfo->remoteClosed = FALSE;
    if (preread > 0) {
        cinfo->buf = inbuf;
        cinfo->ptr = inbuf + preread;
    } else {
        cinfo->buf = SCM_NEW_ATOMIC2(char *, cinfo->bufsiz);
        cinfo->ptr = cinfo->buf;
    }

    ScmPortBuffer bufrec;
    memset(&bufrec, 0, sizeof(bufrec));
    bufrec.size = cinfo->bufsiz;
    bufrec.buffer = SCM_NEW_ATOMIC2(char *, cinfo->bufsiz);
    bufrec.mode = SCM_PORT_BUFFER_FULL;
    bufrec.filler = conv_input_filler;
    bufrec.flusher = NULL;
    bufrec.closer = conv_input_closer;
    bufrec.ready = conv_ready;
    bufrec.filenum = conv_fileno;
    bufrec.data = (void*)cinfo;

    ScmObj name = conv_name(SCM_PORT_INPUT, fromPort, fromCode, toCode);
    return Scm_MakeBufferedPort(SCM_CLASS_PORT, name, SCM_PORT_INPUT, TRUE, &bufrec);
}
Exemplo n.º 4
0
static int conv_input_filler(ScmPort *port, int mincnt)
{
    ScmConvInfo *info = (ScmConvInfo*)port->src.buf.data;
    const char *inbuf = info->buf;
    char *outbuf = port->src.buf.end;

    if (info->remoteClosed) return 0;

    /* Fill the input buffer.  There may be some remaining bytes in the
       inbuf from the last conversion (insize), so we try to fill the
       rest. */
    size_t insize = info->ptr - info->buf;
    int nread = Scm_Getz(info->ptr, info->bufsiz - (int)insize, info->remote);
    if (nread <= 0) {
        /* input reached EOF.  finish the output state */
        if (insize == 0) {
            size_t outroom = SCM_PORT_BUFFER_ROOM(port);
            size_t result = jconv_reset(info, outbuf, outroom);
            if (result == OUTPUT_NOT_ENOUGH) {
                /* The port buffer doesn't have enough space to contain the
                   finishing sequence.  Its unusual, for the port buffer
                   must be almost empty at this time, and the finishing
                   sequence is usually just a few bytes.
                   We signal an error. */
                Scm_Error("couldn't flush the ending escape sequence in the character encoding conversion port (%s -> %s).  possibly an implementation error",
                          info->fromCode, info->toCode);
                }
            if (info->ownerp) {
                Scm_ClosePort(info->remote);
                info->remoteClosed = TRUE;
            }
#ifdef JCONV_DEBUG
            fprintf(stderr, "<= r=%d (reset), out(%p)%d\n",
                    result, outbuf, outroom);
#endif
            return (int)result;
        }
    } else {
        insize += nread;
    }

    /* Conversion. */
    size_t inroom = insize;
    size_t outroom = SCM_PORT_BUFFER_ROOM(port);

#ifdef JCONV_DEBUG
    fprintf(stderr, "=> in(%p)%d out(%p)%d\n", inbuf, insize, outbuf, outroom);
#endif
    size_t result = jconv(info, &inbuf, &inroom, &outbuf, &outroom);
#ifdef JCONV_DEBUG
    fprintf(stderr, "<= r=%d, in(%p)%d out(%p)%d\n",
            result, inbuf, inroom, outbuf, outroom);
#endif
    /* we've got an error. */
    if (result == INPUT_NOT_ENOUGH || result == OUTPUT_NOT_ENOUGH) {
        /* Conversion stopped due to an incomplete character at the
           end of the input buffer, or the output buffer is full.
           We shift the unconverted bytes to the beginning of input
           buffer. */
        memmove(info->buf, info->buf+insize-inroom, inroom);
        info->ptr = info->buf + inroom;
        return info->bufsiz - (int)outroom;
    } else if (result == ILLEGAL_SEQUENCE) {
        /* it's likely that the input contains invalid sequence. */
        int cnt = inroom >= 6 ? 6 : (int)inroom;
        ScmObj s = Scm_MakeString(info->buf+insize-inroom, cnt, cnt,
                                  SCM_STRING_COPYING|SCM_STRING_INCOMPLETE);
        Scm_Error("invalid character sequence in the input stream: %S ...", s);
    }

    /* Conversion is done completely. */
    /* NB: There are cases that some bytes are left in the input buffer
       even iconv returns positive value.  We need to shift those bytes. */
    if (inroom > 0) {
        memmove(info->buf, info->buf+insize-inroom, inroom);
        info->ptr = info->buf + inroom;
        return info->bufsiz - (int)outroom;
    } else {
        info->ptr = info->buf;
        return info->bufsiz - (int)outroom;
    }
}