Michael wrote:
> Hi,
>
> I have a proble I don't understand when using strtok(). It seems that if I
> make a call to strtok(), then make a call to another function that also
> makes use of strtok(), the original call is somehow confused or upset.
>
> I have the following code, which I am using to tokenise some input which is
> in th form x
1.2:
>
> int tokenize_input(Sale *sale, char *string){
>
> char *temp;
> int temp_int;
> int result = TRUE;
>
> if((temp = strtok(string, ":")) == NULL){
> result = FALSE;
> } else {
> sale -> sale_id = atoi(temp);
> }
>
> if((temp = strtok('\0',":")) == NULL){
> result = FALSE;
> } else {
> if(get_date(temp)
> > -1){ /* when I added this
> line, my problem started*/
> strncpy(sale -> date, temp, DATE_LENGTH);
> } else
> {
> /*These were added at the same time*/
> result = FALSE;
> /**/
> }
> /**/
> }
>
> if((temp = strtok('\0',".")) ==
> NULL){ /*this now returns NULL*/
> result = FALSE;
> } else {
> temp_int = atoi(temp)*100;
> }
>
> if((temp = strtok('\0',":")) == NULL){
> result = FALSE;
> } else {
> temp_int = temp_int + atoi(temp);
> sale -> price = temp_int;
> }
>
> return result;
> }
>
> get_date() is also using strtok(). It all worked fine until I added the
> marked lines in order to do some validation of input, at which point the
> later strtok() began returning NULL.
>
> Can anyone explain why this would occur and how can get around it?
>
> Thanks for your help
>
> Michael
>
>
>
The strtok() function uses a static char * to maintain the address of
the string it is parsing. If a new initializing call to strtok() is
made you will lose the address of the first string. Over the years I've
written several replacement functions for strtok() (which I believe
should be deprecated). My favorite is something I wrote a few years ago
in another language and ported recently to C. Here it is, so enjoy.
/************************************************** ********************/
/* File Name: gettoken.c. */
/* Author: Stan Milam. */
/* Date Written: 15-Jan-2000. */
/* Description: */
/* Extract and remove a token from a string. Handles empty */
/* tokens. */
/* (c) Copyright 2006 by Stan Milam. */
/* All rights reserved. */
/* */
/************************************************** ********************/
#include <errno.h>
#include <string.h>
#define strzcpy(d,s,l) (strncpy((d), (s), (l))[(l)] = '\0', (d))
/************************************************** ********************/
/* Name: */
/* gettoken(). */
/* */
/* Synopsis: */
/* #include "strtools.h" */
/* char *gettoken( char *dest, char *source, char *delimters ); */
/* */
/* Description: */
/* The gettoken() function will extract tokens seperated by a */
/* specified set of delimiters from a string and store the token */
/* value in the dest argument. Furthermore, the token is removed */
/* from the source string along with the delimiter. Empty token */
/* fields cause the destination vaue to be an empty string. */
/* */
/* Arguments: */
/* char *dest - Address of a buffer where the token will be */
/* stored. */
/* char *source - The address of the string containing one or */
/* more tokens. */
/* char *delimiters - The address of a string of characters used */
/* as token delimiters. */
/* */
/* Return Value: */
/* The gettoken() function will return the address of the */
/* destination argument upon successful completion, and will */
/* return NULL when there no tokens left to extract or any one of */
/* the arguments are a NULL value. Should one of the arguments */
/* be a NULL pointer the global errno variable will be set to */
/* EINVAL. */
/* */
/************************************************** ********************/
char *
gettoken( char *dest, char *source, const char *delimiters )
{
char *rv = NULL;
if ( dest == NULL || source == NULL || delimiters == NULL )
errno = EINVAL;
else {
*dest = '\0';
if ( *source ) {
char *ptr = strpbrk( source, delimiters );
/************************************************** ********/
/* At this point we know we have something, perhaps an */
/* empty token. Default the return value to the */
/* destination address. If the result of strpbrk() is not */
/* NULL and not the same as the source, copy the token */
/* into the destination string. */
/************************************************** ********/
rv = dest;
if ( ptr != NULL ) {
char *tmp = ptr++;
if ( source != tmp )
rv = strzcpy( dest, source, (size_t)(tmp-source) );
}
/************************************************** ************/
/* If there are no delimters the source is the token. */
/************************************************** ************/
else {
rv = strcpy( dest, source );
ptr = (char *) source + strlen( source );
}
/************************************************** ********/
/* Copy the source string down past the token we just */
/* found. */
/************************************************** ********/
memmove( (char *)source, ptr, strlen( ptr ) + 1 );
}
}
return rv;
}
#ifdef TEST
#include <stdio.h>
#include <assert.h>
int
main( void )
{
char dest[100];
char delim[]="|;!";
char a[] = "|B.B. Shagnasty|!Shagnasty, William B.|Billy Bob
Shagnasty|;!";
errno = 0;
assert( gettoken( NULL, a, delim ) == NULL);
assert( errno == EINVAL ); errno = 0;
assert( gettoken( dest, NULL, delim ) == NULL);
assert( errno == EINVAL ); errno = 0;
assert( gettoken( dest, a, NULL ) == NULL );
assert( errno == EINVAL ); errno = 0;
while( gettoken( dest, a, delim ) )
puts( dest );
return 0;
}
#endif
--
Regards,
Stan Milam
================================================== ===========
Charter Member of The Society for Mediocre Guitar Playing on
Expensive Instruments, Ltd.
================================================== ===========