1 /* strtokc.c */
2 
3 #include <string.h>
4 #include "Strn.h"
5 
6 char *
7 strtokc(char *parsestr, const char *delims, char **context)
8 {
9 	char *cp;
10 	const char *cp2;
11 	char c, c2;
12 	char *start;
13 
14 	if (parsestr == NULL)
15 		start = *context;
16 	else
17 		start = parsestr;
18 
19 	if ((start == NULL) || (delims == NULL)) {
20 		*context = NULL;
21 		return NULL;
22 	}
23 
24 	/* Eat leading delimiters. */
25 	for (cp = start; ; ) {
26 next1:
27 		c = *cp++;
28 		if (c == '\0') {
29 			/* No more tokens. */
30 			*context = NULL;
31 			return (NULL);
32 		}
33 		for (cp2 = delims; ; ) {
34 			c2 = (char) *cp2++;
35 			if (c2 == '\0') {
36 				/* This character was not a delimiter.
37 				 * The token starts here.
38 				 */
39 				start = cp - 1;
40 				goto starttok;
41 			}
42 			if (c2 == c) {
43 				/* This char was a delimiter. */
44 				/* Skip it, look at next character. */
45 				goto next1;
46 			}
47 		}
48 		/*NOTREACHED*/
49 	}
50 
51 starttok:
52 	for ( ; ; cp++) {
53 		c = *cp;
54 		if (c == '\0') {
55 			/* Token is finished. */
56 			*context = cp;
57 			break;
58 		}
59 		for (cp2 = delims; ; ) {
60 			c2 = (char) *cp2++;
61 			if (c2 == '\0') {
62 				/* This character was not a delimiter.
63 				 * Keep it as part of current token.
64 				 */
65 				break;
66 			}
67 			if (c2 == c) {
68 				/* This char was a delimiter. */
69 				/* End of token. */
70 				*cp++ = '\0';
71 				*context = cp;
72 				return (start);
73 			}
74 		}
75 	}
76 	return (start);
77 }	/* strtokc */
78 
79 
80 
81 
82 /* Same as strtokc, only you specify the destination buffer to write
83  * the token in along with its size.  strntokc will write to the dst
84  * buffer, always nul-terminating it.
85  *
86  * It also returns the length of the token, or zero if there was no
87  * token.  This differs from strtokc, which returns a pointer to the
88  * token or NULL for no token.
89  */
90 
91 int
92 strntokc(char *dstTokenStart, size_t tokenSize, char *parsestr, const char *delims, char **context)
93 {
94 	char *cp;
95 	const char *cp2;
96 	char c, c2;
97 	char *start;
98 	int len;
99 	char *dst, *lim;
100 
101 	dst = dstTokenStart;
102 	lim = dst + tokenSize - 1;		/* Leave room for nul byte. */
103 
104 	if (parsestr == NULL)
105 		start = *context;
106 	else
107 		start = parsestr;
108 
109 	if ((start == NULL) || (delims == NULL)) {
110 		*context = NULL;
111 		goto done;
112 	}
113 
114 	/* Eat leading delimiters. */
115 	for (cp = start; ; ) {
116 next1:
117 		c = *cp++;
118 		if (c == '\0') {
119 			/* No more tokens. */
120 			*context = NULL;
121 			goto done;
122 		}
123 		for (cp2 = delims; ; ) {
124 			c2 = (char) *cp2++;
125 			if (c2 == '\0') {
126 				/* This character was not a delimiter.
127 				 * The token starts here.
128 				 */
129 				start = cp - 1;
130 				if (dst < lim)
131 					*dst++ = c;
132 				goto starttok;
133 			}
134 			if (c2 == c) {
135 				/* This char was a delimiter. */
136 				/* Skip it, look at next character. */
137 				goto next1;
138 			}
139 		}
140 		/*NOTREACHED*/
141 	}
142 
143 starttok:
144 	for ( ; ; cp++) {
145 		c = *cp;
146 		if (c == '\0') {
147 			/* Token is finished. */
148 			*context = cp;
149 			break;
150 		}
151 		for (cp2 = delims; ; ) {
152 			c2 = (char) *cp2++;
153 			if (c2 == '\0') {
154 				/* This character was not a delimiter.
155 				 * Keep it as part of current token.
156 				 */
157 				break;
158 			}
159 			if (c2 == c) {
160 				/* This char was a delimiter. */
161 				/* End of token. */
162 				*cp++ = '\0';
163 				*context = cp;
164 				goto done;
165 			}
166 		}
167 		if (dst < lim)			/* Don't overrun token size. */
168 			*dst++ = c;
169 	}
170 
171 done:
172 	*dst = '\0';
173 	len = (int) (dst - dstTokenStart);	/* Return length of token. */
174 
175 #if (STRN_ZERO_PAD == 1)
176 	/* Pad with zeros. */
177 	for (++dst; dst <= lim; )
178 		*dst++ = 0;
179 #endif	/* STRN_ZERO_PAD */
180 
181 	return (len);
182 }	/* strntokc */
183 
184 
185 
186 
187 #ifdef TESTING_STRTOK
188 #include <stdio.h>
189 
190 void
191 main(int argc, char **argv)
192 {
193 	char buf[256];
194 	int i;
195 	char *t;
196 	char token[8];
197 	int tokenLen;
198 	char *context;
199 
200 	if (argc < 3) {
201 		fprintf(stderr, "Usage: test \"buffer,with,delims\" <delimiters>\n");
202 		exit(1);
203 	}
204 	strcpy(buf, argv[1]);
205 	i = 1;
206 	t = strtok(buf, argv[2]);
207 	if (t == NULL)
208 		exit(0);
209 	do {
210 		printf("strtok %d=[%s] length=%d\n", i, t, (int) strlen(t));
211 		t = strtok(NULL, argv[2]);
212 		++i;
213 	} while (t != NULL);
214 
215 	printf("------------------------------------------------\n");
216 	strcpy(buf, argv[1]);
217 	i = 1;
218 	t = strtokc(buf, argv[2], &context);
219 	if (t == NULL)
220 		exit(0);
221 	do {
222 		printf("strtokc %d=[%s] length=%d\n", i, t, (int) strlen(t));
223 		t = strtokc(NULL, argv[2], &context);
224 		++i;
225 	} while (t != NULL);
226 
227 	printf("------------------------------------------------\n");
228 	strcpy(buf, argv[1]);
229 	i = 1;
230 	tokenLen = strntokc(token, sizeof(token), buf, argv[2], &context);
231 	if (tokenLen <= 0)
232 		exit(0);
233 	do {
234 		printf("strntokc %d=[%s] length=%d\n", i, token, tokenLen);
235 		tokenLen = strntokc(token, sizeof(token), NULL, argv[2], &context);
236 		++i;
237 	} while (tokenLen > 0);
238 	exit(0);
239 }
240 #endif
241