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 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 /* 29 * Module: pkgstr.c 30 * Synopsis: general string services 31 * Taxonomy: project private 32 * Debug Flag: str 33 * Description: 34 * 35 * This module implements general string utility services 36 * 37 * Public Methods: 38 * 39 * pkgstrAddToken - Add a token to a string 40 * pkgstrContainsToken - Determine if a string contains a specified token 41 * pkgstrConvertPathToBasename - Return copy of base name in path string 42 * pkgstrConvertPathToDirname - Return copy of directory name in path string 43 * pkgstrConvertUllToTimeString_r - convert unsigned long long to time string 44 * pkgstrExpandTokens - Expand tokens from string appending tokens to another 45 * pkgstrGetToken - Get a token from a string 46 * pkgstrGetToken_r - Get a token from a string into a fixed buffer 47 * pkgstrLocatePathBasename - Locate position of base name in path string 48 * pkgstrNumTokens - Determine number of tokens in string 49 * pkgstrPrintf - Create a string from a printf style format and arguments 50 * pkgstrPrintf_r - Create a string from a printf style format and arguments 51 * into a fixed buffer 52 * pkgstrRemoveToken - Remove a token from a string 53 * pkgstrRemoveLeadingWhitespace - remove leading whitespace from string 54 * pkgstrScaleNumericString - Convert unsigned long long to human 55 * readable form 56 */ 57 58 /* 59 * Unix Includes 60 */ 61 62 #define __EXTENSIONS__ 63 64 #include <stdio.h> 65 #include <stdlib.h> 66 #include <string.h> 67 #include <libintl.h> 68 #include <limits.h> 69 #include <sys/types.h> 70 #include <assert.h> 71 #include <errno.h> 72 #include <libintl.h> 73 #include <ctype.h> 74 #include <unistd.h> 75 #include <strings.h> 76 #include <stdarg.h> 77 78 /* 79 * pkglib Includes 80 */ 81 82 #include "pkglib.h" 83 #include "pkgstrct.h" 84 #include "libintl.h" 85 #include "pkglocale.h" 86 87 /* 88 * External definitions 89 */ 90 91 /* 92 * Public methods 93 */ 94 95 /* 96 * Name: pkgstrRemoveLeadingWhitespace 97 * Synopsis: Remove leading whitespace from string 98 * Description: Remove all leading whitespace characters from a string 99 * Arguments: a_str - [RO, *RW] - (char **) 100 * Pointer to handle to string (in allocated storage) to 101 * remove all leading whitespace from 102 * Returns: void 103 * The input string is modified as follows: 104 * == (char *)NULL: 105 * - input string was (char *)NULL 106 * - input string is all whitespace 107 * != (char *)NULL: 108 * - copy of input string with leading 109 * whitespace removed 110 * CAUTION: The input string must be allocated space (via mem* or 111 * pkgstr* methods) - it must not be a static or inline 112 * character string 113 * NOTE: The input string a_str will be freed with 'free' 114 * if it is all whitespace, or if it contains any leading 115 * whitespace characters 116 * NOTE: Any string returned is placed in new storage for the 117 * calling method. The caller must use 'free' to dispose 118 * of the storage once the string is no longer needed. 119 * Errors: If the string cannot be created, the process exits 120 */ 121 122 void 123 pkgstrRemoveLeadingWhitespace(char **a_str) 124 { 125 char *o_str; 126 127 /* entry assertions */ 128 129 assert(a_str != (char **)NULL); 130 131 /* if string is null, just return */ 132 133 if (*a_str == (char *)NULL) { 134 return; 135 } 136 o_str = *a_str; 137 138 /* if string is empty, deallocate and return NULL */ 139 140 if (*o_str == '\0') { 141 /* free string - handle is reset to NULL by free */ 142 free(*a_str); 143 *a_str = (char *)NULL; 144 return; 145 } 146 147 /* if first character is not a space, just return */ 148 149 if (!isspace(*o_str)) { 150 return; 151 } 152 153 /* advance past all space characters */ 154 155 while ((*o_str != '\0') && (isspace(*o_str))) { 156 o_str++; 157 } 158 159 /* if string was all space characters, deallocate and return NULL */ 160 161 if (*o_str == '\0') { 162 /* free string - *a_str is reset to NULL by free */ 163 free(*a_str); 164 *a_str = (char *)NULL; 165 return; 166 } 167 168 /* have non-space/null byte, return dup, deallocate original */ 169 170 o_str = strdup(o_str); 171 assert(o_str != (char *)NULL); 172 if (o_str != (char *)NULL) { 173 free(*a_str); 174 *a_str = o_str; 175 } 176 } 177 178 unsigned long 179 pkgstrNumTokens(char *a_string, char *a_separators) 180 { 181 int index; 182 183 if (a_string == (char *)NULL) { 184 return (0); 185 } 186 187 if (*a_string == '\0') { 188 return (0); 189 } 190 191 for (index = 0 ; ; index ++) { 192 char *p; 193 194 p = pkgstrGetToken((char *)NULL, a_string, index, a_separators); 195 if (p == (char *)NULL) { 196 return (index); 197 } 198 free(p); 199 } 200 } 201 202 /* 203 * Name: pkgstrPrintf_r 204 * Synopsis: Create string from printf style format and arguments 205 * Description: Call to convert a printf style format and arguments into a 206 * string of characters placed in allocated storage 207 * Arguments: a_buf - [RO, *RW] - (char *) 208 * - Pointer to buffer used as storage space for the 209 * returned string created 210 * a_bufLen - [RO, *RO] - (int) 211 * - Size of 'a_buf' in bytes - a maximum of 'a_bufLen-1' 212 * bytes will be placed in 'a_buf' - the returned 213 * string is always null terminated 214 * a_format - [RO, RO*] (char *) 215 * printf-style format for string to be formatted 216 * VARG_LIST - [RO] (?) 217 * arguments as appropriate to 'format' specified 218 * Returns: void 219 */ 220 221 /*PRINTFLIKE3*/ 222 void 223 pkgstrPrintf_r(char *a_buf, int a_bufLen, char *a_format, ...) 224 { 225 va_list ap; 226 size_t vres = 0; 227 228 /* entry assertions */ 229 230 assert(a_format != (char *)NULL); 231 assert(*a_format != '\0'); 232 assert(a_buf != (char *)NULL); 233 assert(a_bufLen > 1); 234 235 /* generate the results of the printf conversion */ 236 237 va_start(ap, a_format); 238 vres = vsnprintf(a_buf, a_bufLen-1, a_format, ap); 239 va_end(ap); 240 241 assert(vres > 0); 242 assert(vres < a_bufLen); 243 244 a_buf[a_bufLen-1] = '\0'; 245 } 246 247 /* 248 * Name: pkgstrPrintf 249 * Synopsis: Create string from printf style format and arguments 250 * Description: Call to convert a printf style format and arguments into a 251 * string of characters placed in allocated storage 252 * Arguments: format - [RO, RO*] (char *) 253 * printf-style format for string to be formatted 254 * VARG_LIST - [RO] (?) 255 * arguments as appropriate to 'format' specified 256 * Returns: char * 257 * A string representing the printf conversion results 258 * NOTE: Any string returned is placed in new storage for the 259 * calling method. The caller must use 'free' to dispose 260 * of the storage once the string is no longer needed. 261 * Errors: If the string cannot be created, the process exits 262 */ 263 264 /*PRINTFLIKE1*/ 265 char * 266 pkgstrPrintf(char *a_format, ...) 267 { 268 va_list ap; 269 size_t vres = 0; 270 char bfr[1]; 271 char *rstr = (char *)NULL; 272 273 /* entry assertions */ 274 275 assert(a_format != (char *)NULL); 276 assert(*a_format != '\0'); 277 278 /* determine size of the message in bytes */ 279 280 va_start(ap, a_format); 281 vres = vsnprintf(bfr, 1, a_format, ap); 282 va_end(ap); 283 284 assert(vres > 0); 285 assert(vres < LINE_MAX); 286 287 /* allocate storage to hold the message */ 288 289 rstr = (char *)calloc(1, vres+2); 290 assert(rstr != (char *)NULL); 291 if (rstr == (char *)NULL) { 292 return ((char *)NULL); 293 } 294 295 /* generate the results of the printf conversion */ 296 297 va_start(ap, a_format); 298 vres = vsnprintf(rstr, vres+1, a_format, ap); 299 va_end(ap); 300 301 assert(vres > 0); 302 assert(vres < LINE_MAX); 303 assert(*rstr != '\0'); 304 305 /* return the results */ 306 307 return (rstr); 308 } 309 310 /* 311 * Name: pkgstrExpandTokens 312 * Synopsis: Expand tokens from string appending tokens to another 313 * Description: Given a string and a list of one or more separators, 314 * expand each token from the string and append those tokens 315 * to a string that is in allocated space - create new string 316 * if no string to append to exists. 317 * Arguments: a_old - [RO, *RW] - (char **) 318 * - Pointer to handle to string to append token to 319 * == (char *)NULL - new string is created 320 * a_separator - [RO, *RO] - (char *) 321 * - separator to end tokens returned 322 * a_separators - [RO, *RO] - (char *) 323 * - String containing one or more characters that 324 * can separate one "token" from a_string from another 325 * Returns: void 326 * NOTE: Any token string returned is placed in new storage for the 327 * calling method. The caller must use 'free' to dispose 328 * of the storage once the token string is no longer needed. 329 */ 330 331 void 332 pkgstrExpandTokens(char **a_old, char *a_string, char a_separator, 333 char *a_separators) 334 { 335 int i; 336 char sep[2] = {'\0', '\0'}; 337 338 /* convert single separator character into character string */ 339 340 sep[0] = a_separator; 341 342 /* 343 * iterate extracting tokens from the source string and adding 344 * those tokens to the target string when the tokens are not 345 * already present in the target string 346 */ 347 348 for (i = 0; ; i++) { 349 char *p; 350 351 /* extract the next matching token from the source string */ 352 353 p = pkgstrGetToken((char *)NULL, a_string, i, a_separators); 354 355 /* return if no token is available */ 356 357 if (p == (char *)NULL) { 358 return; 359 } 360 361 /* 362 * obtained token from source string: if the token is not 363 * in the target string, add the token to the target string 364 */ 365 366 if (pkgstrContainsToken(*a_old, p, sep) == B_FALSE) { 367 pkgstrAddToken(a_old, p, *sep); 368 } 369 370 /* free up temporary storage used by token from source string */ 371 372 free(p); 373 } 374 /*NOTREACHED*/ 375 } 376 377 378 /* 379 * Name: pkgstrGetToken 380 * Synopsis: Get a separator delimited token from a string 381 * Description: Given a string and a list of one or more separators, 382 * return the position specified token (sequence of one or 383 * more characters that do not include any of the separators) 384 * Arguments: r_sep - [*RW] - (char *) 385 * - separator that ended the token returned 386 * - NOTE: this is a pointer to a "char", e.g.: 387 * - char a; 388 * - pkgstrGetToken(&a, ...) 389 * a_string - [RO, *RO] - (char *) 390 * - pointer to string to extract token from 391 * a_index - [RO, *RO] - (int) 392 * - Index of token to return; '0' is first matching 393 * token, '1' is second matching token, etc. 394 * a_separators - [RO, *RO] - (char *) 395 * - String containing one or more characters that 396 * can separate one "token" from another 397 * Returns: char * 398 * == (char *)NULL - no token matching criteria found 399 * != (char *)NULL - token matching criteria 400 * NOTE: Any token string returned is placed in new storage for the 401 * calling method. The caller must use 'free' to dispose 402 * of the storage once the token string is no longer needed. 403 */ 404 405 char * 406 pkgstrGetToken(char *r_sep, char *a_string, int a_index, char *a_separators) 407 { 408 char *p; 409 char *q; 410 char *lasts; 411 412 /* entry assertions */ 413 414 assert(a_string != (char *)NULL); 415 assert(a_index >= 0); 416 assert(a_separators != (char *)NULL); 417 assert(*a_separators != '\0'); 418 419 /* if returned separator requested, reset to null until token found */ 420 421 if (r_sep != (char *)NULL) { 422 *r_sep = '\0'; 423 } 424 425 /* duplicate original string before breaking down into tokens */ 426 427 p = strdup(a_string); 428 assert(p != (char *)NULL); 429 if (p == (char *)NULL) { 430 return ((char *)NULL); 431 } 432 lasts = p; 433 434 /* scan for separators and return 'index'th token found */ 435 436 while (q = strtok_r((char *)NULL, a_separators, &lasts)) { 437 /* retrieve separator if requested */ 438 439 if (r_sep != (char *)NULL) { 440 char *x; 441 442 x = strpbrk(a_string, a_separators); 443 if (x) { 444 *r_sep = *x; 445 } 446 } 447 448 /* if this is the 'index'th token requested return it */ 449 450 if (a_index-- == 0) { 451 char *tmp; 452 453 /* duplicate token into its own storage */ 454 455 tmp = strdup(q); 456 assert(tmp != (char *)NULL); 457 if (tmp == (char *)NULL) { 458 return ((char *)NULL); 459 } 460 461 /* free up copy of original input string */ 462 463 free(p); 464 465 /* return token found */ 466 467 return (tmp); 468 } 469 } 470 471 /* 472 * token not found 473 */ 474 475 /* free up copy of original input string */ 476 477 free(p); 478 479 /* return NULL pointer (token not found) */ 480 481 return ((char *)NULL); 482 } 483 484 /* 485 * Name: pkgstrGetToken 486 * Synopsis: Get separator delimited token from a string into a fixed buffer 487 * Description: Given a string and a list of one or more separators, 488 * return the position specified token (sequence of one or 489 * more characters that do not include any of the separators) 490 * into a specified buffer of a fixed maximum size 491 * Arguments: r_sep - [*RW] - (char *) 492 * - separator that ended the token returned 493 * - NOTE: this is a pointer to a "char", e.g.: 494 * - char a; 495 * - pkgstrGetToken(&a, ...) 496 * a_string - [RO, *RO] - (char *) 497 * - pointer to string to extract token from 498 * a_index - [RO, *RO] - (int) 499 * - Index of token to return; '0' is first matching 500 * token, '1' is second matching token, etc. 501 * a_separators - [RO, *RO] - (char *) 502 * - String containing one or more characters that 503 * can separate one "token" from another 504 * a_buf - [RO, *RW] - (char *) 505 * - Pointer to buffer used as storage space for the 506 * returned token - the returned token is always 507 * null terminated 508 * a_buf[0] == '\0' - no token meeting criteria found 509 * a_buf[0] != '\0' - token meeting criteria returned 510 * a_bufLen - [RO, *RO] - (int) 511 * - Size of 'a_buf' in bytes - a maximum of 'a_bufLen-1' 512 * bytes will be placed in 'a_buf' - the returned 513 * token is always null terminated 514 * Returns: void 515 */ 516 517 void 518 pkgstrGetToken_r(char *r_sep, char *a_string, int a_index, 519 char *a_separators, char *a_buf, int a_bufLen) 520 { 521 char *p; 522 char *q; 523 char *lasts; 524 525 /* entry assertions */ 526 527 assert(a_string != (char *)NULL); 528 assert(a_index >= 0); 529 assert(a_separators != (char *)NULL); 530 assert(*a_separators != '\0'); 531 assert(a_buf != (char *)NULL); 532 assert(a_bufLen > 0); 533 534 /* reset returned separator */ 535 536 if (r_sep != (char *)NULL) { 537 *r_sep = '\0'; 538 } 539 540 /* zero out contents of return buffer */ 541 542 bzero(a_buf, a_bufLen); 543 544 /* duplicate original string before breaking down into tokens */ 545 546 p = strdup(a_string); 547 assert(p != (char *)NULL); 548 if (p == (char *)NULL) { 549 return; 550 } 551 lasts = p; 552 553 /* scan for separators and return 'index'th token found */ 554 555 while (q = strtok_r((char *)NULL, a_separators, &lasts)) { 556 /* retrieve separator if requested */ 557 558 if (r_sep != (char *)NULL) { 559 char *x; 560 x = strpbrk(a_string, a_separators); 561 if (x) { 562 *r_sep = *x; 563 } 564 } 565 566 /* if this is the 'index'th token requested return it */ 567 568 if (a_index-- == 0) { 569 /* copy as many characters as possible to return buf */ 570 571 (void) strncpy(a_buf, q, a_bufLen-1); 572 break; 573 } 574 } 575 576 /* free up copy of original input string */ 577 578 free(p); 579 } 580 581 /* 582 * Name: pkgstrAddToken 583 * Synopsis: Add a token to a string 584 * Description: Append a token (sequence of one or more characters) to a 585 * string that is in allocated space - create new string if 586 * no string to append to exists 587 * Arguments: a_old - [RO, *RW] - (char **) 588 * - Pointer to handle to string to append token to 589 * == (char *)NULL - new string is created 590 * a_new - [RO, *RO] - (char *) 591 * - Pointer to string representing token to append 592 * to the end of the "a_old" string 593 * == (char *)NULL - no action is performed 594 * a_new[0] == '\0' - no action is performed 595 * a_separator - [RO, *RO] - (char) 596 * - One character placed between the old (existing) 597 * string and the new token to be added IF the old 598 * string exists and is not empty (zero length) 599 * Returns: void 600 * CAUTION: The old (existing) string must be allocated space (via lu_mem* 601 * or pkgstr* methods) - it must not be a static or inline 602 * character string 603 * NOTE: The old (existing) string may be freed with 'free' 604 * if a token is appended to it 605 * NOTE: Any string returned in 'a_old' is placed in new storage for the 606 * calling method. The caller must use 'free' to dispose 607 * of the storage once the token string is no longer needed. 608 */ 609 610 void 611 pkgstrAddToken(char **a_old, char *a_new, char a_separator) 612 { 613 /* entry assertions */ 614 615 assert(a_old != (char **)NULL); 616 assert(a_separator != '\0'); 617 618 /* if token to add is null, just return */ 619 620 if (a_new == (char *)NULL) { 621 return; 622 } 623 624 /* if token to add is empty (zero length), just return */ 625 626 if (*a_new == '\0') { 627 return; 628 } 629 630 /* make sure that new token does not contain the separator */ 631 632 assert(strchr(a_new, (int)a_separator) == (char *)NULL); 633 634 /* if old string is empty (zero length), deallocate */ 635 636 if ((*a_old != (char *)NULL) && ((*a_old)[0] == '\0')) { 637 /* *a_old is set to NULL by free */ 638 free(*a_old); 639 *a_old = (char *)NULL; 640 } 641 642 /* if old string is exists, append separator and token */ 643 644 if (*a_old != (char *)NULL) { 645 char *p; 646 p = pkgstrPrintf("%s%c%s", *a_old, a_separator, a_new); 647 free(*a_old); 648 *a_old = p; 649 return; 650 } 651 652 /* old string does not exist - return duplicate of token */ 653 654 assert(*a_old == (char *)NULL); 655 *a_old = strdup(a_new); 656 assert(*a_old != (char *)NULL); 657 } 658 659 /* 660 * Name: pkgstrContainsToken 661 * Synopsis: Does a given string contain a specified substring 662 * Description: Determine if a given substring exists in a larger string 663 * Arguments: a_string - [RO, *RO] - (char *) 664 * Pointer to string to look for substring in 665 * a_token - [RO, *RO] - (char *) 666 * Pointer to substring to look for in larger string 667 * Results: boolean_t 668 * B_TRUE - substring exists in larger string 669 * B_FALSE - substring does NOT exist in larger string 670 * NOTE: The substring must match on a "token" basis; that is, the 671 * substring must exist in the larger string delineated with 672 * either spaces or tabs to match. 673 */ 674 675 boolean_t 676 pkgstrContainsToken(char *a_string, char *a_token, char *a_separators) 677 { 678 char *lasts; 679 char *current; 680 char *p; 681 682 /* entry assertions */ 683 684 assert(a_separators != (char *)NULL); 685 assert(*a_separators != '\0'); 686 687 /* if token is not supplied, return false */ 688 689 if (a_token == (char *)NULL) { 690 return (B_FALSE); 691 } 692 693 /* if no string provided, return false */ 694 695 if (a_string == (char *)NULL) { 696 return (B_FALSE); 697 } 698 699 /* if string empty (zero length), return false */ 700 701 if (*a_string == '\0') { 702 return (B_FALSE); 703 } 704 705 /* duplicate larger string because strtok_r changes it */ 706 707 p = strdup(a_string); 708 assert(p != (char *)NULL); 709 if (p == (char *)NULL) { 710 return (B_FALSE); 711 } 712 713 lasts = p; 714 715 /* scan each token looking for a match */ 716 717 while ((current = strtok_r((char *)NULL, a_separators, &lasts)) != 718 (char *)NULL) { 719 if (streq(current, a_token)) { 720 free(p); 721 return (B_TRUE); 722 } 723 } 724 725 /* free up temporary storage */ 726 727 free(p); 728 729 /* not found */ 730 731 return (B_FALSE); 732 } 733 734 /* 735 * Name: pkgstrRemoveToken 736 * Synopsis: Remove a token from a string 737 * Description: Remove a token (sequence of one or more characters) from a 738 * string that is in allocated space 739 * Arguments: r_string - [RO, *RW] - (char **) 740 * - Pointer to handle to string to remove token from 741 * a_token - [RO, *RO] - (char *) 742 * Pointer to token (substring) to look for and remove 743 * from r_string provided 744 * a_separators - [RO, *RO] - (char *) 745 * - String containing one or more characters that 746 * separate one "token" from another in r_string 747 * a_index - [RO, *RO] - (int) 748 * - Index of token to remove; '0' is first matching 749 * token, '1' is second matching token, etc. 750 * Returns: void 751 * CAUTION: The input string must be allocated space (via lu_mem* or 752 * pkgstr* methods) - it must not be a static or inline 753 * character string 754 * NOTE: The input string r_string will be freed with 'free' 755 * if the token to be removed is found 756 * NOTE: Any token string returned is placed in new storage for the 757 * calling method. The caller must use 'free' to dispose 758 * of the storage once the token string is no longer needed. 759 * Errors: If the new token string cannot be created, the process exits 760 */ 761 762 void 763 pkgstrRemoveToken(char **r_string, char *a_token, char *a_separators, 764 int a_index) 765 { 766 char *a_string; 767 char *copyString; 768 char sep = 0; 769 int copyLength; 770 int i; 771 772 /* entry assertions */ 773 774 assert(r_string != (char **)NULL); 775 assert(a_token != (char *)NULL); 776 assert(*a_token != '\0'); 777 assert(a_separators != (char *)NULL); 778 assert(*a_separators != '\0'); 779 780 /* simple case: input string is null; return empty string */ 781 782 a_string = *r_string; 783 if (*a_string == '\0') { 784 return; 785 } 786 787 /* simple case: token == input string; return empty string */ 788 789 if (streq(a_string, a_token)) { 790 /* deallocate input string; free sets *r_string to NULL */ 791 792 free(*r_string); 793 *r_string = (char *)NULL; 794 return; 795 } 796 797 /* simple case: token not in input string: return */ 798 799 if (!pkgstrContainsToken(a_string, a_token, a_separators)) { 800 return; 801 } 802 803 /* 804 * Pick apart the old string building the new one as we go along 805 * removing the first occurance of the token provided 806 */ 807 808 copyLength = (strlen(a_string)-strlen(a_token))+2; 809 copyString = calloc(1, copyLength); 810 assert(copyString != (char *)NULL); 811 if (copyString == (char *)NULL) { 812 return; 813 } 814 815 for (i = 0; ; i++) { 816 char *p; 817 818 p = pkgstrGetToken(&sep, a_string, i, a_separators); 819 if (p == (char *)NULL) { 820 break; 821 } 822 823 if (streq(p, a_token) && (a_index-- == 0)) { 824 continue; 825 } 826 827 if (*copyString) { 828 assert(sep != '\0'); 829 (void) strncat(copyString, &sep, 1); 830 } 831 832 (void) strcat(copyString, p); 833 } 834 835 free(*r_string); 836 assert(*copyString); 837 *r_string = copyString; 838 } 839 840 /* 841 * Name: pkgstrScaleNumericString 842 * Synopsis: Convert unsigned long long to human readable form 843 * Description: Convert a string containing an unsigned long long representation 844 * and convert it into a human readable numeric string. The number 845 * is scaled down until it is small enough to be in a good human 846 * readable format i.e. in the range 0 thru scale-1. 847 * Arguments: a_buf - [RO, *RW] - (char *) 848 * Pointer to buffer containing string representation 849 * of unsigned long long to convert 850 * scale - [RO, *RO] - (unsigned long long) 851 * Value to scale the number into 852 * Returns: a_buf - contains human readable scaled representation of 853 * original value contained in the buffer 854 * Note: The value "(unsigned long long)-1" is a special case and 855 * is always converted to "-1". 856 * Errors: If the string cannot be created, the process exits 857 */ 858 859 void 860 pkgstrScaleNumericString(char *a_buf, unsigned long long scale) 861 { 862 static char *M = " KMGTPE"; /* Measurement: */ 863 /* kilo, mega, giga, tera, peta, exa */ 864 865 unsigned long long number = 0; /* convert this number */ 866 unsigned long long save = 0; 867 char *uom = M; /* unit of measurement, initially ' ' (=M[0]) */ 868 869 /* entry assertions */ 870 871 assert(scale > (unsigned long long)0); 872 assert(scale <= (unsigned long long)1048576); 873 874 /* 875 * Get the number - if no number of empty number, just return 876 */ 877 878 if (a_buf == (char *)NULL) { 879 return; 880 } 881 882 if (*a_buf == '\0') { 883 (void) strcpy(a_buf, "0"); 884 return; 885 } 886 887 /* convert out the number from the input buffer */ 888 889 number = strtoull(a_buf, (char **)NULL, 10); 890 891 /* if conversion error, return "-1" */ 892 893 if ((long long)number == (long long)-1) { 894 (void) strcpy(a_buf, "-1"); 895 return; 896 } 897 898 /* 899 * Now have number as a count of scale units. 900 * Stop scaling when we reached exa-bytes, then something is 901 * probably wrong with our number (it is improbably large) 902 */ 903 904 while ((number >= scale) && (*uom != 'E')) { 905 uom++; /* next unit of measurement */ 906 save = number; 907 number = (number + (scale / 2)) / scale; 908 } 909 910 /* check if we should output a decimal place after the point */ 911 912 if (save && ((save / scale) < 10)) { 913 /* sprintf() will round for us */ 914 float fnum = (float)save / scale; 915 (void) sprintf(a_buf, "%4.1f%c", fnum, *uom); 916 } else { 917 (void) sprintf(a_buf, "%4llu%c", number, *uom); 918 } 919 } 920 921 /* 922 * Name: pkgstrLocatePathBasename 923 * Synopsis: Locate position of base name in path string 924 * Description: Locate the base name (last path item) in a path and 925 * return a pointer to the first byte of the base name 926 * within the given path 927 * Arguments: a_path - [RO, *RO] - (char *) 928 * - Pointer to string representing path to scan 929 * Returns: char * 930 * - Pointer into string of first byte of path base name 931 * - == (char *)NULL - input path is (char *)NULL 932 */ 933 934 char * 935 pkgstrLocatePathBasename(char *a_path) 936 { 937 char *p; 938 939 /* if path is NULL, return NULL */ 940 941 if (!a_path) { 942 return (a_path); 943 } 944 945 /* locate last occurance of '/' in path */ 946 947 p = strrchr(a_path, '/'); 948 if (p != (char *)NULL) { 949 /* base name located - return -> first byte */ 950 return (p+1); 951 } 952 953 /* no occurance of '/' - entry path must be basename */ 954 955 return (a_path); 956 } 957 958 /* 959 * Name: pkgstrConvertPathToBasename 960 * Synopsis: Return copy of base name in path string 961 * Description: Locate the base name (last path item) in a path and 962 * return a copy of the base name in allocated storage 963 * Arguments: a_path - [RO, *RO] - (char *) 964 * - Pointer to string representing path to scan 965 * Returns: char * 966 * - String containing path base name 967 * - == (char *)NULL - input path is (char *)NULL 968 * NOTE: Any string returned is placed in new storage for the 969 * calling method. The caller must use 'free' to dispose 970 * of the storage once the string is no longer needed. 971 * Errors: If the string cannot be created, the process exits 972 */ 973 974 char * 975 pkgstrConvertPathToBasename(char *a_path) 976 { 977 char *p; 978 979 /* if path is NULL, return NULL */ 980 981 if (a_path == (char *)NULL) { 982 return ((char *)NULL); 983 } 984 985 /* if path is empty (zero length), return NULL */ 986 987 if (*a_path == '\0') { 988 return ((char *)NULL); 989 } 990 991 /* locate last occurance of '/' in path */ 992 993 p = strrchr(a_path, '/'); 994 if (p == (char *)NULL) { 995 /* no occurance of '/' - entry path must be basename */ 996 997 return (strdup(a_path)); 998 } 999 1000 /* base name located - return string from -> first byte */ 1001 1002 return (strdup(p+1)); 1003 } 1004 1005 /* 1006 * Name: pkgstrConvertPathToDirname 1007 * Synopsis: Return copy of directory in path string 1008 * Description: Locate the directory name (everything but last path item) in a 1009 * path and return a copy of the dir name in allocated storage 1010 * Arguments: a_path - [RO, *RO] - (char *) 1011 * - Pointer to string representing path to scan 1012 * Returns: char * 1013 * - String containing path directory name 1014 * - == (char *)NULL - input path is (char *)NULL, 1015 * or a_path is empty (*a_path == '\0'), or the 1016 * a_path has no directory name in it. 1017 * NOTE: Any string returned is placed in new storage for the 1018 * calling method. The caller must use 'free' to dispose 1019 * of the storage once the string is no longer needed. 1020 * Errors: If the string cannot be created, the process exits 1021 */ 1022 1023 char * 1024 pkgstrConvertPathToDirname(char *a_path) 1025 { 1026 char *p; 1027 char *retPath; 1028 1029 /* if path is NULL, return NULL */ 1030 1031 if (a_path == (char *)NULL) { 1032 return ((char *)NULL); 1033 } 1034 1035 /* if path is empty (zero length), return NULL */ 1036 1037 if (*a_path == '\0') { 1038 return ((char *)NULL); 1039 } 1040 1041 /* locate last occurance of '/' in path */ 1042 1043 p = strrchr(a_path, '/'); 1044 if (p == (char *)NULL) { 1045 /* no occurance of '/' - entire path must be basename */ 1046 1047 return ((char *)NULL); 1048 } 1049 1050 /* duplicate original path */ 1051 1052 retPath = strdup(a_path); 1053 assert(retPath != (char *)NULL); 1054 if (retPath == (char *)NULL) { 1055 return ((char *)NULL); 1056 } 1057 1058 /* remove all trailing '/'s from copy of path */ 1059 1060 for (p = strrchr(retPath, '/'); (p > retPath) && (*p == '/'); p--) { 1061 *p = '\0'; 1062 } 1063 1064 /* if entire path was '/'s, return null string - no directory present */ 1065 1066 if (*retPath == '\0') { 1067 free(retPath); 1068 return ((char *)NULL); 1069 } 1070 1071 /* path has at least one non-'/' in it - return -> directory portion */ 1072 1073 return (retPath); 1074 } 1075 1076 /* 1077 * Name: pkgstrConvertUllToTimeString_r 1078 * Synopsis: Convert an unsigned long long into a "time string" 1079 * Description: Given an unsigned long long, return a "time string" which is a 1080 * conversion of the unsigned long long interpreted as a number of 1081 * nanoseconds into a "hour:minute:second.ns" ascii string 1082 * Arguments: a_time - [RO, *RO] - (unsigned long long)n 1083 * - value to convert 1084 * a_buf - [RO, *RW] - (char *) 1085 * - Pointer to buffer used as storage space for the 1086 * returned string 1087 * a_bufLen - [RO, *RO] - (int) 1088 * - Size of 'a_buf' in bytes - a maximum of 'a_bufLen-1' 1089 * bytes will be placed in 'a_buf' 1090 * Returns: char * 1091 * - String containing converted value 1092 * NOTE: Any string returned is placed in new storage for the 1093 * calling method. The caller must use 'free' to dispose 1094 * of the storage once the string is no longer needed. 1095 * Errors: If the string cannot be created, the process exits 1096 */ 1097 1098 void 1099 pkgstrConvertUllToTimeString_r(unsigned long long a_time, 1100 char *a_buf, int a_bufLen) 1101 { 1102 unsigned long long seconds; 1103 unsigned long long minutes; 1104 unsigned long long hours; 1105 unsigned long long ns; 1106 1107 /* entry assertions */ 1108 1109 assert(a_buf != (char *)NULL); 1110 assert(a_bufLen > 0); 1111 1112 /* if time is 0, return immediate result */ 1113 1114 if (a_time == 0) { 1115 pkgstrPrintf_r(a_buf, a_bufLen, "%s", "0:00:00.000000000"); 1116 return; 1117 } 1118 1119 /* break out individual time components */ 1120 1121 ns = a_time % 1000000000ll; /* nanoseconds left over from seconds */ 1122 seconds = a_time / 1000000000ll; /* total seconds */ 1123 minutes = seconds / 60ll; /* total minutes */ 1124 seconds = seconds % 60ll; /* seconds left over from minutes */ 1125 hours = minutes / 60ll; /* total hours */ 1126 minutes = minutes % 60ll; /* minutes left over from hours */ 1127 1128 /* return a converted string */ 1129 1130 pkgstrPrintf_r(a_buf, a_bufLen, "%llu:%02llu:%02llu.%09llu", 1131 hours, minutes, seconds, ns); 1132 } 1133