1 /*- 2 * Copyright (c) 2000 Poul-Henning Kamp and Dag-Erling Co�dan Sm�rgrav 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/kernel.h> 33 #include <sys/malloc.h> 34 #include <sys/sbuf.h> 35 #include <sys/systm.h> 36 37 #include <machine/stdarg.h> 38 39 MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers"); 40 41 #ifdef INVARIANTS 42 static void 43 assert_sbuf_integrity(struct sbuf *s) 44 { 45 KASSERT(s != NULL, 46 (__FUNCTION__ " called with a NULL sbuf pointer")); 47 KASSERT(s->s_buf != NULL, 48 (__FUNCTION__ " called with unitialized or corrupt sbuf")); 49 KASSERT(s->s_len < s->s_size, 50 ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); 51 } 52 53 static void 54 assert_sbuf_state(struct sbuf *s, int state) 55 { 56 KASSERT((s->s_flags & SBUF_FINISHED) == state, 57 (__FUNCTION__ " called with %sfinished or corrupt sbuf", 58 (state ? "un" : ""))); 59 } 60 #else 61 #define assert_sbuf_integrity(s) do { } while (0) 62 #define assert_sbuf_state(s, i) do { } while (0) 63 #endif 64 65 /* 66 * Initialize an sbuf. 67 * If buf is non-NULL, it points to a static or already-allocated string 68 * big enough to hold at least length characters. 69 */ 70 int 71 sbuf_new(struct sbuf *s, char *buf, size_t length, int flags) 72 { 73 KASSERT(flags == 0, 74 (__FUNCTION__ " called with non-zero flags")); 75 KASSERT(s != NULL, 76 (__FUNCTION__ " called with a NULL sbuf pointer")); 77 78 bzero(s, sizeof *s); 79 s->s_size = length; 80 if (buf) { 81 s->s_buf = buf; 82 return (0); 83 } 84 s->s_buf = malloc(s->s_size, M_SBUF, M_WAITOK); 85 if (s->s_buf == NULL) 86 return (-1); 87 SBUF_SETFLAG(s, SBUF_DYNAMIC); 88 return (0); 89 } 90 91 /* 92 * Set the sbuf's position to an arbitrary value 93 */ 94 int 95 sbuf_setpos(struct sbuf *s, size_t pos) 96 { 97 assert_sbuf_integrity(s); 98 assert_sbuf_state(s, 0); 99 100 KASSERT(pos >= 0, 101 ("attempt to seek to a negative position (%d)", pos)); 102 KASSERT(pos < s->s_size, 103 ("attempt to seek past end of sbuf (%d >= %d)", pos, s->s_size)); 104 105 if (pos < 0 || pos > s->s_len) 106 return (-1); 107 s->s_len = pos; 108 return (0); 109 } 110 111 /* 112 * Append a string to an sbuf. 113 */ 114 int 115 sbuf_cat(struct sbuf *s, char *str) 116 { 117 assert_sbuf_integrity(s); 118 assert_sbuf_state(s, 0); 119 120 if (SBUF_HASOVERFLOWED(s)) 121 return (-1); 122 123 while (*str && SBUF_HASROOM(s)) 124 s->s_buf[s->s_len++] = *str++; 125 if (*str) { 126 SBUF_SETFLAG(s, SBUF_OVERFLOWED); 127 return (-1); 128 } 129 return (0); 130 } 131 132 /* 133 * Copy a string into an sbuf. 134 */ 135 int 136 sbuf_cpy(struct sbuf *s, char *str) 137 { 138 assert_sbuf_integrity(s); 139 assert_sbuf_state(s, 0); 140 141 s->s_len = 0; 142 return (sbuf_cat(s, str)); 143 } 144 145 /* 146 * PCHAR function for sbuf_printf() 147 */ 148 static void 149 _sbuf_pchar(int c, void *v) 150 { 151 struct sbuf *s = (struct sbuf *)v; 152 153 assert_sbuf_integrity(s); 154 assert_sbuf_state(s, 0); 155 156 if (SBUF_HASOVERFLOWED(s)) 157 return; 158 if (SBUF_HASROOM(s)) 159 s->s_buf[s->s_len++] = c; 160 else 161 SBUF_SETFLAG(s, SBUF_OVERFLOWED); 162 } 163 164 /* 165 * Format the given arguments and append the resulting string to an sbuf. 166 */ 167 int 168 sbuf_printf(struct sbuf *s, char *fmt, ...) 169 { 170 va_list ap; 171 size_t len; 172 173 assert_sbuf_integrity(s); 174 assert_sbuf_state(s, 0); 175 176 KASSERT(fmt != NULL, 177 (__FUNCTION__ " called with a NULL format string")); 178 179 if (SBUF_HASOVERFLOWED(s)) 180 return (-1); 181 182 va_start(ap, fmt); 183 len = kvprintf(fmt, _sbuf_pchar, s, 10, ap); 184 va_end(ap); 185 186 KASSERT(s->s_len < s->s_size, 187 ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); 188 189 if (SBUF_HASOVERFLOWED(s)) 190 return (-1); 191 return (0); 192 } 193 194 /* 195 * Append a character to an sbuf. 196 */ 197 int 198 sbuf_putc(struct sbuf *s, int c) 199 { 200 assert_sbuf_integrity(s); 201 assert_sbuf_state(s, 0); 202 203 if (SBUF_HASOVERFLOWED(s)) 204 return (-1); 205 206 if (!SBUF_HASROOM(s)) { 207 SBUF_SETFLAG(s, SBUF_OVERFLOWED); 208 return (-1); 209 } 210 s->s_buf[s->s_len++] = c; 211 return (0); 212 } 213 214 /* 215 * Finish off an sbuf. 216 */ 217 int 218 sbuf_finish(struct sbuf *s) 219 { 220 assert_sbuf_integrity(s); 221 assert_sbuf_state(s, 0); 222 223 if (SBUF_HASOVERFLOWED(s)) 224 return (-1); 225 226 s->s_buf[s->s_len++] = '\0'; 227 SBUF_SETFLAG(s, SBUF_FINISHED); 228 return (0); 229 } 230 231 /* 232 * Return a pointer to the sbuf data. 233 */ 234 char * 235 sbuf_data(struct sbuf *s) 236 { 237 assert_sbuf_integrity(s); 238 assert_sbuf_state(s, SBUF_FINISHED); 239 240 if (SBUF_HASOVERFLOWED(s)) 241 return (NULL); 242 return s->s_buf; 243 } 244 245 /* 246 * Return the length of the sbuf data. 247 */ 248 size_t 249 sbuf_len(struct sbuf *s) 250 { 251 assert_sbuf_integrity(s); 252 assert_sbuf_state(s, SBUF_FINISHED); 253 254 if (SBUF_HASOVERFLOWED(s)) 255 return (0); 256 return s->s_len; 257 } 258 259 /* 260 * Clear an sbuf, free its buffer if necessary. 261 */ 262 void 263 sbuf_delete(struct sbuf *s) 264 { 265 assert_sbuf_integrity(s); 266 /* don't care if it's finished or not */ 267 268 if (SBUF_ISDYNAMIC(s)) 269 free(s->s_buf, M_SBUF); 270 bzero(s, sizeof *s); 271 } 272