The io_read() function

static int
io_read (resmgr_context_t *ctp, io_read_t *msg, RESMGR_OCB_T *ocb)
{
    int     nbytes;
    int     nleft;
    int     sts;
    char    string [MAX_DIGITS + 1];

    // 1) we don't do any xtypes here...
    if ((msg -> i.xtype & _IO_XTYPE_MASK) != _IO_XTYPE_NONE) {
        return (ENOSYS);
    }

    // standard helper
    sts = iofunc_read_verify (ctp, msg, &ocb -> base, NULL);
    if (sts != EOK) {
        return (sts);
    }

    // 2) generate and compress an image
    if (!ocb -> output) {
        unsigned char *input;   // limited scope

        input = calloc (optx, opty);
        if (input == NULL) {
            return (ENOMEM);
        }
        ocb -> output = calloc (optx, opty);
        if (ocb -> output == NULL) {
            free (input);
            return (ENOMEM);
        }

        sprintf (string, "%0*d", optd, ocb -> base.attr -> count++);
        render_7segment (string, input, optx, opty);
        ocb -> size = encode_image (input, optx, opty, ocb -> output);
        free (input);
    }

    // 3) figure out how many bytes are left
    nleft = ocb -> size - ocb -> base.offset;

    // 4) and how many we can return to the client
    nbytes = min (nleft, msg -> i.nbytes);

    if (nbytes) {
        // 5) return it to the client
        MsgReply (ctp -> rcvid, nbytes, 
                 ocb -> output + ocb -> base.offset, nbytes);

        // 6) update flags and offset
        ocb -> base.attr -> base.flags |= 
            IOFUNC_ATTR_ATIME | IOFUNC_ATTR_DIRTY_TIME;
        ocb -> base.offset += nbytes;
    } else {
        // 7) nothing to return, indicate End Of File
        MsgReply (ctp -> rcvid, EOK, NULL, 0);
    }

    // 8) already done the reply ourselves
    return (_RESMGR_NOREPLY);
}

Let's look at this code step-by-step:

  1. If there are any XTYPE directives, we return ENOSYS because we don't handle XTYPEs. XTYPEs are discussed in the Getting Started with QNX Neutrino book in the “Resource Managers” chapter.
  2. If we currently don't have a compressed image to work from (i.e., this is the first time that we've been called for this particular open() request), we allocate the temporary input (raw buffer) and OCB's output (compressed buffer) data areas, call render_7segment() to draw the picture into the raw buffer, and then encode_image() to compress it. Notice that encode_image() returns the number of bytes that it generated and we store that into the OCB's size member. Then we free the temporary input buffer area.
  3. We calculate the number of bytes that are left, which is simply the difference between the number of bytes that we have in the compressed image buffer and our current offset within that buffer. Note that we use the OCB's size member rather than the attributes structure's nbytes member (see note after step 8 below).
  4. We then calculate the number of bytes we can return to the client. This could be smaller than the number of bytes that we have left because the client may request fewer bytes than what we could give them.
  5. If we have any bytes to return to the client (i.e., we haven't reached EOF), we perform the MsgReply() ourselves, giving the client nbytes' worth of data, starting at the output area plus the current offset.
  6. As per POSIX, we update our ATIME flag, because we just accessed the device and returned more than zero bytes. We also move our offset to reflect the number of bytes we just returned to the client, so that we have the correct position within the file for the next time.
  7. If, on the other hand, we were not returning any bytes to the client (i.e., we've reached EOF), we indicate this by doing a MsgReply() with zero bytes.
  8. By returning _RESMGR_NOREPLY we're indicating to the QNX Neutrino resource manager framework that we've already called MsgReply() and that it should not.
Note: Notice that we used the OCB's size member rather than the attributes structure's nbytes member. This is because the image that we generated has a different size (shorter) than the size stored in the attributes structure's nbytes member. Since we want to return the correct number of bytes to the client, we use the smaller size number.