1 /* Id */ 2 /* $NetBSD: list.c,v 1.1.1.1 2016/02/09 20:29:12 plunky Exp $ */ 3 4 /*- 5 * Copyright (c) 2014 Iain Hibbert. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 * THE SOFTWARE. 24 */ 25 26 #include <stdarg.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 30 #include "driver.h" 31 32 /* 33 * A list is an opaque collection of strings. We can add strings, another 34 * list or an array of strings to the list. We can get a pointer to the 35 * array of strings in the list and the number of strings in it, and we 36 * can free the entire list when we are done. 37 */ 38 39 #define COUNT 64 /* element count increments */ 40 #define BLOCK 4096 /* buffer size increments */ 41 42 struct list { 43 const char ** array; 44 size_t arraylen; 45 size_t arrayused; 46 void * buf; 47 size_t buflen; 48 size_t bufused; 49 }; 50 51 /* 52 * return array pointer 53 */ 54 const char ** 55 list_array(const struct list *l) 56 { 57 58 return l->array; 59 } 60 61 /* 62 * return array count 63 */ 64 size_t 65 list_count(const struct list *l) 66 { 67 68 return l->arrayused; 69 } 70 71 /* 72 * allocate a new list header 73 */ 74 struct list * 75 list_alloc(void) 76 { 77 struct list *l; 78 79 l = xmalloc(sizeof(struct list)); 80 l->array = xmalloc(COUNT * sizeof(char *)); 81 l->array[0] = NULL; 82 l->arraylen = COUNT; 83 l->arrayused = 0; 84 l->buf = NULL; 85 l->buflen = 0; 86 l->bufused = 0; 87 88 return l; 89 } 90 91 /* 92 * release a list header and associated storage 93 */ 94 void 95 list_free(struct list *l) 96 { 97 98 free(l->array); 99 free(l->buf); 100 free(l); 101 } 102 103 /* 104 * print out a list 105 */ 106 void 107 list_print(const struct list *l) 108 { 109 size_t i; 110 111 for (i = 0; i < l->arrayused; i++) 112 fprintf(stderr, "%s%s\n", (i == 0 ? "" : " "), l->array[i]); 113 } 114 115 /* 116 * add const string to list 117 */ 118 void 119 list_add_nocopy(struct list *l, const char *str) 120 { 121 122 l->array[l->arrayused++] = str; 123 124 if (l->arrayused == l->arraylen) { 125 l->arraylen += COUNT; 126 l->array = xrealloc(l->array, l->arraylen * sizeof(char *)); 127 } 128 129 l->array[l->arrayused] = NULL; 130 } 131 132 /* 133 * add formatted string to list, storing in list buffer 134 */ 135 void 136 list_add(struct list *l, const char *str, ...) 137 { 138 va_list ap; 139 void *p; 140 size_t s; 141 int n; 142 143 for (;;) { 144 p = l->buf + l->bufused; 145 s = l->buflen - l->bufused; 146 147 va_start(ap, str); 148 n = vsnprintf(p, s, str, ap); 149 va_end(ap); 150 151 if (n < 0) 152 error("vsnprintf"); 153 154 if ((unsigned int)n < s) 155 break; 156 157 l->buflen += BLOCK; 158 l->buf = xrealloc(l->buf, l->buflen); 159 } 160 161 list_add_nocopy(l, p); 162 l->bufused += n; 163 } 164 165 /* 166 * add a NULL terminated array of const data to list 167 */ 168 void 169 list_add_array(struct list *l, const char **a) 170 { 171 172 while (*a) 173 list_add_nocopy(l, *a++); 174 } 175 176 /* 177 * add another list to list (with copy) 178 */ 179 void 180 list_add_list(struct list *l1, const struct list *l2) 181 { 182 size_t i; 183 184 for (i = 0; i < l2->arrayused; i++) 185 list_add(l1, l2->array[i]); 186 } 187