/* ProcFS - buf.c - output buffer management for read calls */ #include "inc.h" #include static char *buf; static size_t left, used; static off_t skip; /* * Initialize the buffer for fresh use. The output is to be stored into 'ptr' * which is BUF_SIZE bytes in size, since that is the size we requested. Due * to the way vsnprintf works, we cannot use the last byte of this buffer. The * first 'start' bytes of the produced output are to be skipped. After that, a * total of 'len' bytes are requested. */ void buf_init(char * ptr, size_t len, off_t start) { buf = ptr; skip = start; left = MIN(len, BUF_SIZE - 1); used = 0; } /* * Add formatted text to the end of the buffer. */ void buf_printf(char * fmt, ...) { va_list args; ssize_t len, max; if (left == 0) return; /* * There is no way to estimate how much space the result will take, so * we need to produce the string even when skipping part of the start. * The null terminating character is not part of the result, so room * must be given for it to be stored after completely filling up the * requested part of the buffer. */ max = MIN(skip + left + 1, BUF_SIZE); va_start(args, fmt); len = vsnprintf(&buf[used], max, fmt, args); va_end(args); /* * The snprintf family returns the number of bytes that would be stored * if the buffer were large enough, excluding the null terminator. */ if (len >= BUF_SIZE) len = BUF_SIZE - 1; if (skip > 0) { assert(used == 0); if (skip >= len) { skip -= len; return; } memmove(buf, &buf[skip], len - skip); len -= skip; skip = 0; } assert(skip == 0); assert(len >= 0); assert((ssize_t) left >= 0); if (len > (ssize_t)left) len = left; used += len; left -= len; } /* * Add arbitrary data to the end of the buffer. */ void buf_append(char * data, size_t len) { if (left == 0) return; if (skip > 0) { if (skip >= (ssize_t)len) { skip -= len; return; } data += skip; len -= skip; skip = 0; } if (len > left) len = left; memcpy(&buf[used], data, len); used += len; left -= len; } /* * Return the resulting number of bytes produced, not counting the trailing * null character in the buffer. */ ssize_t buf_result(void) { return used; }