1 /* Strntok.c */
2 
3 #include <string.h>
4 #include "Strn.h"
5 
6 /* This version of Strtok differs from the regular ANSI strtok in that
7  * an empty token can be returned, and consecutive delimiters are not
8  * ignored like ANSI does.  Example:
9  *
10  * Parse String = ",,mike,gleason,-West Interactive,402-573-1000"
11  * Delimiters = ",-"
12  *
13  * (ANSI strtok:)
14  * strtok 1=[mike] length=4
15  * strtok 2=[gleason] length=7
16  * strtok 3=[West Interactive] length=16
17  * strtok 4=[402] length=3
18  * strtok 5=[573] length=3
19  * strtok 6=[1000] length=4
20  *
21  * (Strtok:)
22  * Strtok 1=[] length=0
23  * Strtok 2=[] length=0
24  * Strtok 3=[mike] length=4
25  * Strtok 4=[gleason] length=7
26  * Strtok 5=[] length=0
27  * Strtok 6=[West Interactive] length=16
28  * Strtok 7=[402] length=3
29  * Strtok 8=[573] length=3
30  * Strtok 9=[1000] length=4
31  *
32  */
33 
34 char *
35 Strtok(char *buf, const char *delims)
36 {
37 	static char *p = NULL;
38 	char *start, *end;
39 
40 	if (buf != NULL) {
41 		p = buf;
42 	} else {
43 		if (p == NULL)
44 			return (NULL);		/* No more tokens. */
45 	}
46 	for (start = p, end = p; ; end++) {
47 		if (*end == '\0') {
48 			p = NULL;		/* This is the last token. */
49 			break;
50 		}
51 		if (strchr(delims, (int) *end) != NULL) {
52 			*end++ = '\0';
53 			p = end;
54 			break;
55 		}
56 	}
57 	return (start);
58 }	/* Strtok */
59 
60 
61 
62 
63 /* This is a bounds-safe version of Strtok, where you also pass a pointer
64  * to the token to write into, and its size.  Using the example above,
65  * with a char token[8], you get the following.  Notice that the token
66  * is not overrun, and is always nul-terminated:
67  *
68  * Strntok 1=[] length=0
69  * Strntok 2=[] length=0
70  * Strntok 3=[mike] length=4
71  * Strntok 4=[gleason] length=7
72  * Strntok 5=[] length=0
73  * Strntok 6=[West In] length=7
74  * Strntok 7=[402] length=3
75  * Strntok 8=[573] length=3
76  * Strntok 9=[1000] length=4
77  */
78 
79 int
80 Strntok(char *dstTokenStart, size_t tokenSize, char *buf, const char *delims)
81 {
82 	static char *p = NULL;
83 	char *end;
84 	char *lim;
85 	char *dst;
86 	int len;
87 
88 	dst = dstTokenStart;
89 	lim = dst + tokenSize - 1;		/* Leave room for nul byte. */
90 
91 	if (buf != NULL) {
92 		p = buf;
93 	} else {
94 		if (p == NULL) {
95 			*dst = '\0';
96 			return (-1);		/* No more tokens. */
97 		}
98 	}
99 
100 	for (end = p; ; end++) {
101 		if (*end == '\0') {
102 			p = NULL;		/* This is the last token. */
103 			break;
104 		}
105 		if (strchr(delims, (int) *end) != NULL) {
106 			++end;
107 			p = end;
108 			break;
109 		}
110 		if (dst < lim)			/* Don't overrun token size. */
111 			*dst++ = *end;
112 	}
113 	*dst = '\0';
114 	len = (int) (dst - dstTokenStart);	/* Return length of token. */
115 
116 #if (STRN_ZERO_PAD == 1)
117 	/* Pad with zeros. */
118 	for (++dst; dst <= lim; )
119 		*dst++ = 0;
120 #endif	/* STRN_ZERO_PAD */
121 
122 	return (len);
123 }	/* Strntok */
124 
125 
126 
127 #ifdef TESTING_STRTOK
128 #include <stdio.h>
129 
130 void
131 main(int argc, char **argv)
132 {
133 	char buf[256];
134 	int i;
135 	char *t;
136 	char token[8];
137 	int tokenLen;
138 
139 	if (argc < 3) {
140 		fprintf(stderr, "Usage: test \"buffer,with,delims\" <delimiters>\n");
141 		exit(1);
142 	}
143 	strcpy(buf, argv[1]);
144 	i = 1;
145 	t = strtok(buf, argv[2]);
146 	if (t == NULL)
147 		exit(0);
148 	do {
149 		printf("strtok %d=[%s] length=%d\n", i, t, (int) strlen(t));
150 		t = strtok(NULL, argv[2]);
151 		++i;
152 	} while (t != NULL);
153 
154 	printf("------------------------------------------------\n");
155 	strcpy(buf, argv[1]);
156 	i = 1;
157 	t = Strtok(buf, argv[2]);
158 	if (t == NULL)
159 		exit(0);
160 	do {
161 		printf("Strtok %d=[%s] length=%d\n", i, t, (int) strlen(t));
162 		t = Strtok(NULL, argv[2]);
163 		++i;
164 	} while (t != NULL);
165 
166 	printf("------------------------------------------------\n");
167 	strcpy(buf, argv[1]);
168 	i = 1;
169 	tokenLen = Strntok(token, sizeof(token), buf, argv[2]);
170 	if (tokenLen < 0)
171 		exit(0);
172 	do {
173 		printf("Strntok %d=[%s] length=%d\n", i, token, tokenLen);
174 		tokenLen = Strntok(token, sizeof(token), NULL, argv[2]);
175 		++i;
176 	} while (tokenLen >= 0);
177 	exit(0);
178 }
179 #endif
180