CBFalconer <> writes:
> Pilcrow wrote:
>>
>> Here is a quick program, together with its output, that illustrates
>> what I consider to be a deficiency of the standard function strtok
>> from <string.h>:
>
> Here is my solution to that problem.
>
> /* ------- file tknsplit.h ----------*/
> #ifndef H_tknsplit_h
> # define H_tknsplit_h
>
> # ifdef __cplusplus
> extern "C" {
> # endif
>
> #include <stddef.h>
>
> /* copy over the next tkn from an input string, after
> skipping leading blanks (or other whitespace?). The
> tkn is terminated by the first appearance of tknchar,
> or by the end of the source string.
>
> The caller must supply sufficient space in tkn to
> receive any tkn, Otherwise tkns will be truncated.
>
> Returns: a pointer past the terminating tknchar.
>
> This will happily return an infinity of empty tkns if
> called with src pointing to the end of a string. Tokens
> will never include a copy of tknchar.
>
> released to Public Domain, by C.B. Falconer.
> Published 2006-02-20. Attribution appreciated.
> revised 2007-05-26 (name)
> */
>
> const char *tknsplit(const char *src, /* Source of tkns */
> char tknchar, /* tkn delimiting char */
> char *tkn, /* receiver of parsed tkn */
> size_t lgh); /* length tkn can receive */
> /* not including final '\0' */
>
> # ifdef __cplusplus
> }
> # endif
> #endif
> /* ------- end file tknsplit.h ----------*/
>
> /* ------- file tknsplit.c ----------*/
> #include "tknsplit.h"
>
> /* copy over the next tkn from an input string, after
> skipping leading blanks (or other whitespace?). The
> tkn is terminated by the first appearance of tknchar,
> or by the end of the source string.
>
> The caller must supply sufficient space in tkn to
> receive any tkn, Otherwise tkns will be truncated.
>
> Returns: a pointer past the terminating tknchar.
>
> This will happily return an infinity of empty tkns if
> called with src pointing to the end of a string. Tokens
> will never include a copy of tknchar.
>
> A better name would be "strtkn", except that is reserved
> for the system namespace. Change to that at your risk.
>
> released to Public Domain, by C.B. Falconer.
> Published 2006-02-20. Attribution appreciated.
> Revised 2006-06-13 2007-05-26 (name)
> */
>
> const char *tknsplit(const char *src, /* Source of tkns */
> char tknchar, /* tkn delimiting char */
> char *tkn, /* receiver of parsed tkn */
> size_t lgh) /* length tkn can receive */
> /* not including final '\0' */
> {
> if (src) {
> while (' ' == *src) src++;
>
> while (*src && (tknchar != *src)) {
> if (lgh) {
> *tkn++ = *src;
> --lgh;
> }
> src++;
> }
> if (*src && (tknchar == *src)) src++;
> }
I would replace the function with this more or less for the following
reasons:
Back to front comparisons are used in a minority of code and most people
hate them. And yes I do know "most" is not "all". Naming of variables
seems almost meaningles - lgh is what? it doesnt save much compiling
time to use meaningful names in a publicly released library. Oh and like
other functions assume it is called with meaningful data.
,----
|
|/* remove leading white space */
|while(*source==' ')
| *source++;
|
|/* store string up to next token */
|while(maxLength-- && ((tokenChar = *source++) != endOfTokenChar))
| *savedToken++=tokenChar;
|
|*savedToken='\0';
|
`----
> *tkn = '\0';
> return src;
> } /* tknsplit */
>
> #ifdef TESTING
> #include <stdio.h>
>
> #define ABRsize 6 /* length of acceptable tkn abbreviations */
>
> /* ---------------- */
>
> static void showtkn(int i, char *tok)
> {
> putchar(i + '1'); putchar(':');
> puts(tok);
> } /* showtkn */
>
> /* ---------------- */
>
> int main(void)
> {
> char teststring[] = "This is a test, ,, abbrev, more";
>
> const char *t, *s = teststring;
> int i;
> char tkn[ABRsize + 1];
>
> puts(teststring);
> t = s;
> for (i = 0; i < 4; i++) {
> t = tknsplit(t, ',', tkn, ABRsize);
> showtkn(i, tkn);
> }
>
> puts("\nHow to detect 'no more tkns' while truncating");
> t = s; i = 0;
> while (*t) {
> t = tknsplit(t, ',', tkn, 3);
> showtkn(i, tkn);
> i++;
> }
>
> puts("\nUsing blanks as tkn delimiters");
> t = s; i = 0;
> while (*t) {
> t = tknsplit(t, ' ', tkn, ABRsize);
> showtkn(i, tkn);
> i++;
> }
> return 0;
> } /* main */
>
> #endif
> /* ------- end file tknsplit.c ----------*/
--
|