/* * 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: zones_str.c * Group: libinstzones * Description: Private functions used by zones library functions to manipulate * strings * * Public Methods: * * _z_strAddToken - Add a token to a string * _z_strContainsToken - Does a given string contain a specified substring * _z_strGetToken - Get a separator delimited token from a string * _z_strGetToken_r - Get separator delimited token from string to fixed buffer * _z_strPrintf - Create string from printf style format and arguments * _z_strPrintf_r - Create string from printf style format and arguments * _z_strRemoveLeadingWhitespace - Remove leading whitespace from string * _z_strRemoveToken - Remove a token from a string */ /* * System includes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * local includes */ #include "instzones_lib.h" #include "zones_strings.h" /* * Private structures */ /* * Library Function Prototypes */ /* * Local Function Prototypes */ /* * Global internal (private) declarations */ /* * ***************************************************************************** * global external (public) functions * ***************************************************************************** */ /* * Name: _z_strAddToken * 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 * == 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 * == 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 _z_str* 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 _z_strAddToken(char **a_old, char *a_new, char a_separator) { /* entry assertions */ assert(a_old != NULL); assert(a_separator != '\0'); /* if token to add is null or token is zero length, just return */ if (a_new == NULL || *a_new == '\0') { return; } /* make sure that new token does not contain the separator */ assert(strchr(a_new, (int)a_separator) == NULL); /* if old string is empty (zero length), deallocate */ if ((*a_old != NULL) && ((*a_old)[0] == '\0')) { /* *a_old is set to NULL by free */ free(*a_old); *a_old = NULL; } /* if old string exists, append separator and token */ if (*a_old != NULL) { char *p; p = _z_strPrintf("%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 == NULL); *a_old = _z_strdup(a_new); } /* * Name: _z_strContainsToken * 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 _z_strContainsToken(char *a_string, char *a_token, char *a_separators) { char *lasts; char *current; char *p; /* entry assertions */ assert(a_separators != NULL); assert(*a_separators != '\0'); /* * if token is not supplied, no string provided, * or the string is an empty string, return false */ if (a_token == NULL || a_string == NULL || *a_string == '\0') { return (B_FALSE); } /* if no string provided, return false */ /* if string empty (zero length), return false */ /* duplicate larger string because strtok_r changes it */ p = _z_strdup(a_string); lasts = p; /* scan each token looking for a match */ while ((current = strtok_r(NULL, a_separators, &lasts)) != NULL) { if (strcmp(current, a_token) == 0) { free(p); return (B_TRUE); } } /* free up temporary storage */ free(p); /* not found */ return (B_FALSE); } /* * Name: _z_strGetToken * 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; * - _z_strGetToken(&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 * * == NULL - no token matching criteria found * != 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 * _z_strGetToken(char *r_sep, char *a_string, int a_index, char *a_separators) { char *p; char *q; char *lasts; /* entry assertions */ assert(a_string != NULL); assert(a_index >= 0); assert(a_separators != NULL); assert(*a_separators != '\0'); /* if returned separator requested, reset to null until token found */ if (r_sep != NULL) { *r_sep = '\0'; } /* duplicate original string before breaking down into tokens */ p = _z_strdup(a_string); lasts = p; /* scan for separators and return 'index'th token found */ while (q = strtok_r(NULL, a_separators, &lasts)) { /* retrieve separator if requested */ if (r_sep != NULL) { char *x; x = strpbrk(a_string, a_separators); if (x != NULL) { *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 = _z_strdup(q); /* 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 (NULL); } /* * Name: _z_strGetToken_r * 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; * - _z_strGetToken(&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 _z_strGetToken_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 != NULL); assert(a_index >= 0); assert(a_separators != NULL); assert(*a_separators != '\0'); assert(a_buf != NULL); assert(a_bufLen > 0); /* reset returned separator */ if (r_sep != NULL) { *r_sep = '\0'; } /* zero out contents of return buffer */ bzero(a_buf, a_bufLen); /* duplicate original string before breaking down into tokens */ p = _z_strdup(a_string); lasts = p; /* scan for separators and return 'index'th token found */ while (q = strtok_r(NULL, a_separators, &lasts)) { /* retrieve separator if requested */ if (r_sep != NULL) { char *x; x = strpbrk(a_string, a_separators); if (x != NULL) { *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: _z_strPrintf * 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 * _z_strPrintf(char *a_format, ...) { va_list ap; size_t vres = 0; char bfr[1]; char *rstr = NULL; /* entry assertions */ assert(a_format != 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 *)_z_calloc(vres+2); /* 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: _z_strPrintf_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 _z_strPrintf_r(char *a_buf, int a_bufLen, char *a_format, ...) { va_list ap; size_t vres = 0; /* entry assertions */ assert(a_format != NULL); assert(*a_format != '\0'); assert(a_buf != 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: _z_strRemoveLeadingWhitespace * 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: * == NULL: * - input string was NULL * - input string is all whitespace * != NULL: * - copy of input string with leading * whitespace removed * CAUTION: The input string must be allocated space (via mem* or * _z_str* 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 _z_strRemoveLeadingWhitespace(char **a_str) { char *o_str; /* entry assertions */ assert(a_str != NULL); /* if string is null, just return */ if (*a_str == NULL) { return; } o_str = *a_str; /* if string is empty, deallocate and return NULL */ if (*o_str == '\0') { /* free string - handle is not reset to NULL by free */ free(*a_str); *a_str = 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 not reset to NULL by free */ free(*a_str); *a_str = NULL; return; } /* have non-space/null byte, return dup, deallocate original */ free(*a_str); *a_str = _z_strdup(o_str); } /* * Name: _z_strRemoveToken * 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 * _z_str* 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 _z_strRemoveToken(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 != NULL); assert(a_token != NULL); assert(*a_token != '\0'); assert(a_separators != 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 (strcmp(a_string, a_token) == 0) { /* * deallocate input string; free doesn't * set *r_string to NULL */ free(*r_string); *r_string = NULL; return; } /* simple case: token not in input string: return */ if (!_z_strContainsToken(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 = (char *)_z_calloc(copyLength); for (i = 0; ; i++) { char *p; p = _z_strGetToken(&sep, a_string, i, a_separators); if (p == NULL) { break; } if ((strcmp(p, a_token) == 0) && (a_index-- == 0)) { free(p); continue; } if (*copyString) { assert(sep != '\0'); (void) strncat(copyString, &sep, 1); } (void) strcat(copyString, p); free(p); } free(*r_string); assert(*copyString); *r_string = copyString; }