xref: /plan9/sys/src/cmd/join.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1*219b2ee8SDavid du Colombier /*	join F1 F2 on stuff */
2*219b2ee8SDavid du Colombier #include <u.h>
3*219b2ee8SDavid du Colombier #include <libc.h>
4*219b2ee8SDavid du Colombier #include <stdio.h>
5*219b2ee8SDavid du Colombier #include <ctype.h>
6*219b2ee8SDavid du Colombier #define F1 0
7*219b2ee8SDavid du Colombier #define F2 1
8*219b2ee8SDavid du Colombier #define F0 3
9*219b2ee8SDavid du Colombier #define	NFLD	100	/* max field per line */
10*219b2ee8SDavid du Colombier #define comp() runecmp(ppi[F1][j1],ppi[F2][j2])
11*219b2ee8SDavid du Colombier FILE *f[2];
12*219b2ee8SDavid du Colombier Rune buf[2][BUFSIZ];	/*input lines */
13*219b2ee8SDavid du Colombier Rune *ppi[2][NFLD+1];	/* pointers to fields in lines */
14*219b2ee8SDavid du Colombier Rune *s1,*s2;
15*219b2ee8SDavid du Colombier int	j1	= 1;	/* join of this field of file 1 */
16*219b2ee8SDavid du Colombier int	j2	= 1;	/* join of this field of file 2 */
17*219b2ee8SDavid du Colombier int	olist[2*NFLD];	/* output these fields */
18*219b2ee8SDavid du Colombier int	olistf[2*NFLD];	/* from these files */
19*219b2ee8SDavid du Colombier int	no;		/* number of entries in olist */
20*219b2ee8SDavid du Colombier Rune	sep1	= ' ';	/* default field separator */
21*219b2ee8SDavid du Colombier Rune	sep2	= '\t';
22*219b2ee8SDavid du Colombier char *sepstr=" ";
23*219b2ee8SDavid du Colombier int	discard;	/* count of truncated lines */
24*219b2ee8SDavid du Colombier Rune	null[BUFSIZ]	= L"";
25*219b2ee8SDavid du Colombier int	a1;
26*219b2ee8SDavid du Colombier int 	a2;
27*219b2ee8SDavid du Colombier 
28*219b2ee8SDavid du Colombier char *getoptarg(int*, char***);
29*219b2ee8SDavid du Colombier void output(int, int);
30*219b2ee8SDavid du Colombier int input(int);
31*219b2ee8SDavid du Colombier void oparse(char*);
32*219b2ee8SDavid du Colombier void error(char*, char*);
33*219b2ee8SDavid du Colombier void seek1(void), seek2(void);
34*219b2ee8SDavid du Colombier Rune *strtorune(Rune *, char *);
35*219b2ee8SDavid du Colombier 
36*219b2ee8SDavid du Colombier 
37*219b2ee8SDavid du Colombier void
38*219b2ee8SDavid du Colombier main(int argc, char **argv)
39*219b2ee8SDavid du Colombier {
40*219b2ee8SDavid du Colombier 	int i;
41*219b2ee8SDavid du Colombier 
42*219b2ee8SDavid du Colombier 	while (argc > 1 && argv[1][0] == '-') {
43*219b2ee8SDavid du Colombier 		if (argv[1][1] == '\0')
44*219b2ee8SDavid du Colombier 			break;
45*219b2ee8SDavid du Colombier 		switch (argv[1][1]) {
46*219b2ee8SDavid du Colombier 		case '-':
47*219b2ee8SDavid du Colombier 			argc--;
48*219b2ee8SDavid du Colombier 			argv++;
49*219b2ee8SDavid du Colombier 			goto proceed;
50*219b2ee8SDavid du Colombier 		case 'a':
51*219b2ee8SDavid du Colombier 			switch(*getoptarg(&argc, &argv)) {
52*219b2ee8SDavid du Colombier 			case '1':
53*219b2ee8SDavid du Colombier 				a1++;
54*219b2ee8SDavid du Colombier 				break;
55*219b2ee8SDavid du Colombier 			case '2':
56*219b2ee8SDavid du Colombier 				a2++;
57*219b2ee8SDavid du Colombier 				break;
58*219b2ee8SDavid du Colombier 			default:
59*219b2ee8SDavid du Colombier 				error("incomplete option -a","");
60*219b2ee8SDavid du Colombier 			}
61*219b2ee8SDavid du Colombier 			break;
62*219b2ee8SDavid du Colombier 		case 'e':
63*219b2ee8SDavid du Colombier 			strtorune(null, getoptarg(&argc, &argv));
64*219b2ee8SDavid du Colombier 			break;
65*219b2ee8SDavid du Colombier 		case 't':
66*219b2ee8SDavid du Colombier 			sepstr=getoptarg(&argc, &argv);
67*219b2ee8SDavid du Colombier 			chartorune(&sep1, sepstr);
68*219b2ee8SDavid du Colombier 			sep2 = sep1;
69*219b2ee8SDavid du Colombier 			break;
70*219b2ee8SDavid du Colombier 		case 'o':
71*219b2ee8SDavid du Colombier 			if(argv[1][2]!=0 ||
72*219b2ee8SDavid du Colombier 			   argc>2 && strchr(argv[2],',')!=0)
73*219b2ee8SDavid du Colombier 				oparse(getoptarg(&argc, &argv));
74*219b2ee8SDavid du Colombier 			else for (no = 0; no<2*NFLD && argc>2; no++){
75*219b2ee8SDavid du Colombier 				if (argv[2][0] == '1' && argv[2][1] == '.') {
76*219b2ee8SDavid du Colombier 					olistf[no] = F1;
77*219b2ee8SDavid du Colombier 					olist[no] = atoi(&argv[2][2]);
78*219b2ee8SDavid du Colombier 				} else if (argv[2][0] == '2' && argv[2][1] == '.') {
79*219b2ee8SDavid du Colombier 					olist[no] = atoi(&argv[2][2]);
80*219b2ee8SDavid du Colombier 					olistf[no] = F2;
81*219b2ee8SDavid du Colombier 				} else if (argv[2][0] == '0')
82*219b2ee8SDavid du Colombier 					olistf[no] = F0;
83*219b2ee8SDavid du Colombier 				else
84*219b2ee8SDavid du Colombier 					break;
85*219b2ee8SDavid du Colombier 				argc--;
86*219b2ee8SDavid du Colombier 				argv++;
87*219b2ee8SDavid du Colombier 			}
88*219b2ee8SDavid du Colombier 			break;
89*219b2ee8SDavid du Colombier 		case 'j':
90*219b2ee8SDavid du Colombier 			if(argc <= 2)
91*219b2ee8SDavid du Colombier 				break;
92*219b2ee8SDavid du Colombier 			if (argv[1][2] == '1')
93*219b2ee8SDavid du Colombier 				j1 = atoi(argv[2]);
94*219b2ee8SDavid du Colombier 			else if (argv[1][2] == '2')
95*219b2ee8SDavid du Colombier 				j2 = atoi(argv[2]);
96*219b2ee8SDavid du Colombier 			else
97*219b2ee8SDavid du Colombier 				j1 = j2 = atoi(argv[2]);
98*219b2ee8SDavid du Colombier 			argc--;
99*219b2ee8SDavid du Colombier 			argv++;
100*219b2ee8SDavid du Colombier 			break;
101*219b2ee8SDavid du Colombier 		case '1':
102*219b2ee8SDavid du Colombier 			j1 = atoi(getoptarg(&argc, &argv));
103*219b2ee8SDavid du Colombier 			break;
104*219b2ee8SDavid du Colombier 		case '2':
105*219b2ee8SDavid du Colombier 			j2 = atoi(getoptarg(&argc, &argv));
106*219b2ee8SDavid du Colombier 			break;
107*219b2ee8SDavid du Colombier 		}
108*219b2ee8SDavid du Colombier 		argc--;
109*219b2ee8SDavid du Colombier 		argv++;
110*219b2ee8SDavid du Colombier 	}
111*219b2ee8SDavid du Colombier proceed:
112*219b2ee8SDavid du Colombier 	for (i = 0; i < no; i++)
113*219b2ee8SDavid du Colombier 		if (olist[i]-- > NFLD)	/* 0 origin */
114*219b2ee8SDavid du Colombier 			error("field number too big in -o","");
115*219b2ee8SDavid du Colombier 	if (argc != 3)
116*219b2ee8SDavid du Colombier 		error("usage: join [-1 x -2 y] [-o list] file1 file2","");
117*219b2ee8SDavid du Colombier 	j1--;
118*219b2ee8SDavid du Colombier 	j2--;	/* everyone else believes in 0 origin */
119*219b2ee8SDavid du Colombier 	s1 = ppi[F1][j1];
120*219b2ee8SDavid du Colombier 	s2 = ppi[F2][j2];
121*219b2ee8SDavid du Colombier 	if (strcmp(argv[1], "-") == 0)
122*219b2ee8SDavid du Colombier 		f[F1] = stdin;
123*219b2ee8SDavid du Colombier 	else if ((f[F1] = fopen(argv[1], "r")) == 0)
124*219b2ee8SDavid du Colombier 		error("can't open %s", argv[1]);
125*219b2ee8SDavid du Colombier 	if(strcmp(argv[2], "-") == 0) {
126*219b2ee8SDavid du Colombier 		f[F2] = stdin;
127*219b2ee8SDavid du Colombier 	} else if ((f[F2] = fopen(argv[2], "r")) == 0)
128*219b2ee8SDavid du Colombier 		error("can't open %s", argv[2]);
129*219b2ee8SDavid du Colombier 
130*219b2ee8SDavid du Colombier 	if(ftell(f[F2]) >= 0)
131*219b2ee8SDavid du Colombier 		seek2();
132*219b2ee8SDavid du Colombier 	else if(ftell(f[F1]) >= 0)
133*219b2ee8SDavid du Colombier 		seek1();
134*219b2ee8SDavid du Colombier 	else
135*219b2ee8SDavid du Colombier 		error("neither file is randomly accessible","");
136*219b2ee8SDavid du Colombier 	if (discard)
137*219b2ee8SDavid du Colombier 		error("some input line was truncated", "");
138*219b2ee8SDavid du Colombier 	exits("");
139*219b2ee8SDavid du Colombier }
140*219b2ee8SDavid du Colombier int runecmp(Rune *a, Rune *b){
141*219b2ee8SDavid du Colombier 	while(*a==*b){
142*219b2ee8SDavid du Colombier 		if(*a=='\0') return 0;
143*219b2ee8SDavid du Colombier 		a++;
144*219b2ee8SDavid du Colombier 		b++;
145*219b2ee8SDavid du Colombier 	}
146*219b2ee8SDavid du Colombier 	if(*a<*b) return -1;
147*219b2ee8SDavid du Colombier 	return 1;
148*219b2ee8SDavid du Colombier }
149*219b2ee8SDavid du Colombier char *runetostr(char *buf, Rune *r){
150*219b2ee8SDavid du Colombier 	char *s;
151*219b2ee8SDavid du Colombier 	for(s=buf;*r;r++) s+=runetochar(s, r);
152*219b2ee8SDavid du Colombier 	*s='\0';
153*219b2ee8SDavid du Colombier 	return buf;
154*219b2ee8SDavid du Colombier }
155*219b2ee8SDavid du Colombier Rune *strtorune(Rune *buf, char *s){
156*219b2ee8SDavid du Colombier 	Rune *r;
157*219b2ee8SDavid du Colombier 	for(r=buf;*s;r++) s+=chartorune(r, s);
158*219b2ee8SDavid du Colombier 	*r='\0';
159*219b2ee8SDavid du Colombier 	return buf;
160*219b2ee8SDavid du Colombier }
161*219b2ee8SDavid du Colombier /* lazy.  there ought to be a clean way to combine seek1 & seek2 */
162*219b2ee8SDavid du Colombier #define get1() n1=input(F1)
163*219b2ee8SDavid du Colombier #define get2() n2=input(F2)
164*219b2ee8SDavid du Colombier void
165*219b2ee8SDavid du Colombier seek2()
166*219b2ee8SDavid du Colombier {
167*219b2ee8SDavid du Colombier 	int n1, n2;
168*219b2ee8SDavid du Colombier 	int top2=0;
169*219b2ee8SDavid du Colombier 	int bot2 = ftell(f[F2]);
170*219b2ee8SDavid du Colombier 	get1();
171*219b2ee8SDavid du Colombier 	get2();
172*219b2ee8SDavid du Colombier 	while(n1>0 && n2>0 || (a1||a2) && n1+n2>0) {
173*219b2ee8SDavid du Colombier 		if(n1>0 && n2>0 && comp()>0 || n1==0) {
174*219b2ee8SDavid du Colombier 			if(a2) output(0, n2);
175*219b2ee8SDavid du Colombier 			bot2 = ftell(f[F2]);
176*219b2ee8SDavid du Colombier 			get2();
177*219b2ee8SDavid du Colombier 		} else if(n1>0 && n2>0 && comp()<0 || n2==0) {
178*219b2ee8SDavid du Colombier 			if(a1) output(n1, 0);
179*219b2ee8SDavid du Colombier 			get1();
180*219b2ee8SDavid du Colombier 		} else /*(n1>0 && n2>0 && comp()==0)*/ {
181*219b2ee8SDavid du Colombier 			while(n2>0 && comp()==0) {
182*219b2ee8SDavid du Colombier 				output(n1, n2);
183*219b2ee8SDavid du Colombier 				top2 = ftell(f[F2]);
184*219b2ee8SDavid du Colombier 				get2();
185*219b2ee8SDavid du Colombier 			}
186*219b2ee8SDavid du Colombier 			fseek(f[F2], bot2, 0);
187*219b2ee8SDavid du Colombier 			get2();
188*219b2ee8SDavid du Colombier 			get1();
189*219b2ee8SDavid du Colombier 			for(;;) {
190*219b2ee8SDavid du Colombier 				if(n1>0 && n2>0 && comp()==0) {
191*219b2ee8SDavid du Colombier 					output(n1, n2);
192*219b2ee8SDavid du Colombier 					get2();
193*219b2ee8SDavid du Colombier 				} else if(n1>0 && n2>0 && comp()<0 || n2==0) {
194*219b2ee8SDavid du Colombier 					fseek(f[F2], bot2, 0);
195*219b2ee8SDavid du Colombier 					get2();
196*219b2ee8SDavid du Colombier 					get1();
197*219b2ee8SDavid du Colombier 				} else /*(n1>0 && n2>0 && comp()>0 || n1==0)*/{
198*219b2ee8SDavid du Colombier 					fseek(f[F2], top2, 0);
199*219b2ee8SDavid du Colombier 					bot2 = top2;
200*219b2ee8SDavid du Colombier 					get2();
201*219b2ee8SDavid du Colombier 					break;
202*219b2ee8SDavid du Colombier 				}
203*219b2ee8SDavid du Colombier 			}
204*219b2ee8SDavid du Colombier 		}
205*219b2ee8SDavid du Colombier 	}
206*219b2ee8SDavid du Colombier }
207*219b2ee8SDavid du Colombier void
208*219b2ee8SDavid du Colombier seek1()
209*219b2ee8SDavid du Colombier {
210*219b2ee8SDavid du Colombier 	int n1, n2;
211*219b2ee8SDavid du Colombier 	int top1=0;
212*219b2ee8SDavid du Colombier 	int bot1 = ftell(f[F1]);
213*219b2ee8SDavid du Colombier 	get1();
214*219b2ee8SDavid du Colombier 	get2();
215*219b2ee8SDavid du Colombier 	while(n1>0 && n2>0 || (a1||a2) && n1+n2>0) {
216*219b2ee8SDavid du Colombier 		if(n1>0 && n2>0 && comp()>0 || n1==0) {
217*219b2ee8SDavid du Colombier 			if(a2) output(0, n2);
218*219b2ee8SDavid du Colombier 			get2();
219*219b2ee8SDavid du Colombier 		} else if(n1>0 && n2>0 && comp()<0 || n2==0) {
220*219b2ee8SDavid du Colombier 			if(a1) output(n1, 0);
221*219b2ee8SDavid du Colombier 			bot1 = ftell(f[F1]);
222*219b2ee8SDavid du Colombier 			get1();
223*219b2ee8SDavid du Colombier 		} else /*(n1>0 && n2>0 && comp()==0)*/ {
224*219b2ee8SDavid du Colombier 			while(n2>0 && comp()==0) {
225*219b2ee8SDavid du Colombier 				output(n1, n2);
226*219b2ee8SDavid du Colombier 				top1 = ftell(f[F1]);
227*219b2ee8SDavid du Colombier 				get1();
228*219b2ee8SDavid du Colombier 			}
229*219b2ee8SDavid du Colombier 			fseek(f[F1], bot1, 0);
230*219b2ee8SDavid du Colombier 			get2();
231*219b2ee8SDavid du Colombier 			get1();
232*219b2ee8SDavid du Colombier 			for(;;) {
233*219b2ee8SDavid du Colombier 				if(n1>0 && n2>0 && comp()==0) {
234*219b2ee8SDavid du Colombier 					output(n1, n2);
235*219b2ee8SDavid du Colombier 					get1();
236*219b2ee8SDavid du Colombier 				} else if(n1>0 && n2>0 && comp()>0 || n1==0) {
237*219b2ee8SDavid du Colombier 					fseek(f[F1], bot1, 0);
238*219b2ee8SDavid du Colombier 					get2();
239*219b2ee8SDavid du Colombier 					get1();
240*219b2ee8SDavid du Colombier 				} else /*(n1>0 && n2>0 && comp()<0 || n2==0)*/{
241*219b2ee8SDavid du Colombier 					fseek(f[F1], top1, 0);
242*219b2ee8SDavid du Colombier 					bot1 = top1;
243*219b2ee8SDavid du Colombier 					get1();
244*219b2ee8SDavid du Colombier 					break;
245*219b2ee8SDavid du Colombier 				}
246*219b2ee8SDavid du Colombier 			}
247*219b2ee8SDavid du Colombier 		}
248*219b2ee8SDavid du Colombier 	}
249*219b2ee8SDavid du Colombier }
250*219b2ee8SDavid du Colombier 
251*219b2ee8SDavid du Colombier int
252*219b2ee8SDavid du Colombier input(int n)		/* get input line and split into fields */
253*219b2ee8SDavid du Colombier {
254*219b2ee8SDavid du Colombier 	register int i, c;
255*219b2ee8SDavid du Colombier 	Rune *bp;
256*219b2ee8SDavid du Colombier 	Rune **pp;
257*219b2ee8SDavid du Colombier 	char line[BUFSIZ];
258*219b2ee8SDavid du Colombier 
259*219b2ee8SDavid du Colombier 	bp = buf[n];
260*219b2ee8SDavid du Colombier 	pp = ppi[n];
261*219b2ee8SDavid du Colombier 	if (fgets(line, BUFSIZ, f[n]) == 0)
262*219b2ee8SDavid du Colombier 		return(0);
263*219b2ee8SDavid du Colombier 	strtorune(bp, line);
264*219b2ee8SDavid du Colombier 	i = 0;
265*219b2ee8SDavid du Colombier 	do {
266*219b2ee8SDavid du Colombier 		i++;
267*219b2ee8SDavid du Colombier 		if (sep1 == ' ')	/* strip multiples */
268*219b2ee8SDavid du Colombier 			while ((c = *bp) == sep1 || c == sep2)
269*219b2ee8SDavid du Colombier 				bp++;	/* skip blanks */
270*219b2ee8SDavid du Colombier 		*pp++ = bp;	/* record beginning */
271*219b2ee8SDavid du Colombier 		while ((c = *bp) != sep1 && c != '\n' && c != sep2 && c != '\0')
272*219b2ee8SDavid du Colombier 			bp++;
273*219b2ee8SDavid du Colombier 		*bp++ = '\0';	/* mark end by overwriting blank */
274*219b2ee8SDavid du Colombier 	} while (c != '\n' && c != '\0' && i < NFLD-1);
275*219b2ee8SDavid du Colombier 	if (c != '\n')
276*219b2ee8SDavid du Colombier 		discard++;
277*219b2ee8SDavid du Colombier 
278*219b2ee8SDavid du Colombier 	*pp = 0;
279*219b2ee8SDavid du Colombier 	return(i);
280*219b2ee8SDavid du Colombier }
281*219b2ee8SDavid du Colombier 
282*219b2ee8SDavid du Colombier void
283*219b2ee8SDavid du Colombier output(int on1, int on2)	/* print items from olist */
284*219b2ee8SDavid du Colombier {
285*219b2ee8SDavid du Colombier 	int i;
286*219b2ee8SDavid du Colombier 	Rune *temp;
287*219b2ee8SDavid du Colombier 	char buf[BUFSIZ];
288*219b2ee8SDavid du Colombier 
289*219b2ee8SDavid du Colombier 	if (no <= 0) {	/* default case */
290*219b2ee8SDavid du Colombier 		printf("%s", runetostr(buf, on1? ppi[F1][j1]: ppi[F2][j2]));
291*219b2ee8SDavid du Colombier 		for (i = 0; i < on1; i++)
292*219b2ee8SDavid du Colombier 			if (i != j1)
293*219b2ee8SDavid du Colombier 				printf("%s%s", sepstr, runetostr(buf, ppi[F1][i]));
294*219b2ee8SDavid du Colombier 		for (i = 0; i < on2; i++)
295*219b2ee8SDavid du Colombier 			if (i != j2)
296*219b2ee8SDavid du Colombier 				printf("%s%s", sepstr, runetostr(buf, ppi[F2][i]));
297*219b2ee8SDavid du Colombier 		printf("\n");
298*219b2ee8SDavid du Colombier 	} else {
299*219b2ee8SDavid du Colombier 		for (i = 0; i < no; i++) {
300*219b2ee8SDavid du Colombier 			if (olistf[i]==F0 && on1>j1)
301*219b2ee8SDavid du Colombier 				temp = ppi[F1][j1];
302*219b2ee8SDavid du Colombier 			else if (olistf[i]==F0 && on2>j2)
303*219b2ee8SDavid du Colombier 				temp = ppi[F2][j2];
304*219b2ee8SDavid du Colombier 			else {
305*219b2ee8SDavid du Colombier 				temp = ppi[olistf[i]][olist[i]];
306*219b2ee8SDavid du Colombier 				if(olistf[i]==F1 && on1<=olist[i] ||
307*219b2ee8SDavid du Colombier 				   olistf[i]==F2 && on2<=olist[i] ||
308*219b2ee8SDavid du Colombier 				   *temp==0)
309*219b2ee8SDavid du Colombier 					temp = null;
310*219b2ee8SDavid du Colombier 			}
311*219b2ee8SDavid du Colombier 			printf("%s", runetostr(buf, temp));
312*219b2ee8SDavid du Colombier 			if (i == no - 1)
313*219b2ee8SDavid du Colombier 				printf("\n");
314*219b2ee8SDavid du Colombier 			else
315*219b2ee8SDavid du Colombier 				printf("%s", sepstr);
316*219b2ee8SDavid du Colombier 		}
317*219b2ee8SDavid du Colombier 	}
318*219b2ee8SDavid du Colombier }
319*219b2ee8SDavid du Colombier 
320*219b2ee8SDavid du Colombier void
321*219b2ee8SDavid du Colombier error(char *s1, char *s2)
322*219b2ee8SDavid du Colombier {
323*219b2ee8SDavid du Colombier 	fprintf(stderr, "join: ");
324*219b2ee8SDavid du Colombier 	fprintf(stderr, s1, s2);
325*219b2ee8SDavid du Colombier 	fprintf(stderr, "\n");
326*219b2ee8SDavid du Colombier 	exits(s1);
327*219b2ee8SDavid du Colombier }
328*219b2ee8SDavid du Colombier 
329*219b2ee8SDavid du Colombier char *
330*219b2ee8SDavid du Colombier getoptarg(int *argcp, char ***argvp)
331*219b2ee8SDavid du Colombier {
332*219b2ee8SDavid du Colombier 	int argc = *argcp;
333*219b2ee8SDavid du Colombier 	char **argv = *argvp;
334*219b2ee8SDavid du Colombier 	if(argv[1][2] != 0)
335*219b2ee8SDavid du Colombier 		return &argv[1][2];
336*219b2ee8SDavid du Colombier 	if(argc<=2 || argv[2][0]=='-')
337*219b2ee8SDavid du Colombier 		error("incomplete option %s", argv[1]);
338*219b2ee8SDavid du Colombier 	*argcp = argc-1;
339*219b2ee8SDavid du Colombier 	*argvp = ++argv;
340*219b2ee8SDavid du Colombier 	return argv[1];
341*219b2ee8SDavid du Colombier }
342*219b2ee8SDavid du Colombier 
343*219b2ee8SDavid du Colombier void
344*219b2ee8SDavid du Colombier oparse(char *s)
345*219b2ee8SDavid du Colombier {
346*219b2ee8SDavid du Colombier 	for (no = 0; no<2*NFLD && *s; no++, s++) {
347*219b2ee8SDavid du Colombier 		switch(*s) {
348*219b2ee8SDavid du Colombier 		case 0:
349*219b2ee8SDavid du Colombier 			return;
350*219b2ee8SDavid du Colombier 		case '0':
351*219b2ee8SDavid du Colombier 			olistf[no] = F0;
352*219b2ee8SDavid du Colombier 			break;
353*219b2ee8SDavid du Colombier 		case '1':
354*219b2ee8SDavid du Colombier 		case '2':
355*219b2ee8SDavid du Colombier 			if(s[1] == '.' && isdigit(s[2])) {
356*219b2ee8SDavid du Colombier 				olistf[no] = *s=='1'? F1: F2;
357*219b2ee8SDavid du Colombier 				olist[no] = atoi(s += 2);
358*219b2ee8SDavid du Colombier 				break;
359*219b2ee8SDavid du Colombier 			} /* fall thru */
360*219b2ee8SDavid du Colombier 		default:
361*219b2ee8SDavid du Colombier 			error("invalid -o list", "");
362*219b2ee8SDavid du Colombier 		}
363*219b2ee8SDavid du Colombier 		if(s[1] == ',')
364*219b2ee8SDavid du Colombier 			s++;
365*219b2ee8SDavid du Colombier 	}
366*219b2ee8SDavid du Colombier }
367