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 */ 33 extern char *_strdup_null(char *); 34 extern char *_strtok_escape(char *, char *, char **); 35 extern char *_strpbrk_escape(char *, char *); 36 extern char *_unescape(char *, char *); 37 38 char *_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 */ 45 char * 46 kva_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 */ 67 void 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 */ 95 void 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 */ 120 kva_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 */ 140 kva_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 */ 203 int 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 232 int 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 253 kva_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 280 static void 281 strip_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 303 char * 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 */ 324 char * 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] = '\0'; 343 return (newstr); 344 } else 345 return (NULL); 346 } 347 348 349 char ** 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 379 void 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 391 void 392 print_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