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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 28 /* 29 * Module: zones_str.c 30 * Group: libinstzones 31 * Description: Private functions used by zones library functions to manipulate 32 * strings 33 * 34 * Public Methods: 35 * 36 * _z_strAddToken - Add a token to a string 37 * _z_strContainsToken - Does a given string contain a specified substring 38 * _z_strGetToken - Get a separator delimited token from a string 39 * _z_strGetToken_r - Get separator delimited token from string to fixed buffer 40 * _z_strPrintf - Create string from printf style format and arguments 41 * _z_strPrintf_r - Create string from printf style format and arguments 42 * _z_strRemoveLeadingWhitespace - Remove leading whitespace from string 43 * _z_strRemoveToken - Remove a token from a string 44 */ 45 46 /* 47 * System includes 48 */ 49 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <unistd.h> 53 #include <ctype.h> 54 #include <sys/types.h> 55 #include <sys/param.h> 56 #include <string.h> 57 #include <strings.h> 58 #include <stdarg.h> 59 #include <limits.h> 60 #include <stropts.h> 61 #include <libintl.h> 62 #include <locale.h> 63 #include <assert.h> 64 65 /* 66 * local includes 67 */ 68 69 #include "instzones_lib.h" 70 #include "zones_strings.h" 71 72 /* 73 * Private structures 74 */ 75 76 /* 77 * Library Function Prototypes 78 */ 79 80 /* 81 * Local Function Prototypes 82 */ 83 84 /* 85 * Global internal (private) declarations 86 */ 87 88 /* 89 * ***************************************************************************** 90 * global external (public) functions 91 * ***************************************************************************** 92 */ 93 94 /* 95 * Name: _z_strAddToken 96 * Synopsis: Add a token to a string 97 * Description: Append a token (sequence of one or more characters) to a 98 * string that is in allocated space - create new string if 99 * no string to append to exists 100 * Arguments: a_old - [RO, *RW] - (char **) 101 * - Pointer to handle to string to append token to 102 * == NULL - new string is created 103 * a_new - [RO, *RO] - (char *) 104 * - Pointer to string representing token to append 105 * to the end of the "a_old" string 106 * == NULL - no action is performed 107 * a_new[0] == '\0' - no action is performed 108 * a_separator - [RO, *RO] - (char) 109 * - One character placed between the old (existing) 110 * string and the new token to be added IF the old 111 * string exists and is not empty (zero length) 112 * Returns: void 113 * CAUTION: The old (existing) string must be allocated space (via lu_mem* 114 * or _z_str* methods) - it must not be a static or inline 115 * character string 116 * NOTE: The old (existing) string may be freed with 'free' 117 * if a token is appended to it 118 * NOTE: Any string returned in 'a_old' is placed in new storage for the 119 * calling method. The caller must use 'free' to dispose 120 * of the storage once the token string is no longer needed. 121 */ 122 123 void 124 _z_strAddToken(char **a_old, char *a_new, char a_separator) 125 { 126 /* entry assertions */ 127 128 assert(a_old != NULL); 129 assert(a_separator != '\0'); 130 131 /* if token to add is null or token is zero length, just return */ 132 133 if (a_new == NULL || *a_new == '\0') { 134 return; 135 } 136 137 /* make sure that new token does not contain the separator */ 138 139 assert(strchr(a_new, (int)a_separator) == NULL); 140 141 /* if old string is empty (zero length), deallocate */ 142 143 if ((*a_old != NULL) && ((*a_old)[0] == '\0')) { 144 /* *a_old is set to NULL by free */ 145 free(*a_old); 146 *a_old = NULL; 147 } 148 149 /* if old string exists, append separator and token */ 150 151 if (*a_old != NULL) { 152 char *p; 153 p = _z_strPrintf("%s%c%s", *a_old, a_separator, a_new); 154 free(*a_old); 155 *a_old = p; 156 return; 157 } 158 159 /* old string does not exist - return duplicate of token */ 160 161 assert(*a_old == NULL); 162 *a_old = _z_strdup(a_new); 163 } 164 165 /* 166 * Name: _z_strContainsToken 167 * Synopsis: Does a given string contain a specified substring 168 * Description: Determine if a given substring exists in a larger string 169 * Arguments: a_string - [RO, *RO] - (char *) 170 * Pointer to string to look for substring in 171 * a_token - [RO, *RO] - (char *) 172 * Pointer to substring to look for in larger string 173 * Results: boolean_t 174 * B_TRUE - substring exists in larger string 175 * B_FALSE - substring does NOT exist in larger string 176 * NOTE: The substring must match on a "token" basis; that is, the 177 * substring must exist in the larger string delineated with 178 * either spaces or tabs to match. 179 */ 180 181 boolean_t 182 _z_strContainsToken(char *a_string, char *a_token, char *a_separators) 183 { 184 char *lasts; 185 char *current; 186 char *p; 187 188 /* entry assertions */ 189 190 assert(a_separators != NULL); 191 assert(*a_separators != '\0'); 192 193 /* 194 * if token is not supplied, no string provided, 195 * or the string is an empty string, return false 196 */ 197 198 if (a_token == NULL || a_string == NULL || *a_string == '\0') { 199 return (B_FALSE); 200 } 201 202 /* if no string provided, return false */ 203 204 /* if string empty (zero length), return false */ 205 206 /* duplicate larger string because strtok_r changes it */ 207 208 p = _z_strdup(a_string); 209 210 lasts = p; 211 212 /* scan each token looking for a match */ 213 214 while ((current = strtok_r(NULL, a_separators, &lasts)) != 215 NULL) { 216 if (strcmp(current, a_token) == 0) { 217 free(p); 218 return (B_TRUE); 219 } 220 } 221 222 /* free up temporary storage */ 223 224 free(p); 225 226 /* not found */ 227 228 return (B_FALSE); 229 } 230 231 /* 232 * Name: _z_strGetToken 233 * Synopsis: Get a separator delimited token from a string 234 * Description: Given a string and a list of one or more separators, 235 * return the position specified token (sequence of one or 236 * more characters that do not include any of the separators) 237 * Arguments: r_sep - [*RW] - (char *) 238 * - separator that ended the token returned 239 * - NOTE: this is a pointer to a "char", e.g.: 240 * - char a; 241 * - _z_strGetToken(&a, ...) 242 * a_string - [RO, *RO] - (char *) 243 * - pointer to string to extract token from 244 * a_index - [RO, *RO] - (int) 245 * - Index of token to return; '0' is first matching 246 * token, '1' is second matching token, etc. 247 * a_separators - [RO, *RO] - (char *) 248 * - String containing one or more characters that 249 * can separate one "token" from another 250 * Returns: char * 251 * == NULL - no token matching criteria found 252 * != NULL - token matching criteria 253 * NOTE: Any token string returned is placed in new storage for the 254 * calling method. The caller must use 'free' to dispose 255 * of the storage once the token string is no longer needed. 256 */ 257 258 char * 259 _z_strGetToken(char *r_sep, char *a_string, int a_index, char *a_separators) 260 { 261 char *p; 262 char *q; 263 char *lasts; 264 265 /* entry assertions */ 266 267 assert(a_string != NULL); 268 assert(a_index >= 0); 269 assert(a_separators != NULL); 270 assert(*a_separators != '\0'); 271 272 /* if returned separator requested, reset to null until token found */ 273 274 if (r_sep != NULL) { 275 *r_sep = '\0'; 276 } 277 278 /* duplicate original string before breaking down into tokens */ 279 280 p = _z_strdup(a_string); 281 282 lasts = p; 283 284 /* scan for separators and return 'index'th token found */ 285 286 while (q = strtok_r(NULL, a_separators, &lasts)) { 287 /* retrieve separator if requested */ 288 289 if (r_sep != NULL) { 290 char *x; 291 292 x = strpbrk(a_string, a_separators); 293 if (x != NULL) { 294 *r_sep = *x; 295 } 296 } 297 298 /* if this is the 'index'th token requested return it */ 299 300 if (a_index-- == 0) { 301 char *tmp; 302 303 /* duplicate token into its own storage */ 304 305 tmp = _z_strdup(q); 306 307 /* free up copy of original input string */ 308 309 free(p); 310 311 /* return token found */ 312 313 return (tmp); 314 } 315 } 316 317 /* 318 * token not found 319 */ 320 321 /* free up copy of original input string */ 322 323 free(p); 324 325 /* return NULL pointer (token not found) */ 326 327 return (NULL); 328 } 329 330 /* 331 * Name: _z_strGetToken_r 332 * Synopsis: Get separator delimited token from a string into a fixed buffer 333 * Description: Given a string and a list of one or more separators, 334 * return the position specified token (sequence of one or 335 * more characters that do not include any of the separators) 336 * into a specified buffer of a fixed maximum size 337 * Arguments: r_sep - [*RW] - (char *) 338 * - separator that ended the token returned 339 * - NOTE: this is a pointer to a "char", e.g.: 340 * - char a; 341 * - _z_strGetToken(&a, ...) 342 * a_string - [RO, *RO] - (char *) 343 * - pointer to string to extract token from 344 * a_index - [RO, *RO] - (int) 345 * - Index of token to return; '0' is first matching 346 * token, '1' is second matching token, etc. 347 * a_separators - [RO, *RO] - (char *) 348 * - String containing one or more characters that 349 * can separate one "token" from another 350 * a_buf - [RO, *RW] - (char *) 351 * - Pointer to buffer used as storage space for the 352 * returned token - the returned token is always 353 * null terminated 354 * a_buf[0] == '\0' - no token meeting criteria found 355 * a_buf[0] != '\0' - token meeting criteria returned 356 * a_bufLen - [RO, *RO] - (int) 357 * - Size of 'a_buf' in bytes - a maximum of 'a_bufLen-1' 358 * bytes will be placed in 'a_buf' - the returned 359 * token is always null terminated 360 * Returns: void 361 */ 362 363 void 364 _z_strGetToken_r(char *r_sep, char *a_string, int a_index, 365 char *a_separators, char *a_buf, int a_bufLen) 366 { 367 char *p; 368 char *q; 369 char *lasts; 370 371 /* entry assertions */ 372 373 assert(a_string != NULL); 374 assert(a_index >= 0); 375 assert(a_separators != NULL); 376 assert(*a_separators != '\0'); 377 assert(a_buf != NULL); 378 assert(a_bufLen > 0); 379 380 /* reset returned separator */ 381 382 if (r_sep != NULL) { 383 *r_sep = '\0'; 384 } 385 386 /* zero out contents of return buffer */ 387 388 bzero(a_buf, a_bufLen); 389 390 /* duplicate original string before breaking down into tokens */ 391 392 p = _z_strdup(a_string); 393 394 lasts = p; 395 396 /* scan for separators and return 'index'th token found */ 397 398 while (q = strtok_r(NULL, a_separators, &lasts)) { 399 /* retrieve separator if requested */ 400 401 if (r_sep != NULL) { 402 char *x; 403 x = strpbrk(a_string, a_separators); 404 if (x != NULL) { 405 *r_sep = *x; 406 } 407 } 408 409 /* if this is the 'index'th token requested return it */ 410 411 if (a_index-- == 0) { 412 /* copy as many characters as possible to return buf */ 413 414 (void) strncpy(a_buf, q, a_bufLen-1); 415 break; 416 } 417 } 418 419 /* free up copy of original input string */ 420 421 free(p); 422 } 423 424 /* 425 * Name: _z_strPrintf 426 * Synopsis: Create string from printf style format and arguments 427 * Description: Call to convert a printf style format and arguments into a 428 * string of characters placed in allocated storage 429 * Arguments: format - [RO, RO*] (char *) 430 * printf-style format for string to be formatted 431 * VARG_LIST - [RO] (?) 432 * arguments as appropriate to 'format' specified 433 * Returns: char * 434 * A string representing the printf conversion results 435 * NOTE: Any string returned is placed in new storage for the 436 * calling method. The caller must use 'free' to dispose 437 * of the storage once the string is no longer needed. 438 * Errors: If the string cannot be created, the process exits 439 */ 440 441 /*PRINTFLIKE1*/ 442 char * 443 _z_strPrintf(char *a_format, ...) 444 { 445 va_list ap; 446 size_t vres = 0; 447 char bfr[1]; 448 char *rstr = NULL; 449 450 /* entry assertions */ 451 452 assert(a_format != NULL); 453 assert(*a_format != '\0'); 454 455 /* determine size of the message in bytes */ 456 457 va_start(ap, a_format); 458 vres = vsnprintf(bfr, 1, a_format, ap); 459 va_end(ap); 460 461 assert(vres > 0); 462 assert(vres < LINE_MAX); 463 464 /* allocate storage to hold the message */ 465 466 rstr = (char *)_z_calloc(vres+2); 467 468 /* generate the results of the printf conversion */ 469 470 va_start(ap, a_format); 471 vres = vsnprintf(rstr, vres+1, a_format, ap); 472 va_end(ap); 473 474 assert(vres > 0); 475 assert(vres < LINE_MAX); 476 assert(*rstr != '\0'); 477 478 /* return the results */ 479 480 return (rstr); 481 } 482 483 /* 484 * Name: _z_strPrintf_r 485 * Synopsis: Create string from printf style format and arguments 486 * Description: Call to convert a printf style format and arguments into a 487 * string of characters placed in allocated storage 488 * Arguments: a_buf - [RO, *RW] - (char *) 489 * - Pointer to buffer used as storage space for the 490 * returned string created 491 * a_bufLen - [RO, *RO] - (int) 492 * - Size of 'a_buf' in bytes - a maximum of 'a_bufLen-1' 493 * bytes will be placed in 'a_buf' - the returned 494 * string is always null terminated 495 * a_format - [RO, RO*] (char *) 496 * printf-style format for string to be formatted 497 * VARG_LIST - [RO] (?) 498 * arguments as appropriate to 'format' specified 499 * Returns: void 500 */ 501 502 /*PRINTFLIKE3*/ 503 void 504 _z_strPrintf_r(char *a_buf, int a_bufLen, char *a_format, ...) 505 { 506 va_list ap; 507 size_t vres = 0; 508 509 /* entry assertions */ 510 511 assert(a_format != NULL); 512 assert(*a_format != '\0'); 513 assert(a_buf != NULL); 514 assert(a_bufLen > 1); 515 516 /* generate the results of the printf conversion */ 517 518 va_start(ap, a_format); 519 vres = vsnprintf(a_buf, a_bufLen-1, a_format, ap); 520 va_end(ap); 521 522 assert(vres > 0); 523 assert(vres < a_bufLen); 524 525 a_buf[a_bufLen-1] = '\0'; 526 } 527 528 /* 529 * Name: _z_strRemoveLeadingWhitespace 530 * Synopsis: Remove leading whitespace from string 531 * Description: Remove all leading whitespace characters from a string 532 * Arguments: a_str - [RO, *RW] - (char **) 533 * Pointer to handle to string (in allocated storage) to 534 * remove all leading whitespace from 535 * Returns: void 536 * The input string is modified as follows: 537 * == NULL: 538 * - input string was NULL 539 * - input string is all whitespace 540 * != NULL: 541 * - copy of input string with leading 542 * whitespace removed 543 * CAUTION: The input string must be allocated space (via mem* or 544 * _z_str* methods) - it must not be a static or inline 545 * character string 546 * NOTE: The input string a_str will be freed with 'free' 547 * if it is all whitespace, or if it contains any leading 548 * whitespace characters 549 * NOTE: Any string returned is placed in new storage for the 550 * calling method. The caller must use 'free' to dispose 551 * of the storage once the string is no longer needed. 552 * Errors: If the string cannot be created, the process exits 553 */ 554 555 void 556 _z_strRemoveLeadingWhitespace(char **a_str) 557 { 558 char *o_str; 559 560 /* entry assertions */ 561 562 assert(a_str != NULL); 563 564 /* if string is null, just return */ 565 566 if (*a_str == NULL) { 567 return; 568 } 569 o_str = *a_str; 570 571 /* if string is empty, deallocate and return NULL */ 572 573 if (*o_str == '\0') { 574 /* free string - handle is not reset to NULL by free */ 575 free(*a_str); 576 *a_str = NULL; 577 return; 578 } 579 580 /* if first character is not a space, just return */ 581 582 if (!isspace(*o_str)) { 583 return; 584 } 585 586 /* advance past all space characters */ 587 588 while ((*o_str != '\0') && (isspace(*o_str))) { 589 o_str++; 590 } 591 592 /* if string was all space characters, deallocate and return NULL */ 593 594 if (*o_str == '\0') { 595 /* free string - *a_str is not reset to NULL by free */ 596 free(*a_str); 597 *a_str = NULL; 598 return; 599 } 600 601 /* have non-space/null byte, return dup, deallocate original */ 602 603 free(*a_str); 604 *a_str = _z_strdup(o_str); 605 } 606 607 /* 608 * Name: _z_strRemoveToken 609 * Synopsis: Remove a token from a string 610 * Description: Remove a token (sequence of one or more characters) from a 611 * string that is in allocated space 612 * Arguments: r_string - [RO, *RW] - (char **) 613 * - Pointer to handle to string to remove token from 614 * a_token - [RO, *RO] - (char *) 615 * Pointer to token (substring) to look for and remove 616 * from r_string provided 617 * a_separators - [RO, *RO] - (char *) 618 * - String containing one or more characters that 619 * separate one "token" from another in r_string 620 * a_index - [RO, *RO] - (int) 621 * - Index of token to remove; '0' is first matching 622 * token, '1' is second matching token, etc. 623 * Returns: void 624 * CAUTION: The input string must be allocated space (via lu_mem* or 625 * _z_str* methods) - it must not be a static or inline 626 * character string 627 * NOTE: The input string r_string will be freed with 'free' 628 * if the token to be removed is found 629 * NOTE: Any token string returned is placed in new storage for the 630 * calling method. The caller must use 'free' to dispose 631 * of the storage once the token string is no longer needed. 632 * Errors: If the new token string cannot be created, the process exits 633 */ 634 635 void 636 _z_strRemoveToken(char **r_string, char *a_token, char *a_separators, 637 int a_index) 638 { 639 char *a_string; 640 char *copyString; 641 char sep = 0; 642 int copyLength; 643 int i; 644 645 /* entry assertions */ 646 647 assert(r_string != NULL); 648 assert(a_token != NULL); 649 assert(*a_token != '\0'); 650 assert(a_separators != NULL); 651 assert(*a_separators != '\0'); 652 653 /* simple case: input string is null; return empty string */ 654 655 a_string = *r_string; 656 if (*a_string == '\0') { 657 return; 658 } 659 660 /* simple case: token == input string; return empty string */ 661 662 if (strcmp(a_string, a_token) == 0) { 663 /* 664 * deallocate input string; free doesn't 665 * set *r_string to NULL 666 */ 667 free(*r_string); 668 *r_string = NULL; 669 return; 670 } 671 672 /* simple case: token not in input string: return */ 673 674 if (!_z_strContainsToken(a_string, a_token, a_separators)) { 675 return; 676 } 677 678 /* 679 * Pick apart the old string building the new one as we go along 680 * removing the first occurance of the token provided 681 */ 682 683 copyLength = (strlen(a_string)-strlen(a_token))+2; 684 copyString = (char *)_z_calloc(copyLength); 685 686 for (i = 0; ; i++) { 687 char *p; 688 689 p = _z_strGetToken(&sep, a_string, i, a_separators); 690 if (p == NULL) { 691 break; 692 } 693 694 if ((strcmp(p, a_token) == 0) && (a_index-- == 0)) { 695 free(p); 696 continue; 697 } 698 699 if (*copyString) { 700 assert(sep != '\0'); 701 (void) strncat(copyString, &sep, 1); 702 } 703 704 (void) strcat(copyString, p); 705 free(p); 706 } 707 708 free(*r_string); 709 assert(*copyString); 710 *r_string = copyString; 711 } 712