open-cas-linux/casadm/safeclib/strtok_s.c
Robert Baldyga 94e8ca09e0 Initial commit
Signed-off-by: Robert Baldyga <robert.baldyga@intel.com>
2019-03-29 08:45:50 +01:00

324 lines
10 KiB
C

/*------------------------------------------------------------------
* strtok_s.c
*
* October 2008, Bo Berry
*
* Copyright (c) 2008-2011 by Cisco Systems, Inc
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*------------------------------------------------------------------
*/
#include "safeclib_private.h"
#include "safe_str_constraint.h"
#include "safe_str_lib.h"
/**
* NAME
* strtok_s
*
* SYNOPSIS
* #include "safe_str_lib.h"
* char *
* strtok_s(char *dest, rsize_t *dmax, char *src, char **ptr)
*
* DESCRIPTION
* A sequence of calls to the strtok_s function breaks the string
* pointed to by dest into a sequence of tokens, each of which is
* delimited by a character from the string pointed to by src. The
* fourth argument points to a caller-provided char pointer into
* which the strtok_s function stores information necessary for
* it to continue scanning the same string.
*
* The first call in a sequence has a non-null first argument and
* dmax points to an object whose value is the number of elements
* in the character array pointed to by the first argument. The
* first call stores an initial value in the object pointed to by
* ptr and updates the value pointed to by dmax to reflect the
* number of elements that remain in relation to ptr. Subsequent
* calls in the sequence have a null first argument and the objects
* pointed to by dmax and ptr are required to have the values
* stored by the previous call in the sequence, which are then
* updated. The separator string pointed to by src may be different
* from call to call.
*
* The first call in the sequence searches the string pointed to
* by dest for the first character that is not contained in the
* current separator string pointed to by src. If no such character
* is found, then there are no tokens in the string pointed to
* by dest and the strtok_s function returns a null pointer. If
* such a character is found, it is the start of the first token.
*
* The strtok_s function then searches from there for the first
* character in dest that is contained in the current separator
* string. If no such character is found, the current token
* extends to the end of the string pointed to by dest, and
* subsequent searches in the same string for a token return
* a null pointer. If such a character is found, it is
* overwritten by a null character, which terminates the
* current token.
*
* In all cases, the strtok_s function stores sufficient information
* in the pointer pointed to by ptr so that subsequent calls,
* with a null pointer for dest and the unmodified pointer value
* for ptr, shall start searching just past the element overwritten
* by a null character (if any).
*
* SPECIFIED IN
* ISO/IEC TR 24731-1, Programming languages, environments
* and system software interfaces, Extensions to the C Library,
* Part I: Bounds-checking interfaces
*
* INPUT PARAMETERS
* dest pointer to string to tokenize
*
* dmax restricted maximum length of dest string
*
* src pointer to delimiter string (len < 255)
*
* ptr returned pointer to token
*
* OUTPUT PARAMETERS
* dmax update length
*
* ptr update pointer to token
*
* RUNTIME CONSTRAINTS
* src shall not be a null pointer.
* ptr shall not be a null pointer.
* dmax shall not be a null pointer.
* *dmax shall not be 0.
*
* If dest is a null pointer, then *ptr shall not be a null pointer.
*
* dest must not be unterminated.
*
* The value of *dmax shall not be greater than RSIZE_MAX_STR. The
* end of the token found shall occur within the first *dmax
* characters of dest for the first call, and shall occur within
* the first *dmax characters of where searching resumes on
* subsequent calls.
*
* RETURN VALUE
* The strtok_s function returns a pointer to the first character
* of a token; or a null pointer if there is no token or there
* is a runtime-constraint violation.
*
* EOK
* ESNULLP NULL pointer
* ESZEROL zero length
* ESLEMAX length exceeds max limit
* ESUNTERM unterminated string
*
* EXAMPLES
* [1] Sequencial strtok_s() calls to tokenize a string
*
* String to tokenize str1 = ",.:*one,two;three,;four*.*.five-six***"
* len=38
* String of delimiters str2 = ",.;*"
*
* p2tok = strtok_s(str1, &len, str2, &p2str);
* token -one- remaining -two;three,;four*.*.five-six***- len=30
*
* p2tok = strtok_s(NULL, &len, str2, &p2str);
* token -two- remaining -three,;four*.*.five-six***- len=26
*
* p2tok = strtok_s(NULL, &len, str2, &p2str);
* token -three- remaining -;four*.*.five-six***- len=20
*
* p2tok = strtok_s(NULL, &len, str2, &p2str);
* token -four- remaining -.*.five-six***- len=14
*
* p2tok = strtok_s(NULL, &len, str2, &p2str);
* token -five-six- remaining -**- len=2
*
* p2tok = strtok_s(NULL, &len, str2, &p2str);
* token -(null)- remaining -**- len=0
*
*
* [2] While loop with same entry data as [1]
*
* p2tok = str1;
* while (p2tok && len) {
* p2tok = strtok_s(NULL, &len, str2, &p2str);
* printf(" token -- remaining -- len=0 \n",
* p2tok, p2str, (int)len );
* }
*
*-
*/
char *
strtok_s(char *dest, rsize_t *dmax, const char *src, char **ptr)
{
/*
* CONFIGURE: The spec does not call out a maximum for the src
* string, so one is defined here.
*/
#define STRTOK_DELIM_MAX_LEN ( 16 )
const char *pt;
char *ptoken;
rsize_t dlen;
rsize_t slen;
if (dmax == NULL) {
invoke_safe_str_constraint_handler("strtok_s: dmax is NULL",
NULL, ESNULLP);
return (NULL);
}
if (*dmax == 0) {
invoke_safe_str_constraint_handler("strtok_s: dmax is 0",
NULL, ESZEROL);
return (NULL);
}
if (*dmax > RSIZE_MAX_STR) {
invoke_safe_str_constraint_handler("strtok_s: dmax exceeds max",
NULL, ESLEMAX);
return (NULL);
}
if (src == NULL) {
invoke_safe_str_constraint_handler("strtok_s: src is null",
NULL, ESNULLP);
return (NULL);
}
if (ptr == NULL) {
invoke_safe_str_constraint_handler("strtok_s: ptr is null",
NULL, ESNULLP);
return (NULL);
}
/* if the source was NULL, use the tokenizer context */
if (dest == NULL) {
dest = *ptr;
}
/*
* scan dest for a delimiter
*/
dlen = *dmax;
ptoken = NULL;
while (*dest != '\0' && !ptoken) {
if (dlen == 0) {
*ptr = NULL;
invoke_safe_str_constraint_handler(
"strtok_s: dest is unterminated",
NULL, ESUNTERM);
return (NULL);
}
/*
* must scan the entire delimiter list
* ISO should have included a delimiter string limit!!
*/
slen = STRTOK_DELIM_MAX_LEN;
pt = src;
while (*pt != '\0') {
if (slen == 0) {
*ptr = NULL;
invoke_safe_str_constraint_handler(
"strtok_s: src is unterminated",
NULL, ESUNTERM);
return (NULL);
}
slen--;
if (*dest == *pt) {
ptoken = NULL;
break;
} else {
pt++;
ptoken = dest;
}
}
dest++;
dlen--;
}
/*
* if the beginning of a token was not found, then no
* need to continue the scan.
*/
if (ptoken == NULL) {
*dmax = dlen;
return (ptoken);
}
/*
* Now we need to locate the end of the token
*/
while (*dest != '\0') {
if (dlen == 0) {
*ptr = NULL;
invoke_safe_str_constraint_handler(
"strtok_s: dest is unterminated",
NULL, ESUNTERM);
return (NULL);
}
slen = STRTOK_DELIM_MAX_LEN;
pt = src;
while (*pt != '\0') {
if (slen == 0) {
*ptr = NULL;
invoke_safe_str_constraint_handler(
"strtok_s: src is unterminated",
NULL, ESUNTERM);
return (NULL);
}
slen--;
if (*dest == *pt) {
/*
* found a delimiter, set to null
* and return context ptr to next char
*/
*dest = '\0';
*ptr = (dest + 1); /* return pointer for next scan */
*dmax = dlen - 1; /* account for the nulled delimiter */
return (ptoken);
} else {
/*
* simply scanning through the delimiter string
*/
pt++;
}
}
dest++;
dlen--;
}
*dmax = dlen;
return (ptoken);
}