1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <strings.h> 30 #include <secdb.h> 31 #include <ctype.h> 32 33 /* From libnsl */ 34 extern char *_strdup_null(char *); 35 extern char *_strtok_escape(char *, char *, char **); 36 extern char *_strpbrk_escape(char *, char *); 37 extern char *_unescape(char *, char *); 38 39 char *_do_unescape(char *); 40 41 42 /* 43 * kva_match(): Given a key-value array and a key, return a pointer to the 44 * value that matches the key. 45 */ 46 char * 47 kva_match(kva_t *kva, char *key) 48 { 49 int i; 50 kv_t *data; 51 52 if (kva == NULL || key == NULL) { 53 return ((char *)NULL); 54 } 55 data = kva->data; 56 for (i = 0; i < kva->length; i++) { 57 if (strcmp(data[i].key, key) == 0) { 58 return (data[i].value); 59 } 60 } 61 62 return ((char *)NULL); 63 } 64 65 /* 66 * _kva_free(): Free up memory. 67 */ 68 void 69 _kva_free(kva_t *kva) 70 { 71 int i; 72 kv_t *data; 73 74 if (kva == NULL) { 75 return; 76 } 77 data = kva->data; 78 for (i = 0; i < kva->length; i++) { 79 if (data[i].key != NULL) { 80 free(data[i].key); 81 data[i].key = NULL; 82 } 83 if (data[i].value != NULL) { 84 free(data[i].value); 85 data[i].value = NULL; 86 } 87 } 88 free(kva->data); 89 free(kva); 90 } 91 92 /* 93 * new_kva(): Allocate a key-value array. 94 */ 95 kva_t * 96 _new_kva(int size) 97 { 98 kva_t *new_kva; 99 100 if ((new_kva = (kva_t *)calloc(1, sizeof (kva_t))) == NULL) { 101 return ((kva_t *)NULL); 102 } 103 if ((new_kva->data = (kv_t *)calloc(1, (size*sizeof (kv_t)))) == NULL) { 104 free(new_kva); 105 return ((kva_t *)NULL); 106 } 107 108 return (new_kva); 109 } 110 111 /* 112 * _str2kva(): Given a string (s) of key-value pairs, separated by delimeter 113 * (del), place the values into the key value array (nkva). 114 */ 115 kva_t * 116 _str2kva(char *s, char *ass, char *del) 117 { 118 int n = 0; 119 int m; 120 int size = KV_ADD_KEYS; 121 char *buf; 122 char *p; 123 char *pair; 124 char *key; 125 char *last_pair; 126 char *last_key; 127 kv_t *data; 128 kva_t *nkva; 129 130 if (s == NULL || 131 ass == NULL || 132 del == NULL || 133 *s == '\0' || 134 *s == '\n' || 135 (strlen(s) <= 1)) { 136 return ((kva_t *)NULL); 137 } 138 p = s; 139 while ((p = _strpbrk_escape(p, ass)) != NULL) { 140 n++; 141 p++; 142 } 143 if (n > size) { 144 m = n/size; 145 if (n%size) { 146 ++m; 147 } 148 size = m * KV_ADD_KEYS; 149 } 150 if ((nkva = _new_kva(size)) == NULL) { 151 return ((kva_t *)NULL); 152 } 153 data = nkva->data; 154 nkva->length = 0; 155 if ((buf = strdup(s)) == NULL) { 156 return ((kva_t *)NULL); 157 } 158 pair = _strtok_escape(buf, del, &last_pair); 159 do { 160 key = _strtok_escape(pair, ass, &last_key); 161 if (key != NULL) { 162 data[nkva->length].key = _do_unescape(key); 163 data[nkva->length].value = _do_unescape(last_key); 164 nkva->length++; 165 } 166 } while ((pair = _strtok_escape(NULL, del, &last_pair)) != NULL); 167 free(buf); 168 return (nkva); 169 } 170 171 /* 172 * _kva2str(): Given an array of key-value pairs, place them into a string 173 * (buf). Use delimeter (del) to separate pairs. Use assignment character 174 * (ass) to separate keys and values. 175 * 176 * Return Values: 0 Success 1 Buffer too small 2 Out of memory 177 */ 178 int 179 _kva2str(kva_t *kva, char *buf, int buflen, char *ass, char *del) 180 { 181 int i; 182 int length = 0; 183 char *tmp; 184 kv_t *data; 185 186 if (kva == NULL) { 187 return (0); 188 } 189 data = kva->data; 190 for (i = 0; i < kva->length; i++) { 191 if (data[i].value != NULL) { 192 length += 2 + strlen(data[i].value); 193 } 194 } 195 if (length > buflen) { 196 return (1); 197 } 198 (void) memset(buf, 0, buflen); 199 if ((tmp = (char *)malloc(buflen)) == NULL) { 200 return (2); 201 } 202 for (i = 0; i < kva->length; i++) { 203 if (data[i].value != NULL) { 204 if (snprintf(tmp, buflen, "%s%s%s%s", 205 data[i].key, ass, data[i].value, del) >= buflen) { 206 return (0); 207 } 208 (void) strcat(buf, tmp); 209 } 210 } 211 return (0); 212 } 213 214 int 215 _insert2kva(kva_t *kva, char *key, char *value) 216 { 217 int i; 218 kv_t *data; 219 220 if (kva == NULL) { 221 return (0); 222 } 223 data = kva->data; 224 for (i = 0; i < kva->length; i++) { 225 if (strcmp(data[i].key, key) == 0) { 226 if (data[i].value != NULL) 227 free(data[i].value); 228 data[i].value = _strdup_null(value); 229 return (0); 230 } 231 } 232 return (1); 233 } 234 235 kva_t * 236 _kva_dup(kva_t *old_kva) 237 { 238 int i; 239 int size; 240 kv_t *old_data; 241 kv_t *new_data; 242 kva_t *nkva = (kva_t *)NULL; 243 244 if (old_kva == NULL) { 245 return ((kva_t *)NULL); 246 } 247 old_data = old_kva->data; 248 size = old_kva->length; 249 if ((nkva = _new_kva(size)) == NULL) { 250 return ((kva_t *)NULL); 251 } 252 new_data = nkva->data; 253 nkva->length = old_kva->length; 254 for (i = 0; i <= nkva->length; i++) { 255 new_data[i].key = _strdup_null(old_data[i].key); 256 new_data[i].value = _strdup_null(old_data[i].value); 257 } 258 259 return (nkva); 260 } 261 262 static void 263 strip_spaces(char **valuep) 264 { 265 char *p, *start; 266 267 /* Find first non-white space character and return pointer to it */ 268 for (p = *valuep; *p != '\0' && isspace((unsigned char)*p); p++) 269 ; 270 271 *valuep = start = p; 272 273 if (*p == '\0') 274 return; 275 276 p = p + strlen(p) - 1; 277 278 /* Remove trailing spaces */ 279 while (p > start && isspace((unsigned char)*p)) 280 p--; 281 282 p[1] = '\0'; 283 } 284 285 char * 286 _do_unescape(char *src) 287 { 288 char *tmp = NULL; 289 char *dst = NULL; 290 291 if (src == NULL) { 292 dst = _strdup_null(src); 293 } else { 294 strip_spaces(&src); 295 tmp = _unescape(src, "=;:,\\"); 296 dst = (tmp == NULL) ? _strdup_null(src) : tmp; 297 } 298 299 return (dst); 300 } 301 302 303 /* 304 * Some utilities for handling comma-separated lists. 305 */ 306 char * 307 _argv_to_csl(char **strings) 308 { 309 int len = 0; 310 int i = 0; 311 char *newstr = (char *)NULL; 312 313 if (strings == NULL) 314 return ((char *)NULL); 315 for (i = 0; strings[i] != NULL; i++) { 316 len += strlen(strings[i]) + 1; 317 } 318 if ((len > 0) && ((newstr = (char *)malloc(len + 1)) != NULL)) { 319 (void) memset(newstr, 0, len); 320 for (i = 0; strings[i] != NULL; i++) { 321 (void) strcat(newstr, strings[i]); 322 (void) strcat(newstr, ","); 323 } 324 newstr[len-1] = NULL; 325 return (newstr); 326 } else 327 return ((char *)NULL); 328 } 329 330 331 char ** 332 _csl_to_argv(char *csl) 333 { 334 int len = 0; 335 int ncommas = 0; 336 int i = 0; 337 char **spc = (char **)NULL; 338 char *copy = (char *)NULL; 339 char *pc; 340 char *lasts = (char *)NULL; 341 342 len = strlen(csl); 343 for (i = 0; i < len; i++) { 344 if (csl[i] == ',') 345 ncommas++; 346 } 347 if ((spc = (char **)malloc((ncommas + 2) * sizeof (char *))) == NULL) { 348 return ((char **)NULL); 349 } 350 copy = strdup(csl); 351 for (pc = strtok_r(copy, ",", &lasts), i = 0; pc != NULL; 352 pc = strtok_r(NULL, ",", &lasts), i++) { 353 spc[i] = strdup(pc); 354 } 355 spc[i] = NULL; 356 free(copy); 357 return (spc); 358 } 359 360 361 void 362 _free_argv(char **p_argv) 363 { 364 char **p_a; 365 366 for (p_a = p_argv; *p_a != NULL; p_a++) 367 free(*p_a); 368 free(p_argv); 369 } 370 371 372 #ifdef DEBUG 373 void 374 print_kva(kva_t *kva) 375 { 376 int i; 377 kv_t *data; 378 379 if (kva == NULL) { 380 printf(" (empty)\n"); 381 return; 382 } 383 data = kva->data; 384 for (i = 0; i < kva->length; i++) { 385 printf(" %s = %s\n", data[i].key, data[i].value); 386 } 387 } 388 #endif /* DEBUG */ 389