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