1 /* ProcFS - buf.c - by Alen Stojanov and David van Moolenbroek */ 2 3 #include "inc.h" 4 #include <stdarg.h> 5 6 #define BUF_SIZE 4096 7 8 static char buf[BUF_SIZE + 1]; 9 static size_t off, left, used; 10 static off_t skip; 11 12 /*===========================================================================* 13 * buf_init * 14 *===========================================================================*/ 15 void buf_init(off_t start, size_t len) 16 { 17 /* Initialize the buffer for fresh use. The first 'start' bytes of the 18 * produced output are to be skipped. After that, up to a total of 19 * 'len' bytes are requested. 20 */ 21 22 skip = start; 23 left = MIN(len, BUF_SIZE); 24 off = 0; 25 used = 0; 26 } 27 28 /*===========================================================================* 29 * buf_printf * 30 *===========================================================================*/ 31 void buf_printf(char *fmt, ...) 32 { 33 /* Add formatted text to the end of the buffer. 34 */ 35 va_list args; 36 ssize_t len, max; 37 38 if (left == 0) 39 return; 40 41 /* There is no way to estimate how much space the result will take, so 42 * we need to produce the string even when skipping part of the start. 43 * If part of the result is to be skipped, do not memcpy; instead, save 44 * the offset of where the result starts within the buffer. 45 * 46 * The null terminating character is not part of the result, so room 47 * must be given for it to be stored after completely filling up the 48 * requested part of the buffer. 49 */ 50 max = MIN(skip + left, BUF_SIZE); 51 52 va_start(args, fmt); 53 len = vsnprintf(&buf[off + used], max + 1, fmt, args); 54 va_end(args); 55 56 if (skip > 0) { 57 assert(off == 0); 58 assert(used == 0); 59 60 if (skip >= len) { 61 skip -= len; 62 63 return; 64 } 65 66 off = skip; 67 if (left > BUF_SIZE - off) 68 left = BUF_SIZE - off; 69 len -= off; 70 skip = 0; 71 } 72 73 assert(skip == 0); 74 assert(len >= 0); 75 assert((long) left >= 0); 76 77 if (len > (ssize_t) left) 78 len = left; 79 80 used += len; 81 left -= len; 82 } 83 84 /*===========================================================================* 85 * buf_append * 86 *===========================================================================*/ 87 void buf_append(char *data, size_t len) 88 { 89 /* Add arbitrary data to the end of the buffer. 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[off + used], data, len); 111 112 used += len; 113 left -= len; 114 } 115 116 /*===========================================================================* 117 * buf_get * 118 *===========================================================================*/ 119 size_t buf_get(char **ptr) 120 { 121 /* Return the buffer's starting address and the length of the used 122 * part, not counting the trailing null character for the latter. 123 */ 124 125 *ptr = &buf[off]; 126 127 return used; 128 } 129