diff --git a/src/lib/in.c b/src/lib/in.c index 6443e0e34..7f729377c 100644 --- a/src/lib/in.c +++ b/src/lib/in.c @@ -28,8 +28,10 @@ typedef struct inputctx { #endif unsigned char ibuf[BUFSIZ]; // we dump raw reads into this ringbuffer, and // process them all post-read - int ibufvalid, ibufwrite; // our bookkeeping for ibuf; - // we mustn't read() if ibufvalid == sizeof(ibuf) + int ibufvalid; // we mustn't read() if ibufvalid == sizeof(ibuf) + int ibufwrite; // we write here next + int ibufread; // first valid byte here (if any are valid) + cursorloc* csrs; // cursor reports are dumped here ncinput* inputs; // processed input is dumped here int csize, isize; // total number of slots in csrs/inputs @@ -51,11 +53,14 @@ create_inputctx(tinfo* ti){ i->isize = BUFSIZ; if( (i->inputs = malloc(sizeof(*i->inputs) * i->isize)) ){ // FIXME set up infd/handle + i->termfd = -1; + i->stdinfd = -1; i->ti = ti; i->cvalid = i->ivalid = 0; i->cwrite = i->iwrite = 0; i->cread = i->iread = 0; i->ibufvalid = i->ibufwrite = 0; + i->ibufread = 0; return i; } free(i->csrs); @@ -75,14 +80,81 @@ free_inputctx(inputctx* i){ } } +// how many bytes can a single read fill in the ibuf? this might be fewer than +// the actual number of free bytes, due to reading on the right or left side. +static inline size_t +space_for_read(inputctx* ictx){ + // if we are valid everywhere, there's no space to read into. + if(ictx->ibufvalid == sizeof(ictx->ibuf)){ + return 0; + } + // if we are valid nowhere, we can read into the head of the buffer + if(ictx->ibufvalid == 0){ + ictx->ibufread = 0; + ictx->ibufwrite = 0; + return sizeof(ictx->ibuf); + } + // otherwise, we can read either from ibufwrite to the end of the buffer, + // or from ibufwrite to ibufread. + if(ictx->ibufwrite < ictx->ibufread){ + return ictx->ibufread - ictx->ibufwrite; + } + return sizeof(ictx->ibuf) - ictx->ibufwrite; +} + +// populate the ibuf with any new data from the specified file descriptor. +static void +read_input_nblock(inputctx* ictx, int fd){ + if(fd >= 0){ + size_t space = space_for_read(ictx); + if(space == 0){ + return; + } + ssize_t r = read(fd, ictx->ibuf + ictx->ibufwrite, space); + if(r >= 0){ + ictx->ibufwrite += r; + if(ictx->ibufwrite == sizeof(ictx->ibuf)){ + ictx->ibufwrite = 0; + } + ictx->ibufvalid += r; + space -= r; + loginfo("read %lldB from %d (%lluB left)\n", (long long)r, fd, (unsigned long long)space); + if(space == 0){ + return; + } + // might have been falsely limited by space (only reading on the right). + // this will recurse one time at most. + if(ictx->ibufwrite == 0){ + read_input_nblock(ictx, fd); + } + } + } +} + +// walk the matching automaton from wherever we were. +static void +process_ibuf(inputctx* ictx){ + // FIXME +} + +// populate the ibuf with any new data, up through its size, but do not block. +// don't loop around this call without some kind of readiness notification. +static void +read_inputs_nblock(inputctx* ictx){ + // first we read from the terminal, if that's a distinct source. + read_input_nblock(ictx, ictx->termfd); + // now read bulk, possibly with term escapes intermingled within (if there + // was not a distinct terminal source). + read_input_nblock(ictx, ictx->stdinfd); +} + static void* input_thread(void* vmarshall){ inputctx* ictx = vmarshall; for(;;){ - if(ictx->ibufvalid == sizeof(ictx->ibuf)){ - // we can't read any more. need clients to clear their buffers. - // sleep on condvar FIXME - } + read_inputs_nblock(ictx); + // process anything we've read + process_ibuf(ictx); } return NULL; }