xref: /openbsd-src/regress/lib/libc/regex/split.c (revision 2ed2be6ef3e74cfc0d72db1624a4eb9350fc819e)
1*2ed2be6eSchl /*	$OpenBSD: split.c,v 1.5 2007/09/09 23:25:12 chl Exp $	*/
2df930be7Sderaadt /*	$NetBSD: split.c,v 1.2 1995/04/20 22:39:57 cgd Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt #include <stdio.h>
5df930be7Sderaadt #include <string.h>
6df930be7Sderaadt 
7db3296cfSderaadt int split(char *string, char *fields[], int nfields, char *sep);
8db3296cfSderaadt 
9df930be7Sderaadt /*
10df930be7Sderaadt  - split - divide a string into fields, like awk split()
11df930be7Sderaadt  = int split(char *string, char *fields[], int nfields, char *sep);
12df930be7Sderaadt  */
13df930be7Sderaadt int				/* number of fields, including overflow */
split(char * string,char * fields[],int nfields,char * sep)14db3296cfSderaadt split(char *string, char *fields[], int nfields, char *sep)
15df930be7Sderaadt {
16df930be7Sderaadt 	register char *p = string;
17df930be7Sderaadt 	register char c;			/* latest character */
18df930be7Sderaadt 	register char sepc = sep[0];
19df930be7Sderaadt 	register char sepc2;
20df930be7Sderaadt 	register int fn;
21df930be7Sderaadt 	register char **fp = fields;
22df930be7Sderaadt 	register char *sepp;
23df930be7Sderaadt 	register int trimtrail;
24df930be7Sderaadt 
25df930be7Sderaadt 	/* white space */
26df930be7Sderaadt 	if (sepc == '\0') {
27df930be7Sderaadt 		while ((c = *p++) == ' ' || c == '\t')
28df930be7Sderaadt 			continue;
29df930be7Sderaadt 		p--;
30df930be7Sderaadt 		trimtrail = 1;
31df930be7Sderaadt 		sep = " \t";	/* note, code below knows this is 2 long */
32df930be7Sderaadt 		sepc = ' ';
33df930be7Sderaadt 	} else
34df930be7Sderaadt 		trimtrail = 0;
35df930be7Sderaadt 	sepc2 = sep[1];		/* now we can safely pick this up */
36df930be7Sderaadt 
37df930be7Sderaadt 	/* catch empties */
38df930be7Sderaadt 	if (*p == '\0')
39df930be7Sderaadt 		return(0);
40df930be7Sderaadt 
41df930be7Sderaadt 	/* single separator */
42df930be7Sderaadt 	if (sepc2 == '\0') {
43df930be7Sderaadt 		fn = nfields;
44df930be7Sderaadt 		for (;;) {
45df930be7Sderaadt 			*fp++ = p;
46df930be7Sderaadt 			fn--;
47df930be7Sderaadt 			if (fn == 0)
48df930be7Sderaadt 				break;
49df930be7Sderaadt 			while ((c = *p++) != sepc)
50df930be7Sderaadt 				if (c == '\0')
51df930be7Sderaadt 					return(nfields - fn);
52df930be7Sderaadt 			*(p-1) = '\0';
53df930be7Sderaadt 		}
54df930be7Sderaadt 		/* we have overflowed the fields vector -- just count them */
55df930be7Sderaadt 		fn = nfields;
56df930be7Sderaadt 		for (;;) {
57df930be7Sderaadt 			while ((c = *p++) != sepc)
58df930be7Sderaadt 				if (c == '\0')
59df930be7Sderaadt 					return(fn);
60df930be7Sderaadt 			fn++;
61df930be7Sderaadt 		}
62df930be7Sderaadt 		/* not reached */
63df930be7Sderaadt 	}
64df930be7Sderaadt 
65df930be7Sderaadt 	/* two separators */
66df930be7Sderaadt 	if (sep[2] == '\0') {
67df930be7Sderaadt 		fn = nfields;
68df930be7Sderaadt 		for (;;) {
69df930be7Sderaadt 			*fp++ = p;
70df930be7Sderaadt 			fn--;
71df930be7Sderaadt 			while ((c = *p++) != sepc && c != sepc2)
72df930be7Sderaadt 				if (c == '\0') {
73df930be7Sderaadt 					if (trimtrail && **(fp-1) == '\0')
74df930be7Sderaadt 						fn++;
75df930be7Sderaadt 					return(nfields - fn);
76df930be7Sderaadt 				}
77df930be7Sderaadt 			if (fn == 0)
78df930be7Sderaadt 				break;
79df930be7Sderaadt 			*(p-1) = '\0';
80df930be7Sderaadt 			while ((c = *p++) == sepc || c == sepc2)
81df930be7Sderaadt 				continue;
82df930be7Sderaadt 			p--;
83df930be7Sderaadt 		}
84df930be7Sderaadt 		/* we have overflowed the fields vector -- just count them */
85df930be7Sderaadt 		fn = nfields;
86df930be7Sderaadt 		while (c != '\0') {
87df930be7Sderaadt 			while ((c = *p++) == sepc || c == sepc2)
88df930be7Sderaadt 				continue;
89df930be7Sderaadt 			p--;
90df930be7Sderaadt 			fn++;
91df930be7Sderaadt 			while ((c = *p++) != '\0' && c != sepc && c != sepc2)
92df930be7Sderaadt 				continue;
93df930be7Sderaadt 		}
94df930be7Sderaadt 		/* might have to trim trailing white space */
95df930be7Sderaadt 		if (trimtrail) {
96df930be7Sderaadt 			p--;
97df930be7Sderaadt 			while ((c = *--p) == sepc || c == sepc2)
98df930be7Sderaadt 				continue;
99df930be7Sderaadt 			p++;
100df930be7Sderaadt 			if (*p != '\0') {
101df930be7Sderaadt 				if (fn == nfields+1)
102df930be7Sderaadt 					*p = '\0';
103df930be7Sderaadt 				fn--;
104df930be7Sderaadt 			}
105df930be7Sderaadt 		}
106df930be7Sderaadt 		return(fn);
107df930be7Sderaadt 	}
108df930be7Sderaadt 
109df930be7Sderaadt 	/* n separators */
110df930be7Sderaadt 	fn = 0;
111df930be7Sderaadt 	for (;;) {
112df930be7Sderaadt 		if (fn < nfields)
113df930be7Sderaadt 			*fp++ = p;
114df930be7Sderaadt 		fn++;
115df930be7Sderaadt 		for (;;) {
116df930be7Sderaadt 			c = *p++;
117df930be7Sderaadt 			if (c == '\0')
118df930be7Sderaadt 				return(fn);
119df930be7Sderaadt 			sepp = sep;
120df930be7Sderaadt 			while ((sepc = *sepp++) != '\0' && sepc != c)
121df930be7Sderaadt 				continue;
122df930be7Sderaadt 			if (sepc != '\0')	/* it was a separator */
123df930be7Sderaadt 				break;
124df930be7Sderaadt 		}
125df930be7Sderaadt 		if (fn < nfields)
126df930be7Sderaadt 			*(p-1) = '\0';
127df930be7Sderaadt 		for (;;) {
128df930be7Sderaadt 			c = *p++;
129df930be7Sderaadt 			sepp = sep;
130df930be7Sderaadt 			while ((sepc = *sepp++) != '\0' && sepc != c)
131df930be7Sderaadt 				continue;
132df930be7Sderaadt 			if (sepc == '\0')	/* it wasn't a separator */
133df930be7Sderaadt 				break;
134df930be7Sderaadt 		}
135df930be7Sderaadt 		p--;
136df930be7Sderaadt 	}
137df930be7Sderaadt 
138df930be7Sderaadt 	/* not reached */
139df930be7Sderaadt }
140df930be7Sderaadt 
141df930be7Sderaadt #ifdef TEST_SPLIT
142df930be7Sderaadt 
143df930be7Sderaadt 
144df930be7Sderaadt /*
145df930be7Sderaadt  * test program
146df930be7Sderaadt  * pgm		runs regression
147df930be7Sderaadt  * pgm sep	splits stdin lines by sep
148df930be7Sderaadt  * pgm str sep	splits str by sep
149df930be7Sderaadt  * pgm str sep n	splits str by sep n times
150df930be7Sderaadt  */
151df930be7Sderaadt int
main(argc,argv)152df930be7Sderaadt main(argc, argv)
153df930be7Sderaadt int argc;
154df930be7Sderaadt char *argv[];
155df930be7Sderaadt {
156df930be7Sderaadt 	char buf[512];
157df930be7Sderaadt 	register int n;
158df930be7Sderaadt #	define	MNF	10
159df930be7Sderaadt 	char *fields[MNF];
160df930be7Sderaadt 
161df930be7Sderaadt 	if (argc > 4)
162df930be7Sderaadt 		for (n = atoi(argv[3]); n > 0; n--) {
163112e1910Sderaadt 			(void) strlcpy(buf, argv[1], sizeof buf);
164df930be7Sderaadt 		}
165df930be7Sderaadt 	else if (argc > 3)
166df930be7Sderaadt 		for (n = atoi(argv[3]); n > 0; n--) {
167112e1910Sderaadt 			(void) strlcpy(buf, argv[1], sizeof buf);
168df930be7Sderaadt 			(void) split(buf, fields, MNF, argv[2]);
169df930be7Sderaadt 		}
170df930be7Sderaadt 	else if (argc > 2)
171df930be7Sderaadt 		dosplit(argv[1], argv[2]);
172df930be7Sderaadt 	else if (argc > 1)
173df930be7Sderaadt 		while (fgets(buf, sizeof(buf), stdin) != NULL) {
174*2ed2be6eSchl 			buf[strcspn(buf, "\n")] = '\0';	/* stomp newline */
175df930be7Sderaadt 			dosplit(buf, argv[1]);
176df930be7Sderaadt 		}
177df930be7Sderaadt 	else
178df930be7Sderaadt 		regress();
179df930be7Sderaadt 
180df930be7Sderaadt 	exit(0);
181df930be7Sderaadt }
182df930be7Sderaadt 
dosplit(string,seps)183df930be7Sderaadt dosplit(string, seps)
184df930be7Sderaadt char *string;
185df930be7Sderaadt char *seps;
186df930be7Sderaadt {
187df930be7Sderaadt #	define	NF	5
188df930be7Sderaadt 	char *fields[NF];
189df930be7Sderaadt 	register int nf;
190df930be7Sderaadt 
191df930be7Sderaadt 	nf = split(string, fields, NF, seps);
192df930be7Sderaadt 	print(nf, NF, fields);
193df930be7Sderaadt }
194df930be7Sderaadt 
print(nf,nfp,fields)195df930be7Sderaadt print(nf, nfp, fields)
196df930be7Sderaadt int nf;
197df930be7Sderaadt int nfp;
198df930be7Sderaadt char *fields[];
199df930be7Sderaadt {
200df930be7Sderaadt 	register int fn;
201df930be7Sderaadt 	register int bound;
202df930be7Sderaadt 
203df930be7Sderaadt 	bound = (nf > nfp) ? nfp : nf;
204df930be7Sderaadt 	printf("%d:\t", nf);
205df930be7Sderaadt 	for (fn = 0; fn < bound; fn++)
206df930be7Sderaadt 		printf("\"%s\"%s", fields[fn], (fn+1 < nf) ? ", " : "\n");
207df930be7Sderaadt }
208df930be7Sderaadt 
209df930be7Sderaadt #define	RNF	5		/* some table entries know this */
210df930be7Sderaadt struct {
211df930be7Sderaadt 	char *str;
212df930be7Sderaadt 	char *seps;
213df930be7Sderaadt 	int nf;
214df930be7Sderaadt 	char *fi[RNF];
215df930be7Sderaadt } tests[] = {
216df930be7Sderaadt 	"",		" ",	0,	{ "" },
217df930be7Sderaadt 	" ",		" ",	2,	{ "", "" },
218df930be7Sderaadt 	"x",		" ",	1,	{ "x" },
219df930be7Sderaadt 	"xy",		" ",	1,	{ "xy" },
220df930be7Sderaadt 	"x y",		" ",	2,	{ "x", "y" },
221df930be7Sderaadt 	"abc def  g ",	" ",	5,	{ "abc", "def", "", "g", "" },
222df930be7Sderaadt 	"  a bcd",	" ",	4,	{ "", "", "a", "bcd" },
223df930be7Sderaadt 	"a b c d e f",	" ",	6,	{ "a", "b", "c", "d", "e f" },
224df930be7Sderaadt 	" a b c d ",	" ",	6,	{ "", "a", "b", "c", "d " },
225df930be7Sderaadt 
226df930be7Sderaadt 	"",		" _",	0,	{ "" },
227df930be7Sderaadt 	" ",		" _",	2,	{ "", "" },
228df930be7Sderaadt 	"x",		" _",	1,	{ "x" },
229df930be7Sderaadt 	"x y",		" _",	2,	{ "x", "y" },
230df930be7Sderaadt 	"ab _ cd",	" _",	2,	{ "ab", "cd" },
231df930be7Sderaadt 	" a_b  c ",	" _",	5,	{ "", "a", "b", "c", "" },
232df930be7Sderaadt 	"a b c_d e f",	" _",	6,	{ "a", "b", "c", "d", "e f" },
233df930be7Sderaadt 	" a b c d ",	" _",	6,	{ "", "a", "b", "c", "d " },
234df930be7Sderaadt 
235df930be7Sderaadt 	"",		" _~",	0,	{ "" },
236df930be7Sderaadt 	" ",		" _~",	2,	{ "", "" },
237df930be7Sderaadt 	"x",		" _~",	1,	{ "x" },
238df930be7Sderaadt 	"x y",		" _~",	2,	{ "x", "y" },
239df930be7Sderaadt 	"ab _~ cd",	" _~",	2,	{ "ab", "cd" },
240df930be7Sderaadt 	" a_b  c~",	" _~",	5,	{ "", "a", "b", "c", "" },
241df930be7Sderaadt 	"a b_c d~e f",	" _~",	6,	{ "a", "b", "c", "d", "e f" },
242df930be7Sderaadt 	"~a b c d ",	" _~",	6,	{ "", "a", "b", "c", "d " },
243df930be7Sderaadt 
244df930be7Sderaadt 	"",		" _~-",	0,	{ "" },
245df930be7Sderaadt 	" ",		" _~-",	2,	{ "", "" },
246df930be7Sderaadt 	"x",		" _~-",	1,	{ "x" },
247df930be7Sderaadt 	"x y",		" _~-",	2,	{ "x", "y" },
248df930be7Sderaadt 	"ab _~- cd",	" _~-",	2,	{ "ab", "cd" },
249df930be7Sderaadt 	" a_b  c~",	" _~-",	5,	{ "", "a", "b", "c", "" },
250df930be7Sderaadt 	"a b_c-d~e f",	" _~-",	6,	{ "a", "b", "c", "d", "e f" },
251df930be7Sderaadt 	"~a-b c d ",	" _~-",	6,	{ "", "a", "b", "c", "d " },
252df930be7Sderaadt 
253df930be7Sderaadt 	"",		"  ",	0,	{ "" },
254df930be7Sderaadt 	" ",		"  ",	2,	{ "", "" },
255df930be7Sderaadt 	"x",		"  ",	1,	{ "x" },
256df930be7Sderaadt 	"xy",		"  ",	1,	{ "xy" },
257df930be7Sderaadt 	"x y",		"  ",	2,	{ "x", "y" },
258df930be7Sderaadt 	"abc def  g ",	"  ",	4,	{ "abc", "def", "g", "" },
259df930be7Sderaadt 	"  a bcd",	"  ",	3,	{ "", "a", "bcd" },
260df930be7Sderaadt 	"a b c d e f",	"  ",	6,	{ "a", "b", "c", "d", "e f" },
261df930be7Sderaadt 	" a b c d ",	"  ",	6,	{ "", "a", "b", "c", "d " },
262df930be7Sderaadt 
263df930be7Sderaadt 	"",		"",	0,	{ "" },
264df930be7Sderaadt 	" ",		"",	0,	{ "" },
265df930be7Sderaadt 	"x",		"",	1,	{ "x" },
266df930be7Sderaadt 	"xy",		"",	1,	{ "xy" },
267df930be7Sderaadt 	"x y",		"",	2,	{ "x", "y" },
268df930be7Sderaadt 	"abc def  g ",	"",	3,	{ "abc", "def", "g" },
269df930be7Sderaadt 	"\t a bcd",	"",	2,	{ "a", "bcd" },
270df930be7Sderaadt 	"  a \tb\t c ",	"",	3,	{ "a", "b", "c" },
271df930be7Sderaadt 	"a b c d e ",	"",	5,	{ "a", "b", "c", "d", "e" },
272df930be7Sderaadt 	"a b\tc d e f",	"",	6,	{ "a", "b", "c", "d", "e f" },
273df930be7Sderaadt 	" a b c d e f ",	"",	6,	{ "a", "b", "c", "d", "e f " },
274df930be7Sderaadt 
275df930be7Sderaadt 	NULL,		NULL,	0,	{ NULL },
276df930be7Sderaadt };
277df930be7Sderaadt 
regress()278df930be7Sderaadt regress()
279df930be7Sderaadt {
280df930be7Sderaadt 	char buf[512];
281df930be7Sderaadt 	register int n;
282df930be7Sderaadt 	char *fields[RNF+1];
283df930be7Sderaadt 	register int nf;
284df930be7Sderaadt 	register int i;
285df930be7Sderaadt 	register int printit;
286df930be7Sderaadt 	register char *f;
287df930be7Sderaadt 
288df930be7Sderaadt 	for (n = 0; tests[n].str != NULL; n++) {
289112e1910Sderaadt 		(void) strlcpy(buf, tests[n].str, sizeof buf);
290df930be7Sderaadt 		fields[RNF] = NULL;
291df930be7Sderaadt 		nf = split(buf, fields, RNF, tests[n].seps);
292df930be7Sderaadt 		printit = 0;
293df930be7Sderaadt 		if (nf != tests[n].nf) {
294df930be7Sderaadt 			printf("split `%s' by `%s' gave %d fields, not %d\n",
295df930be7Sderaadt 				tests[n].str, tests[n].seps, nf, tests[n].nf);
296df930be7Sderaadt 			printit = 1;
297df930be7Sderaadt 		} else if (fields[RNF] != NULL) {
298df930be7Sderaadt 			printf("split() went beyond array end\n");
299df930be7Sderaadt 			printit = 1;
300df930be7Sderaadt 		} else {
301df930be7Sderaadt 			for (i = 0; i < nf && i < RNF; i++) {
302df930be7Sderaadt 				f = fields[i];
303df930be7Sderaadt 				if (f == NULL)
304df930be7Sderaadt 					f = "(NULL)";
305df930be7Sderaadt 				if (strcmp(f, tests[n].fi[i]) != 0) {
306df930be7Sderaadt 					printf("split `%s' by `%s', field %d is `%s', not `%s'\n",
307df930be7Sderaadt 						tests[n].str, tests[n].seps,
308df930be7Sderaadt 						i, fields[i], tests[n].fi[i]);
309df930be7Sderaadt 					printit = 1;
310df930be7Sderaadt 				}
311df930be7Sderaadt 			}
312df930be7Sderaadt 		}
313df930be7Sderaadt 		if (printit)
314df930be7Sderaadt 			print(nf, RNF, fields);
315df930be7Sderaadt 	}
316df930be7Sderaadt }
317df930be7Sderaadt #endif
318