1 /* ProcFS - buf.c - output buffer management for read calls */ 2 3 #include "inc.h" 4 #include <stdarg.h> 5 6 static char *buf; 7 static size_t left, used; 8 static off_t skip; 9 10 /* 11 * Initialize the buffer for fresh use. The output is to be stored into 'ptr' 12 * which is BUF_SIZE bytes in size, since that is the size we requested. Due 13 * to the way vsnprintf works, we cannot use the last byte of this buffer. The 14 * first 'start' bytes of the produced output are to be skipped. After that, a 15 * total of 'len' bytes are requested. 16 */ 17 void 18 buf_init(char * ptr, size_t len, off_t start) 19 { 20 21 buf = ptr; 22 skip = start; 23 left = MIN(len, BUF_SIZE - 1); 24 used = 0; 25 } 26 27 /* 28 * Add formatted text to the end of the buffer. 29 */ 30 void 31 buf_printf(char * fmt, ...) 32 { 33 va_list args; 34 ssize_t len, max; 35 36 if (left == 0) 37 return; 38 39 /* 40 * There is no way to estimate how much space the result will take, so 41 * we need to produce the string even when skipping part of the start. 42 * The null terminating character is not part of the result, so room 43 * must be given for it to be stored after completely filling up the 44 * requested part of the buffer. 45 */ 46 max = MIN(skip + left + 1, BUF_SIZE); 47 48 va_start(args, fmt); 49 len = vsnprintf(&buf[used], max, fmt, args); 50 va_end(args); 51 52 /* 53 * The snprintf family returns the number of bytes that would be stored 54 * if the buffer were large enough, excluding the null terminator. 55 */ 56 if (len >= BUF_SIZE) 57 len = BUF_SIZE - 1; 58 59 if (skip > 0) { 60 assert(used == 0); 61 62 if (skip >= len) { 63 skip -= len; 64 65 return; 66 } 67 68 memmove(buf, &buf[skip], len - skip); 69 70 len -= skip; 71 skip = 0; 72 } 73 74 assert(skip == 0); 75 assert(len >= 0); 76 assert((ssize_t) left >= 0); 77 78 if (len > (ssize_t)left) 79 len = left; 80 81 used += len; 82 left -= len; 83 } 84 85 /* 86 * Add arbitrary data to the end of the buffer. 87 */ 88 void 89 buf_append(char * data, size_t len) 90 { 91 92 if (left == 0) 93 return; 94 95 if (skip > 0) { 96 if (skip >= (ssize_t)len) { 97 skip -= len; 98 99 return; 100 } 101 102 data += skip; 103 len -= skip; 104 skip = 0; 105 } 106 107 if (len > left) 108 len = left; 109 110 memcpy(&buf[used], data, len); 111 112 used += len; 113 left -= len; 114 } 115 116 /* 117 * Return the resulting number of bytes produced, not counting the trailing 118 * null character in the buffer. 119 */ 120 ssize_t 121 buf_result(void) 122 { 123 124 return used; 125 } 126