/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Module: pkgstr.c * Synopsis: general string services * Taxonomy: project private * Debug Flag: str * Description: * * This module implements general string utility services * * Public Methods: * * pkgstrAddToken - Add a token to a string * pkgstrContainsToken - Determine if a string contains a specified token * pkgstrConvertPathToBasename - Return copy of base name in path string * pkgstrConvertPathToDirname - Return copy of directory name in path string * pkgstrConvertUllToTimeString_r - convert unsigned long long to time string * pkgstrExpandTokens - Expand tokens from string appending tokens to another * pkgstrGetToken - Get a token from a string * pkgstrGetToken_r - Get a token from a string into a fixed buffer * pkgstrLocatePathBasename - Locate position of base name in path string * pkgstrNumTokens - Determine number of tokens in string * pkgstrPrintf - Create a string from a printf style format and arguments * pkgstrPrintf_r - Create a string from a printf style format and arguments * into a fixed buffer * pkgstrRemoveToken - Remove a token from a string * pkgstrRemoveLeadingWhitespace - remove leading whitespace from string * pkgstrScaleNumericString - Convert unsigned long long to human * readable form */ /* * Unix Includes */ #define __EXTENSIONS__ #include #include #include #include #include #include #include #include #include #include #include #include #include /* * pkglib Includes */ #include "pkglib.h" #include "pkgstrct.h" #include "libintl.h" #include "pkglocale.h" /* * External definitions */ /* * Public methods */ /* * Name: pkgstrRemoveLeadingWhitespace * Synopsis: Remove leading whitespace from string * Description: Remove all leading whitespace characters from a string * Arguments: a_str - [RO, *RW] - (char **) * Pointer to handle to string (in allocated storage) to * remove all leading whitespace from * Returns: void * The input string is modified as follows: * == (char *)NULL: * - input string was (char *)NULL * - input string is all whitespace * != (char *)NULL: * - copy of input string with leading * whitespace removed * CAUTION: The input string must be allocated space (via mem* or * pkgstr* methods) - it must not be a static or inline * character string * NOTE: The input string a_str will be freed with 'free' * if it is all whitespace, or if it contains any leading * whitespace characters * NOTE: Any string returned is placed in new storage for the * calling method. The caller must use 'free' to dispose * of the storage once the string is no longer needed. * Errors: If the string cannot be created, the process exits */ void pkgstrRemoveLeadingWhitespace(char **a_str) { char *o_str; /* entry assertions */ assert(a_str != (char **)NULL); /* if string is null, just return */ if (*a_str == (char *)NULL) { return; } o_str = *a_str; /* if string is empty, deallocate and return NULL */ if (*o_str == '\0') { /* free string - handle is reset to NULL by free */ free(*a_str); *a_str = (char *)NULL; return; } /* if first character is not a space, just return */ if (!isspace(*o_str)) { return; } /* advance past all space characters */ while ((*o_str != '\0') && (isspace(*o_str))) { o_str++; } /* if string was all space characters, deallocate and return NULL */ if (*o_str == '\0') { /* free string - *a_str is reset to NULL by free */ free(*a_str); *a_str = (char *)NULL; return; } /* have non-space/null byte, return dup, deallocate original */ o_str = strdup(o_str); assert(o_str != (char *)NULL); if (o_str != (char *)NULL) { free(*a_str); *a_str = o_str; } } unsigned long pkgstrNumTokens(char *a_string, char *a_separators) { int index; if (a_string == (char *)NULL) { return (0); } if (*a_string == '\0') { return (0); } for (index = 0 ; ; index ++) { char *p; p = pkgstrGetToken((char *)NULL, a_string, index, a_separators); if (p == (char *)NULL) { return (index); } free(p); } } /* * Name: pkgstrPrintf_r * Synopsis: Create string from printf style format and arguments * Description: Call to convert a printf style format and arguments into a * string of characters placed in allocated storage * Arguments: a_buf - [RO, *RW] - (char *) * - Pointer to buffer used as storage space for the * returned string created * a_bufLen - [RO, *RO] - (int) * - Size of 'a_buf' in bytes - a maximum of 'a_bufLen-1' * bytes will be placed in 'a_buf' - the returned * string is always null terminated * a_format - [RO, RO*] (char *) * printf-style format for string to be formatted * VARG_LIST - [RO] (?) * arguments as appropriate to 'format' specified * Returns: void */ /*PRINTFLIKE3*/ void pkgstrPrintf_r(char *a_buf, int a_bufLen, char *a_format, ...) { va_list ap; size_t vres = 0; /* entry assertions */ assert(a_format != (char *)NULL); assert(*a_format != '\0'); assert(a_buf != (char *)NULL); assert(a_bufLen > 1); /* generate the results of the printf conversion */ va_start(ap, a_format); vres = vsnprintf(a_buf, a_bufLen-1, a_format, ap); va_end(ap); assert(vres > 0); assert(vres < a_bufLen); a_buf[a_bufLen-1] = '\0'; } /* * Name: pkgstrPrintf * Synopsis: Create string from printf style format and arguments * Description: Call to convert a printf style format and arguments into a * string of characters placed in allocated storage * Arguments: format - [RO, RO*] (char *) * printf-style format for string to be formatted * VARG_LIST - [RO] (?) * arguments as appropriate to 'format' specified * Returns: char * * A string representing the printf conversion results * NOTE: Any string returned is placed in new storage for the * calling method. The caller must use 'free' to dispose * of the storage once the string is no longer needed. * Errors: If the string cannot be created, the process exits */ /*PRINTFLIKE1*/ char * pkgstrPrintf(char *a_format, ...) { va_list ap; size_t vres = 0; char bfr[1]; char *rstr = (char *)NULL; /* entry assertions */ assert(a_format != (char *)NULL); assert(*a_format != '\0'); /* determine size of the message in bytes */ va_start(ap, a_format); vres = vsnprintf(bfr, 1, a_format, ap); va_end(ap); assert(vres > 0); assert(vres < LINE_MAX); /* allocate storage to hold the message */ rstr = (char *)calloc(1, vres+2); assert(rstr != (char *)NULL); if (rstr == (char *)NULL) { return ((char *)NULL); } /* generate the results of the printf conversion */ va_start(ap, a_format); vres = vsnprintf(rstr, vres+1, a_format, ap); va_end(ap); assert(vres > 0); assert(vres < LINE_MAX); assert(*rstr != '\0'); /* return the results */ return (rstr); } /* * Name: pkgstrExpandTokens * Synopsis: Expand tokens from string appending tokens to another * Description: Given a string and a list of one or more separators, * expand each token from the string and append those tokens * to a string that is in allocated space - create new string * if no string to append to exists. * Arguments: a_old - [RO, *RW] - (char **) * - Pointer to handle to string to append token to * == (char *)NULL - new string is created * a_separator - [RO, *RO] - (char *) * - separator to end tokens returned * a_separators - [RO, *RO] - (char *) * - String containing one or more characters that * can separate one "token" from a_string from another * Returns: void * NOTE: Any token string returned is placed in new storage for the * calling method. The caller must use 'free' to dispose * of the storage once the token string is no longer needed. */ void pkgstrExpandTokens(char **a_old, char *a_string, char a_separator, char *a_separators) { int i; char sep[2] = {'\0', '\0'}; /* convert single separator character into character string */ sep[0] = a_separator; /* * iterate extracting tokens from the source string and adding * those tokens to the target string when the tokens are not * already present in the target string */ for (i = 0; ; i++) { char *p; /* extract the next matching token from the source string */ p = pkgstrGetToken((char *)NULL, a_string, i, a_separators); /* return if no token is available */ if (p == (char *)NULL) { return; } /* * obtained token from source string: if the token is not * in the target string, add the token to the target string */ if (pkgstrContainsToken(*a_old, p, sep) == B_FALSE) { pkgstrAddToken(a_old, p, *sep); } /* free up temporary storage used by token from source string */ free(p); } /*NOTREACHED*/ } /* * Name: pkgstrGetToken * Synopsis: Get a separator delimited token from a string * Description: Given a string and a list of one or more separators, * return the position specified token (sequence of one or * more characters that do not include any of the separators) * Arguments: r_sep - [*RW] - (char *) * - separator that ended the token returned * - NOTE: this is a pointer to a "char", e.g.: * - char a; * - pkgstrGetToken(&a, ...) * a_string - [RO, *RO] - (char *) * - pointer to string to extract token from * a_index - [RO, *RO] - (int) * - Index of token to return; '0' is first matching * token, '1' is second matching token, etc. * a_separators - [RO, *RO] - (char *) * - String containing one or more characters that * can separate one "token" from another * Returns: char * * == (char *)NULL - no token matching criteria found * != (char *)NULL - token matching criteria * NOTE: Any token string returned is placed in new storage for the * calling method. The caller must use 'free' to dispose * of the storage once the token string is no longer needed. */ char * pkgstrGetToken(char *r_sep, char *a_string, int a_index, char *a_separators) { char *p; char *q; char *lasts; /* entry assertions */ assert(a_string != (char *)NULL); assert(a_index >= 0); assert(a_separators != (char *)NULL); assert(*a_separators != '\0'); /* if returned separator requested, reset to null until token found */ if (r_sep != (char *)NULL) { *r_sep = '\0'; } /* duplicate original string before breaking down into tokens */ p = strdup(a_string); assert(p != (char *)NULL); if (p == (char *)NULL) { return ((char *)NULL); } lasts = p; /* scan for separators and return 'index'th token found */ while (q = strtok_r((char *)NULL, a_separators, &lasts)) { /* retrieve separator if requested */ if (r_sep != (char *)NULL) { char *x; x = strpbrk(a_string, a_separators); if (x) { *r_sep = *x; } } /* if this is the 'index'th token requested return it */ if (a_index-- == 0) { char *tmp; /* duplicate token into its own storage */ tmp = strdup(q); assert(tmp != (char *)NULL); if (tmp == (char *)NULL) { return ((char *)NULL); } /* free up copy of original input string */ free(p); /* return token found */ return (tmp); } } /* * token not found */ /* free up copy of original input string */ free(p); /* return NULL pointer (token not found) */ return ((char *)NULL); } /* * Name: pkgstrGetToken * Synopsis: Get separator delimited token from a string into a fixed buffer * Description: Given a string and a list of one or more separators, * return the position specified token (sequence of one or * more characters that do not include any of the separators) * into a specified buffer of a fixed maximum size * Arguments: r_sep - [*RW] - (char *) * - separator that ended the token returned * - NOTE: this is a pointer to a "char", e.g.: * - char a; * - pkgstrGetToken(&a, ...) * a_string - [RO, *RO] - (char *) * - pointer to string to extract token from * a_index - [RO, *RO] - (int) * - Index of token to return; '0' is first matching * token, '1' is second matching token, etc. * a_separators - [RO, *RO] - (char *) * - String containing one or more characters that * can separate one "token" from another * a_buf - [RO, *RW] - (char *) * - Pointer to buffer used as storage space for the * returned token - the returned token is always * null terminated * a_buf[0] == '\0' - no token meeting criteria found * a_buf[0] != '\0' - token meeting criteria returned * a_bufLen - [RO, *RO] - (int) * - Size of 'a_buf' in bytes - a maximum of 'a_bufLen-1' * bytes will be placed in 'a_buf' - the returned * token is always null terminated * Returns: void */ void pkgstrGetToken_r(char *r_sep, char *a_string, int a_index, char *a_separators, char *a_buf, int a_bufLen) { char *p; char *q; char *lasts; /* entry assertions */ assert(a_string != (char *)NULL); assert(a_index >= 0); assert(a_separators != (char *)NULL); assert(*a_separators != '\0'); assert(a_buf != (char *)NULL); assert(a_bufLen > 0); /* reset returned separator */ if (r_sep != (char *)NULL) { *r_sep = '\0'; } /* zero out contents of return buffer */ bzero(a_buf, a_bufLen); /* duplicate original string before breaking down into tokens */ p = strdup(a_string); assert(p != (char *)NULL); if (p == (char *)NULL) { return; } lasts = p; /* scan for separators and return 'index'th token found */ while (q = strtok_r((char *)NULL, a_separators, &lasts)) { /* retrieve separator if requested */ if (r_sep != (char *)NULL) { char *x; x = strpbrk(a_string, a_separators); if (x) { *r_sep = *x; } } /* if this is the 'index'th token requested return it */ if (a_index-- == 0) { /* copy as many characters as possible to return buf */ (void) strncpy(a_buf, q, a_bufLen-1); break; } } /* free up copy of original input string */ free(p); } /* * Name: pkgstrAddToken * Synopsis: Add a token to a string * Description: Append a token (sequence of one or more characters) to a * string that is in allocated space - create new string if * no string to append to exists * Arguments: a_old - [RO, *RW] - (char **) * - Pointer to handle to string to append token to * == (char *)NULL - new string is created * a_new - [RO, *RO] - (char *) * - Pointer to string representing token to append * to the end of the "a_old" string * == (char *)NULL - no action is performed * a_new[0] == '\0' - no action is performed * a_separator - [RO, *RO] - (char) * - One character placed between the old (existing) * string and the new token to be added IF the old * string exists and is not empty (zero length) * Returns: void * CAUTION: The old (existing) string must be allocated space (via lu_mem* * or pkgstr* methods) - it must not be a static or inline * character string * NOTE: The old (existing) string may be freed with 'free' * if a token is appended to it * NOTE: Any string returned in 'a_old' is placed in new storage for the * calling method. The caller must use 'free' to dispose * of the storage once the token string is no longer needed. */ void pkgstrAddToken(char **a_old, char *a_new, char a_separator) { /* entry assertions */ assert(a_old != (char **)NULL); assert(a_separator != '\0'); /* if token to add is null, just return */ if (a_new == (char *)NULL) { return; } /* if token to add is empty (zero length), just return */ if (*a_new == '\0') { return; } /* make sure that new token does not contain the separator */ assert(strchr(a_new, (int)a_separator) == (char *)NULL); /* if old string is empty (zero length), deallocate */ if ((*a_old != (char *)NULL) && ((*a_old)[0] == '\0')) { /* *a_old is set to NULL by free */ free(*a_old); *a_old = (char *)NULL; } /* if old string is exists, append separator and token */ if (*a_old != (char *)NULL) { char *p; p = pkgstrPrintf("%s%c%s", *a_old, a_separator, a_new); free(*a_old); *a_old = p; return; } /* old string does not exist - return duplicate of token */ assert(*a_old == (char *)NULL); *a_old = strdup(a_new); assert(*a_old != (char *)NULL); } /* * Name: pkgstrContainsToken * Synopsis: Does a given string contain a specified substring * Description: Determine if a given substring exists in a larger string * Arguments: a_string - [RO, *RO] - (char *) * Pointer to string to look for substring in * a_token - [RO, *RO] - (char *) * Pointer to substring to look for in larger string * Results: boolean_t * B_TRUE - substring exists in larger string * B_FALSE - substring does NOT exist in larger string * NOTE: The substring must match on a "token" basis; that is, the * substring must exist in the larger string delineated with * either spaces or tabs to match. */ boolean_t pkgstrContainsToken(char *a_string, char *a_token, char *a_separators) { char *lasts; char *current; char *p; /* entry assertions */ assert(a_separators != (char *)NULL); assert(*a_separators != '\0'); /* if token is not supplied, return false */ if (a_token == (char *)NULL) { return (B_FALSE); } /* if no string provided, return false */ if (a_string == (char *)NULL) { return (B_FALSE); } /* if string empty (zero length), return false */ if (*a_string == '\0') { return (B_FALSE); } /* duplicate larger string because strtok_r changes it */ p = strdup(a_string); assert(p != (char *)NULL); if (p == (char *)NULL) { return (B_FALSE); } lasts = p; /* scan each token looking for a match */ while ((current = strtok_r((char *)NULL, a_separators, &lasts)) != (char *)NULL) { if (streq(current, a_token)) { free(p); return (B_TRUE); } } /* free up temporary storage */ free(p); /* not found */ return (B_FALSE); } /* * Name: pkgstrRemoveToken * Synopsis: Remove a token from a string * Description: Remove a token (sequence of one or more characters) from a * string that is in allocated space * Arguments: r_string - [RO, *RW] - (char **) * - Pointer to handle to string to remove token from * a_token - [RO, *RO] - (char *) * Pointer to token (substring) to look for and remove * from r_string provided * a_separators - [RO, *RO] - (char *) * - String containing one or more characters that * separate one "token" from another in r_string * a_index - [RO, *RO] - (int) * - Index of token to remove; '0' is first matching * token, '1' is second matching token, etc. * Returns: void * CAUTION: The input string must be allocated space (via lu_mem* or * pkgstr* methods) - it must not be a static or inline * character string * NOTE: The input string r_string will be freed with 'free' * if the token to be removed is found * NOTE: Any token string returned is placed in new storage for the * calling method. The caller must use 'free' to dispose * of the storage once the token string is no longer needed. * Errors: If the new token string cannot be created, the process exits */ void pkgstrRemoveToken(char **r_string, char *a_token, char *a_separators, int a_index) { char *a_string; char *copyString; char sep = 0; int copyLength; int i; /* entry assertions */ assert(r_string != (char **)NULL); assert(a_token != (char *)NULL); assert(*a_token != '\0'); assert(a_separators != (char *)NULL); assert(*a_separators != '\0'); /* simple case: input string is null; return empty string */ a_string = *r_string; if (*a_string == '\0') { return; } /* simple case: token == input string; return empty string */ if (streq(a_string, a_token)) { /* deallocate input string; free sets *r_string to NULL */ free(*r_string); *r_string = (char *)NULL; return; } /* simple case: token not in input string: return */ if (!pkgstrContainsToken(a_string, a_token, a_separators)) { return; } /* * Pick apart the old string building the new one as we go along * removing the first occurance of the token provided */ copyLength = (strlen(a_string)-strlen(a_token))+2; copyString = calloc(1, copyLength); assert(copyString != (char *)NULL); if (copyString == (char *)NULL) { return; } for (i = 0; ; i++) { char *p; p = pkgstrGetToken(&sep, a_string, i, a_separators); if (p == (char *)NULL) { break; } if (streq(p, a_token) && (a_index-- == 0)) { continue; } if (*copyString) { assert(sep != '\0'); (void) strncat(copyString, &sep, 1); } (void) strcat(copyString, p); } free(*r_string); assert(*copyString); *r_string = copyString; } /* * Name: pkgstrScaleNumericString * Synopsis: Convert unsigned long long to human readable form * Description: Convert a string containing an unsigned long long representation * and convert it into a human readable numeric string. The number * is scaled down until it is small enough to be in a good human * readable format i.e. in the range 0 thru scale-1. * Arguments: a_buf - [RO, *RW] - (char *) * Pointer to buffer containing string representation * of unsigned long long to convert * scale - [RO, *RO] - (unsigned long long) * Value to scale the number into * Returns: a_buf - contains human readable scaled representation of * original value contained in the buffer * Note: The value "(unsigned long long)-1" is a special case and * is always converted to "-1". * Errors: If the string cannot be created, the process exits */ void pkgstrScaleNumericString(char *a_buf, unsigned long long scale) { static char *M = " KMGTPE"; /* Measurement: */ /* kilo, mega, giga, tera, peta, exa */ unsigned long long number = 0; /* convert this number */ unsigned long long save = 0; char *uom = M; /* unit of measurement, initially ' ' (=M[0]) */ /* entry assertions */ assert(scale > (unsigned long long)0); assert(scale <= (unsigned long long)1048576); /* * Get the number - if no number of empty number, just return */ if (a_buf == (char *)NULL) { return; } if (*a_buf == '\0') { (void) strcpy(a_buf, "0"); return; } /* convert out the number from the input buffer */ number = strtoull(a_buf, (char **)NULL, 10); /* if conversion error, return "-1" */ if ((long long)number == (long long)-1) { (void) strcpy(a_buf, "-1"); return; } /* * Now have number as a count of scale units. * Stop scaling when we reached exa-bytes, then something is * probably wrong with our number (it is improbably large) */ while ((number >= scale) && (*uom != 'E')) { uom++; /* next unit of measurement */ save = number; number = (number + (scale / 2)) / scale; } /* check if we should output a decimal place after the point */ if (save && ((save / scale) < 10)) { /* sprintf() will round for us */ float fnum = (float)save / scale; (void) sprintf(a_buf, "%4.1f%c", fnum, *uom); } else { (void) sprintf(a_buf, "%4llu%c", number, *uom); } } /* * Name: pkgstrLocatePathBasename * Synopsis: Locate position of base name in path string * Description: Locate the base name (last path item) in a path and * return a pointer to the first byte of the base name * within the given path * Arguments: a_path - [RO, *RO] - (char *) * - Pointer to string representing path to scan * Returns: char * * - Pointer into string of first byte of path base name * - == (char *)NULL - input path is (char *)NULL */ char * pkgstrLocatePathBasename(char *a_path) { char *p; /* if path is NULL, return NULL */ if (!a_path) { return (a_path); } /* locate last occurance of '/' in path */ p = strrchr(a_path, '/'); if (p != (char *)NULL) { /* base name located - return -> first byte */ return (p+1); } /* no occurance of '/' - entry path must be basename */ return (a_path); } /* * Name: pkgstrConvertPathToBasename * Synopsis: Return copy of base name in path string * Description: Locate the base name (last path item) in a path and * return a copy of the base name in allocated storage * Arguments: a_path - [RO, *RO] - (char *) * - Pointer to string representing path to scan * Returns: char * * - String containing path base name * - == (char *)NULL - input path is (char *)NULL * NOTE: Any string returned is placed in new storage for the * calling method. The caller must use 'free' to dispose * of the storage once the string is no longer needed. * Errors: If the string cannot be created, the process exits */ char * pkgstrConvertPathToBasename(char *a_path) { char *p; /* if path is NULL, return NULL */ if (a_path == (char *)NULL) { return ((char *)NULL); } /* if path is empty (zero length), return NULL */ if (*a_path == '\0') { return ((char *)NULL); } /* locate last occurance of '/' in path */ p = strrchr(a_path, '/'); if (p == (char *)NULL) { /* no occurance of '/' - entry path must be basename */ return (strdup(a_path)); } /* base name located - return string from -> first byte */ return (strdup(p+1)); } /* * Name: pkgstrConvertPathToDirname * Synopsis: Return copy of directory in path string * Description: Locate the directory name (everything but last path item) in a * path and return a copy of the dir name in allocated storage * Arguments: a_path - [RO, *RO] - (char *) * - Pointer to string representing path to scan * Returns: char * * - String containing path directory name * - == (char *)NULL - input path is (char *)NULL, * or a_path is empty (*a_path == '\0'), or the * a_path has no directory name in it. * NOTE: Any string returned is placed in new storage for the * calling method. The caller must use 'free' to dispose * of the storage once the string is no longer needed. * Errors: If the string cannot be created, the process exits */ char * pkgstrConvertPathToDirname(char *a_path) { char *p; char *retPath; /* if path is NULL, return NULL */ if (a_path == (char *)NULL) { return ((char *)NULL); } /* if path is empty (zero length), return NULL */ if (*a_path == '\0') { return ((char *)NULL); } /* locate last occurance of '/' in path */ p = strrchr(a_path, '/'); if (p == (char *)NULL) { /* no occurance of '/' - entire path must be basename */ return ((char *)NULL); } /* duplicate original path */ retPath = strdup(a_path); assert(retPath != (char *)NULL); if (retPath == (char *)NULL) { return ((char *)NULL); } /* remove all trailing '/'s from copy of path */ for (p = strrchr(retPath, '/'); (p > retPath) && (*p == '/'); p--) { *p = '\0'; } /* if entire path was '/'s, return null string - no directory present */ if (*retPath == '\0') { free(retPath); return ((char *)NULL); } /* path has at least one non-'/' in it - return -> directory portion */ return (retPath); } /* * Name: pkgstrConvertUllToTimeString_r * Synopsis: Convert an unsigned long long into a "time string" * Description: Given an unsigned long long, return a "time string" which is a * conversion of the unsigned long long interpreted as a number of * nanoseconds into a "hour:minute:second.ns" ascii string * Arguments: a_time - [RO, *RO] - (unsigned long long)n * - value to convert * a_buf - [RO, *RW] - (char *) * - Pointer to buffer used as storage space for the * returned string * a_bufLen - [RO, *RO] - (int) * - Size of 'a_buf' in bytes - a maximum of 'a_bufLen-1' * bytes will be placed in 'a_buf' * Returns: char * * - String containing converted value * NOTE: Any string returned is placed in new storage for the * calling method. The caller must use 'free' to dispose * of the storage once the string is no longer needed. * Errors: If the string cannot be created, the process exits */ void pkgstrConvertUllToTimeString_r(unsigned long long a_time, char *a_buf, int a_bufLen) { unsigned long long seconds; unsigned long long minutes; unsigned long long hours; unsigned long long ns; /* entry assertions */ assert(a_buf != (char *)NULL); assert(a_bufLen > 0); /* if time is 0, return immediate result */ if (a_time == 0) { pkgstrPrintf_r(a_buf, a_bufLen, "%s", "0:00:00.000000000"); return; } /* break out individual time components */ ns = a_time % 1000000000ll; /* nanoseconds left over from seconds */ seconds = a_time / 1000000000ll; /* total seconds */ minutes = seconds / 60ll; /* total minutes */ seconds = seconds % 60ll; /* seconds left over from minutes */ hours = minutes / 60ll; /* total hours */ minutes = minutes % 60ll; /* minutes left over from hours */ /* return a converted string */ pkgstrPrintf_r(a_buf, a_bufLen, "%llu:%02llu:%02llu.%09llu", hours, minutes, seconds, ns); }