From: darcy@druid.uucp (D'Arcy J.M. Cain)
Subject: Re: strtok
Date: Tue, 5 Jan 1993 12:34:30 GMT
Distribution: usa
Organization: D'Arcy Cain Consulting

paul@hal.COM (Paul Sander) writes:
>Robert Osborne posted a strtok replacement to comp.lang.c on September 12,
>1991 that returns strtok's global state in a parameter to the caller, making
>it reentrant.  The message-ID is 1395@isgtec.UUCP, and I have copies of it
>if anyone is interested.

Here's one I wrote based on Henry Spencer's strtok code.  I had to change
the name since the semantics are completely different than the standard.

/*
 * xstrtok.c
 * Written by D'Arcy J.M. Cain
 * based on code by Henry Spencer
 * modified to assume an ANSI compiler by D'Arcy J.M. Cain
 * because strtok is a little brain dead about multiple calls
 * this is a modified version which carries the pertinent information
 * in a structure.  This allows more than one string to be parsed
 * at the same time (the code is re-entrant.)
 *
 * Get next token from string x->s (NULL on 2nd, 3rd, etc. calls),
 * where tokens are nonempty strings separated by runs of
 * chars from delim.  Writes NULs into s to end tokens.  delim need not
 * remain constant from call to call.   If quote is set then quotes (single
 * or double) are respected.
 *
 * structure in string.h should look like this:
 * typedef struct {
 *	char		*scanpoint;		/ * filled in by xstrtok * /
 *	char		*str2parse;		/ * string to parse - set for first call * /
 *	const char	*delim;			/ * string of delimiters * /
 *	int			quote;			/ * respect quoting if set * /
 * } XSTRTOK;
 */

#include	<string.h>

char	*xstrtok(XSTRTOK *xinfo)
{
	char		*scan;
	char		*tok;
	char		qchar = 0;
	const char	*dscan;

	/* figure out what stage we are at */
	if (xinfo->str2parse == NULL && xinfo->scanpoint == NULL)
		return(NULL);			/* last one went last time */

	if (xinfo->str2parse != NULL)
	{
		scan = xinfo->str2parse;	/* this is the first time */
		xinfo->str2parse = NULL;
	}
	else
		scan = xinfo->scanpoint;	/* we have already started */

	/* Skip leading delimiters.  */
	for (; *scan; scan++)
	{
		for (dscan = xinfo->delim; *dscan; dscan++)
			if (*scan == *dscan)	/* found a delimiter */
				break;				/* from inner loop */

		if (*dscan == '\0')			/* this character not a delimiter */
			break;					/* from outer loop */
	}

	/* are we finished with the line? */
	if (*scan == '\0')
	{
		xinfo->scanpoint = NULL;
		return(NULL);
	}

	/* otherwise we now point to the next token */
	tok = scan;

	/* find the end of the token */
	/* three versions for speedup rather than testing within loop */

	/* first find empty string such as "" */
	if (xinfo->quote && (*tok == '\"' || *tok == '\'') && tok[0] == tok[1])
	{
		*tok = 0;
		xinfo->scanpoint = tok + 2;
		return(tok);
	}

	/* non-empty string respecting quotes */
	if (xinfo->quote) for (; *scan != '\0'; scan++)
	{
		for (dscan = xinfo->delim; *dscan != '\0';)	/* increment is in body */
		{
			/* have we found a delimiter? */
			if (*scan == *dscan++)
			{
				xinfo->scanpoint = scan + 1;	/* point to next character */
				*scan = '\0';				/* terminate the token */
				return(tok);				/* and return it */
			}

			/* is it a quote character */
			if (*scan == '\'' || *scan == '\"')
			{
				qchar = *scan;				/* search for same close quote */
				strcpy(scan, scan + 1);		/* don't return quotes */

				while (*scan && *scan != qchar)
					scan++;

				strcpy(scan, scan + 1);		/* don't return quotes */
			}
		}
	}
	/* normal strtok semantics */
	else for (; *scan != '\0'; scan++)
	{
		for (dscan = xinfo->delim; *dscan != '\0';)	/* increment is in body */
		{
			/* have we found a delimiter? */
			if (*scan == *dscan++)
			{
				xinfo->scanpoint = scan + 1;	/* point to next character */
				*scan = '\0';					/* terminate the token */
				return(tok);					/* and return it */
			}
		}
	}

	/* Reached end of string.  */
	xinfo->scanpoint = NULL;
	return(tok);
}

-- 
D'Arcy J.M. Cain (darcy@druid.com)  |
D'Arcy Cain Consulting              |   There's no government
Toronto, Ontario, Canada            |   like no government!
+1 416 424 2871          DoD#0082   |
Newsgroups: comp.lang.c