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
pkgstrRemoveLeadingWhitespace(char ** a_str)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
pkgstrNumTokens(char * a_string,char * a_separators)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
pkgstrPrintf_r(char * a_buf,int a_bufLen,char * a_format,...)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 *
pkgstrPrintf(char * a_format,...)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
pkgstrExpandTokens(char ** a_old,char * a_string,char a_separator,char * a_separators)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 *
pkgstrGetToken(char * r_sep,char * a_string,int a_index,char * a_separators)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
pkgstrGetToken_r(char * r_sep,char * a_string,int a_index,char * a_separators,char * a_buf,int a_bufLen)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
pkgstrAddToken(char ** a_old,char * a_new,char a_separator)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
pkgstrContainsToken(char * a_string,char * a_token,char * a_separators)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
pkgstrRemoveToken(char ** r_string,char * a_token,char * a_separators,int a_index)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
pkgstrScaleNumericString(char * a_buf,unsigned long long scale)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 *
pkgstrLocatePathBasename(char * a_path)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 *
pkgstrConvertPathToBasename(char * a_path)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 *
pkgstrConvertPathToDirname(char * a_path)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
pkgstrConvertUllToTimeString_r(unsigned long long a_time,char * a_buf,int a_bufLen)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