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