xref: /plan9/sys/src/cmd/join.c (revision 14f51593fd82e19ba95969a8c07ff71131015979)
1219b2ee8SDavid du Colombier /*	join F1 F2 on stuff */
2219b2ee8SDavid du Colombier #include <u.h>
3219b2ee8SDavid du Colombier #include <libc.h>
4*14f51593SDavid du Colombier #include <bio.h>
5219b2ee8SDavid du Colombier #include <ctype.h>
6feef5247SDavid du Colombier 
7*14f51593SDavid du Colombier enum {
8*14f51593SDavid du Colombier 	F1,
9*14f51593SDavid du Colombier 	F2,
10*14f51593SDavid du Colombier 	NIN,
11*14f51593SDavid du Colombier 	F0,
12*14f51593SDavid du Colombier };
13feef5247SDavid du Colombier 
14*14f51593SDavid du Colombier #define	NFLD	100	/* max field per line */
15*14f51593SDavid du Colombier #define comp() runestrcmp(ppi[F1][j1], ppi[F2][j2])
16*14f51593SDavid du Colombier 
17*14f51593SDavid du Colombier Biobuf *f[NIN];
18*14f51593SDavid du Colombier Rune buf[NIN][Bsize];	/* input lines */
19*14f51593SDavid du Colombier Rune *ppi[NIN][NFLD+1];	/* pointers to fields in lines */
20219b2ee8SDavid du Colombier Rune	sep1	= ' ';	/* default field separator */
21219b2ee8SDavid du Colombier Rune	sep2	= '\t';
22*14f51593SDavid du Colombier int	j1	= 1;	/* join of this field of file 1 */
23*14f51593SDavid du Colombier int	j2	= 1;	/* join of this field of file 2 */
24219b2ee8SDavid du Colombier int	a1;
25219b2ee8SDavid du Colombier int 	a2;
26219b2ee8SDavid du Colombier 
27*14f51593SDavid du Colombier int	olist[NIN*NFLD];  /* output these fields */
28*14f51593SDavid du Colombier int	olistf[NIN*NFLD]; /* from these files */
29*14f51593SDavid du Colombier int	no;		/* number of entries in olist */
30*14f51593SDavid du Colombier char *sepstr	= " ";
31*14f51593SDavid du Colombier int	discard;	/* count of truncated lines */
32*14f51593SDavid du Colombier Rune	null[Bsize]	= L"";
33*14f51593SDavid du Colombier Biobuf binbuf, boutbuf;
34*14f51593SDavid du Colombier Biobuf *bin, *bout;
35*14f51593SDavid du Colombier 
36219b2ee8SDavid du Colombier char	*getoptarg(int*, char***);
37219b2ee8SDavid du Colombier int	input(int);
38*14f51593SDavid du Colombier void	join(int);
39219b2ee8SDavid du Colombier void	oparse(char*);
40*14f51593SDavid du Colombier void	output(int, int);
41219b2ee8SDavid du Colombier Rune	*strtorune(Rune *, char *);
42219b2ee8SDavid du Colombier 
43219b2ee8SDavid du Colombier void
main(int argc,char ** argv)44219b2ee8SDavid du Colombier main(int argc, char **argv)
45219b2ee8SDavid du Colombier {
46219b2ee8SDavid du Colombier 	int i;
47*14f51593SDavid du Colombier 	vlong off1, off2;
48219b2ee8SDavid du Colombier 
49*14f51593SDavid du Colombier 	bin = &binbuf;
50*14f51593SDavid du Colombier 	bout = &boutbuf;
51*14f51593SDavid du Colombier 	Binit(bin, 0, OREAD);
52*14f51593SDavid du Colombier 	Binit(bout, 1, OWRITE);
53*14f51593SDavid du Colombier 
54*14f51593SDavid du Colombier 	argv0 = argv[0];
55219b2ee8SDavid du Colombier 	while (argc > 1 && argv[1][0] == '-') {
56219b2ee8SDavid du Colombier 		if (argv[1][1] == '\0')
57219b2ee8SDavid du Colombier 			break;
58219b2ee8SDavid du Colombier 		switch (argv[1][1]) {
59219b2ee8SDavid du Colombier 		case '-':
60219b2ee8SDavid du Colombier 			argc--;
61219b2ee8SDavid du Colombier 			argv++;
62219b2ee8SDavid du Colombier 			goto proceed;
63219b2ee8SDavid du Colombier 		case 'a':
64219b2ee8SDavid du Colombier 			switch(*getoptarg(&argc, &argv)) {
65219b2ee8SDavid du Colombier 			case '1':
66219b2ee8SDavid du Colombier 				a1++;
67219b2ee8SDavid du Colombier 				break;
68219b2ee8SDavid du Colombier 			case '2':
69219b2ee8SDavid du Colombier 				a2++;
70219b2ee8SDavid du Colombier 				break;
71219b2ee8SDavid du Colombier 			default:
72*14f51593SDavid du Colombier 				sysfatal("incomplete option -a");
73219b2ee8SDavid du Colombier 			}
74219b2ee8SDavid du Colombier 			break;
75219b2ee8SDavid du Colombier 		case 'e':
76219b2ee8SDavid du Colombier 			strtorune(null, getoptarg(&argc, &argv));
77219b2ee8SDavid du Colombier 			break;
78219b2ee8SDavid du Colombier 		case 't':
79219b2ee8SDavid du Colombier 			sepstr=getoptarg(&argc, &argv);
80219b2ee8SDavid du Colombier 			chartorune(&sep1, sepstr);
81219b2ee8SDavid du Colombier 			sep2 = sep1;
82219b2ee8SDavid du Colombier 			break;
83219b2ee8SDavid du Colombier 		case 'o':
84219b2ee8SDavid du Colombier 			if(argv[1][2]!=0 ||
85219b2ee8SDavid du Colombier 			   argc>2 && strchr(argv[2],',')!=0)
86219b2ee8SDavid du Colombier 				oparse(getoptarg(&argc, &argv));
87219b2ee8SDavid du Colombier 			else for (no = 0; no<2*NFLD && argc>2; no++){
88219b2ee8SDavid du Colombier 				if (argv[2][0] == '1' && argv[2][1] == '.') {
89219b2ee8SDavid du Colombier 					olistf[no] = F1;
90219b2ee8SDavid du Colombier 					olist[no] = atoi(&argv[2][2]);
91219b2ee8SDavid du Colombier 				} else if (argv[2][0] == '2' && argv[2][1] == '.') {
92219b2ee8SDavid du Colombier 					olist[no] = atoi(&argv[2][2]);
93219b2ee8SDavid du Colombier 					olistf[no] = F2;
94219b2ee8SDavid du Colombier 				} else if (argv[2][0] == '0')
95219b2ee8SDavid du Colombier 					olistf[no] = F0;
96219b2ee8SDavid du Colombier 				else
97219b2ee8SDavid du Colombier 					break;
98219b2ee8SDavid du Colombier 				argc--;
99219b2ee8SDavid du Colombier 				argv++;
100219b2ee8SDavid du Colombier 			}
101219b2ee8SDavid du Colombier 			break;
102219b2ee8SDavid du Colombier 		case 'j':
103219b2ee8SDavid du Colombier 			if(argc <= 2)
104219b2ee8SDavid du Colombier 				break;
105219b2ee8SDavid du Colombier 			if (argv[1][2] == '1')
106219b2ee8SDavid du Colombier 				j1 = atoi(argv[2]);
107219b2ee8SDavid du Colombier 			else if (argv[1][2] == '2')
108219b2ee8SDavid du Colombier 				j2 = atoi(argv[2]);
109219b2ee8SDavid du Colombier 			else
110219b2ee8SDavid du Colombier 				j1 = j2 = atoi(argv[2]);
111219b2ee8SDavid du Colombier 			argc--;
112219b2ee8SDavid du Colombier 			argv++;
113219b2ee8SDavid du Colombier 			break;
114219b2ee8SDavid du Colombier 		case '1':
115219b2ee8SDavid du Colombier 			j1 = atoi(getoptarg(&argc, &argv));
116219b2ee8SDavid du Colombier 			break;
117219b2ee8SDavid du Colombier 		case '2':
118219b2ee8SDavid du Colombier 			j2 = atoi(getoptarg(&argc, &argv));
119219b2ee8SDavid du Colombier 			break;
120219b2ee8SDavid du Colombier 		}
121219b2ee8SDavid du Colombier 		argc--;
122219b2ee8SDavid du Colombier 		argv++;
123219b2ee8SDavid du Colombier 	}
124219b2ee8SDavid du Colombier proceed:
125219b2ee8SDavid du Colombier 	for (i = 0; i < no; i++)
126219b2ee8SDavid du Colombier 		if (olist[i]-- > NFLD)	/* 0 origin */
127*14f51593SDavid du Colombier 			sysfatal("field number too big in -o");
128*14f51593SDavid du Colombier 	if (argc != 3) {
129*14f51593SDavid du Colombier 		fprint(2, "usage: join [-1 x -2 y] [-o list] file1 file2\n");
130*14f51593SDavid du Colombier 		exits("usage");
131*14f51593SDavid du Colombier 	}
13283f0bdbeSDavid du Colombier 	if (j1 < 1  || j2 < 1)
133*14f51593SDavid du Colombier 		sysfatal("invalid field indices");
134219b2ee8SDavid du Colombier 	j1--;
135219b2ee8SDavid du Colombier 	j2--;	/* everyone else believes in 0 origin */
136*14f51593SDavid du Colombier 
137219b2ee8SDavid du Colombier 	if (strcmp(argv[1], "-") == 0)
138*14f51593SDavid du Colombier 		f[F1] = bin;
139*14f51593SDavid du Colombier 	else if ((f[F1] = Bopen(argv[1], OREAD)) == 0)
140*14f51593SDavid du Colombier 		sysfatal("can't open %s: %r", argv[1]);
141*14f51593SDavid du Colombier 	if(strcmp(argv[2], "-") == 0)
142*14f51593SDavid du Colombier 		f[F2] = bin;
143*14f51593SDavid du Colombier 	else if ((f[F2] = Bopen(argv[2], OREAD)) == 0)
144*14f51593SDavid du Colombier 		sysfatal("can't open %s: %r", argv[2]);
145219b2ee8SDavid du Colombier 
146*14f51593SDavid du Colombier 	off1 = Boffset(f[F1]);
147*14f51593SDavid du Colombier 	off2 = Boffset(f[F2]);
148*14f51593SDavid du Colombier 	if(Bseek(f[F2], 0, 2) >= 0){
149*14f51593SDavid du Colombier 		Bseek(f[F2], off2, 0);
150*14f51593SDavid du Colombier 		join(F2);
151*14f51593SDavid du Colombier 	}else if(Bseek(f[F1], 0, 2) >= 0){
152*14f51593SDavid du Colombier 		Bseek(f[F1], off1, 0);
153*14f51593SDavid du Colombier 		Bseek(f[F2], off2, 0);
154*14f51593SDavid du Colombier 		join(F1);
155*14f51593SDavid du Colombier 	}else
156*14f51593SDavid du Colombier 		sysfatal("neither file is randomly accessible");
157219b2ee8SDavid du Colombier 	if (discard)
158*14f51593SDavid du Colombier 		sysfatal("some input line was truncated");
159219b2ee8SDavid du Colombier 	exits("");
160219b2ee8SDavid du Colombier }
161feef5247SDavid du Colombier 
162feef5247SDavid du Colombier char *
runetostr(char * buf,Rune * r)163feef5247SDavid du Colombier runetostr(char *buf, Rune *r)
164feef5247SDavid du Colombier {
165219b2ee8SDavid du Colombier 	char *s;
166feef5247SDavid du Colombier 
167feef5247SDavid du Colombier 	for(s = buf; *r; r++)
168feef5247SDavid du Colombier 		s += runetochar(s, r);
169219b2ee8SDavid du Colombier 	*s = '\0';
170219b2ee8SDavid du Colombier 	return buf;
171219b2ee8SDavid du Colombier }
172feef5247SDavid du Colombier 
173feef5247SDavid du Colombier Rune *
strtorune(Rune * buf,char * s)174feef5247SDavid du Colombier strtorune(Rune *buf, char *s)
175feef5247SDavid du Colombier {
176219b2ee8SDavid du Colombier 	Rune *r;
177feef5247SDavid du Colombier 
178feef5247SDavid du Colombier 	for (r = buf; *s; r++)
179feef5247SDavid du Colombier 		s += chartorune(r, s);
180219b2ee8SDavid du Colombier 	*r = '\0';
181219b2ee8SDavid du Colombier 	return buf;
182219b2ee8SDavid du Colombier }
183feef5247SDavid du Colombier 
184*14f51593SDavid du Colombier void
readboth(int n[])185*14f51593SDavid du Colombier readboth(int n[])
186*14f51593SDavid du Colombier {
187*14f51593SDavid du Colombier 	n[F1] = input(F1);
188*14f51593SDavid du Colombier 	n[F2] = input(F2);
189*14f51593SDavid du Colombier }
190feef5247SDavid du Colombier 
191219b2ee8SDavid du Colombier void
seekbotreadboth(int seekf,vlong bot,int n[])192*14f51593SDavid du Colombier seekbotreadboth(int seekf, vlong bot, int n[])
193219b2ee8SDavid du Colombier {
194*14f51593SDavid du Colombier 	Bseek(f[seekf], bot, 0);
195*14f51593SDavid du Colombier 	readboth(n);
196219b2ee8SDavid du Colombier }
197*14f51593SDavid du Colombier 
198219b2ee8SDavid du Colombier void
join(int seekf)199*14f51593SDavid du Colombier join(int seekf)
200219b2ee8SDavid du Colombier {
201*14f51593SDavid du Colombier 	int cmp, less;
202*14f51593SDavid du Colombier 	int n[NIN];
203*14f51593SDavid du Colombier 	vlong top, bot;
204*14f51593SDavid du Colombier 
205*14f51593SDavid du Colombier 	less = seekf == F2;
206*14f51593SDavid du Colombier 	top = 0;
207*14f51593SDavid du Colombier 	bot = Boffset(f[seekf]);
208*14f51593SDavid du Colombier 	readboth(n);
209*14f51593SDavid du Colombier 	while(n[F1]>0 && n[F2]>0 || (a1||a2) && n[F1]+n[F2]>0) {
210*14f51593SDavid du Colombier 		cmp = comp();
211*14f51593SDavid du Colombier 		if(n[F1]>0 && n[F2]>0 && cmp>0 || n[F1]==0) {
212*14f51593SDavid du Colombier 			if(a2)
213*14f51593SDavid du Colombier 				output(0, n[F2]);
214*14f51593SDavid du Colombier 			if (seekf == F2)
215*14f51593SDavid du Colombier 				bot = Boffset(f[seekf]);
216*14f51593SDavid du Colombier 			n[F2] = input(F2);
217*14f51593SDavid du Colombier 		} else if(n[F1]>0 && n[F2]>0 && cmp<0 || n[F2]==0) {
218*14f51593SDavid du Colombier 			if(a1)
219*14f51593SDavid du Colombier 				output(n[F1], 0);
220*14f51593SDavid du Colombier 			if (seekf == F1)
221*14f51593SDavid du Colombier 				bot = Boffset(f[seekf]);
222*14f51593SDavid du Colombier 			n[F1] = input(F1);
223*14f51593SDavid du Colombier 		} else {
224*14f51593SDavid du Colombier 			/* n[F1]>0 && n[F2]>0 && cmp==0 */
225*14f51593SDavid du Colombier 			while(n[F2]>0 && cmp==0) {
226*14f51593SDavid du Colombier 				output(n[F1], n[F2]);
227*14f51593SDavid du Colombier 				top = Boffset(f[seekf]);
228*14f51593SDavid du Colombier 				n[seekf] = input(seekf);
229*14f51593SDavid du Colombier 				cmp = comp();
230219b2ee8SDavid du Colombier 			}
231*14f51593SDavid du Colombier 			seekbotreadboth(seekf, bot, n);
232219b2ee8SDavid du Colombier 			for(;;) {
233*14f51593SDavid du Colombier 				cmp = comp();
234*14f51593SDavid du Colombier 				if(n[F1]>0 && n[F2]>0 && cmp==0) {
235*14f51593SDavid du Colombier 					output(n[F1], n[F2]);
236*14f51593SDavid du Colombier 					n[seekf] = input(seekf);
237*14f51593SDavid du Colombier 				} else if(n[F1]>0 && n[F2]>0 &&
238*14f51593SDavid du Colombier 				    (less? cmp<0 :cmp>0) || n[seekf]==0)
239*14f51593SDavid du Colombier 					seekbotreadboth(seekf, bot, n);
240*14f51593SDavid du Colombier 				else {
241*14f51593SDavid du Colombier 					/*
242*14f51593SDavid du Colombier 					 * n[F1]>0 && n[F2]>0 &&
243*14f51593SDavid du Colombier 					 * (less? cmp>0 :cmp<0) ||
244*14f51593SDavid du Colombier 					 * n[seekf==F1? F2: F1]==0
245*14f51593SDavid du Colombier 					 */
246*14f51593SDavid du Colombier 					Bseek(f[seekf], top, 0);
247*14f51593SDavid du Colombier 					bot = top;
248*14f51593SDavid du Colombier 					n[seekf] = input(seekf);
249219b2ee8SDavid du Colombier 					break;
250219b2ee8SDavid du Colombier 				}
251219b2ee8SDavid du Colombier 			}
252219b2ee8SDavid du Colombier 		}
253219b2ee8SDavid du Colombier 	}
254219b2ee8SDavid du Colombier }
255219b2ee8SDavid du Colombier 
256219b2ee8SDavid du Colombier int
input(int n)257219b2ee8SDavid du Colombier input(int n)		/* get input line and split into fields */
258219b2ee8SDavid du Colombier {
259*14f51593SDavid du Colombier 	int c, i, len;
260*14f51593SDavid du Colombier 	char *line;
261219b2ee8SDavid du Colombier 	Rune *bp;
262219b2ee8SDavid du Colombier 	Rune **pp;
263219b2ee8SDavid du Colombier 
264219b2ee8SDavid du Colombier 	bp = buf[n];
265219b2ee8SDavid du Colombier 	pp = ppi[n];
266*14f51593SDavid du Colombier 	line = Brdline(f[n], '\n');
267*14f51593SDavid du Colombier 	if (line == nil)
268219b2ee8SDavid du Colombier 		return(0);
269*14f51593SDavid du Colombier 	len = Blinelen(f[n]) - 1;
270*14f51593SDavid du Colombier 	c = line[len];
271*14f51593SDavid du Colombier 	line[len] = '\0';
272219b2ee8SDavid du Colombier 	strtorune(bp, line);
273*14f51593SDavid du Colombier 	line[len] = c;			/* restore delimiter */
274*14f51593SDavid du Colombier 	if (c != '\n')
275*14f51593SDavid du Colombier 		discard++;
276*14f51593SDavid du Colombier 
277219b2ee8SDavid du Colombier 	i = 0;
278219b2ee8SDavid du Colombier 	do {
279219b2ee8SDavid du Colombier 		i++;
280219b2ee8SDavid du Colombier 		if (sep1 == ' ')	/* strip multiples */
281219b2ee8SDavid du Colombier 			while ((c = *bp) == sep1 || c == sep2)
282219b2ee8SDavid du Colombier 				bp++;	/* skip blanks */
283219b2ee8SDavid du Colombier 		*pp++ = bp;		/* record beginning */
284*14f51593SDavid du Colombier 		while ((c = *bp) != sep1 && c != sep2 && c != '\0')
285219b2ee8SDavid du Colombier 			bp++;
286219b2ee8SDavid du Colombier 		*bp++ = '\0';		/* mark end by overwriting blank */
287*14f51593SDavid du Colombier 	} while (c != '\0' && i < NFLD-1);
288219b2ee8SDavid du Colombier 
289219b2ee8SDavid du Colombier 	*pp = 0;
290219b2ee8SDavid du Colombier 	return(i);
291219b2ee8SDavid du Colombier }
292219b2ee8SDavid du Colombier 
293219b2ee8SDavid du Colombier void
prfields(int f,int on,int jn)294*14f51593SDavid du Colombier prfields(int f, int on, int jn)
295*14f51593SDavid du Colombier {
296*14f51593SDavid du Colombier 	int i;
297*14f51593SDavid du Colombier 	char buf[Bsize];
298*14f51593SDavid du Colombier 
299*14f51593SDavid du Colombier 	for (i = 0; i < on; i++)
300*14f51593SDavid du Colombier 		if (i != jn)
301*14f51593SDavid du Colombier 			Bprint(bout, "%s%s", sepstr, runetostr(buf, ppi[f][i]));
302*14f51593SDavid du Colombier }
303*14f51593SDavid du Colombier 
304*14f51593SDavid du Colombier void
output(int on1,int on2)305219b2ee8SDavid du Colombier output(int on1, int on2)	/* print items from olist */
306219b2ee8SDavid du Colombier {
307219b2ee8SDavid du Colombier 	int i;
308219b2ee8SDavid du Colombier 	Rune *temp;
309*14f51593SDavid du Colombier 	char buf[Bsize];
310219b2ee8SDavid du Colombier 
311219b2ee8SDavid du Colombier 	if (no <= 0) {	/* default case */
312*14f51593SDavid du Colombier 		Bprint(bout, "%s", runetostr(buf, on1? ppi[F1][j1]: ppi[F2][j2]));
313*14f51593SDavid du Colombier 		prfields(F1, on1, j1);
314*14f51593SDavid du Colombier 		prfields(F2, on2, j2);
315*14f51593SDavid du Colombier 		Bputc(bout, '\n');
316219b2ee8SDavid du Colombier 	} else {
317219b2ee8SDavid du Colombier 		for (i = 0; i < no; i++) {
318219b2ee8SDavid du Colombier 			if (olistf[i]==F0 && on1>j1)
319219b2ee8SDavid du Colombier 				temp = ppi[F1][j1];
320219b2ee8SDavid du Colombier 			else if (olistf[i]==F0 && on2>j2)
321219b2ee8SDavid du Colombier 				temp = ppi[F2][j2];
322219b2ee8SDavid du Colombier 			else {
323219b2ee8SDavid du Colombier 				temp = ppi[olistf[i]][olist[i]];
324219b2ee8SDavid du Colombier 				if(olistf[i]==F1 && on1<=olist[i] ||
325219b2ee8SDavid du Colombier 				   olistf[i]==F2 && on2<=olist[i] ||
326219b2ee8SDavid du Colombier 				   *temp==0)
327219b2ee8SDavid du Colombier 					temp = null;
328219b2ee8SDavid du Colombier 			}
329*14f51593SDavid du Colombier 			Bprint(bout, "%s", runetostr(buf, temp));
330219b2ee8SDavid du Colombier 			if (i == no - 1)
331*14f51593SDavid du Colombier 				Bputc(bout, '\n');
332219b2ee8SDavid du Colombier 			else
333*14f51593SDavid du Colombier 				Bprint(bout, "%s", sepstr);
334219b2ee8SDavid du Colombier 		}
335219b2ee8SDavid du Colombier 	}
336219b2ee8SDavid du Colombier }
337219b2ee8SDavid du Colombier 
338219b2ee8SDavid du Colombier char *
getoptarg(int * argcp,char *** argvp)339219b2ee8SDavid du Colombier getoptarg(int *argcp, char ***argvp)
340219b2ee8SDavid du Colombier {
341219b2ee8SDavid du Colombier 	int argc = *argcp;
342219b2ee8SDavid du Colombier 	char **argv = *argvp;
343219b2ee8SDavid du Colombier 	if(argv[1][2] != 0)
344219b2ee8SDavid du Colombier 		return &argv[1][2];
345219b2ee8SDavid du Colombier 	if(argc<=2 || argv[2][0]=='-')
346*14f51593SDavid du Colombier 		sysfatal("incomplete option %s", argv[1]);
347219b2ee8SDavid du Colombier 	*argcp = argc-1;
348219b2ee8SDavid du Colombier 	*argvp = ++argv;
349219b2ee8SDavid du Colombier 	return argv[1];
350219b2ee8SDavid du Colombier }
351219b2ee8SDavid du Colombier 
352219b2ee8SDavid du Colombier void
oparse(char * s)353219b2ee8SDavid du Colombier oparse(char *s)
354219b2ee8SDavid du Colombier {
355219b2ee8SDavid du Colombier 	for (no = 0; no<2*NFLD && *s; no++, s++) {
356219b2ee8SDavid du Colombier 		switch(*s) {
357219b2ee8SDavid du Colombier 		case 0:
358219b2ee8SDavid du Colombier 			return;
359219b2ee8SDavid du Colombier 		case '0':
360219b2ee8SDavid du Colombier 			olistf[no] = F0;
361219b2ee8SDavid du Colombier 			break;
362219b2ee8SDavid du Colombier 		case '1':
363219b2ee8SDavid du Colombier 		case '2':
364219b2ee8SDavid du Colombier 			if(s[1] == '.' && isdigit(s[2])) {
365219b2ee8SDavid du Colombier 				olistf[no] = *s=='1'? F1: F2;
366219b2ee8SDavid du Colombier 				olist[no] = atoi(s += 2);
367219b2ee8SDavid du Colombier 				break;
368feef5247SDavid du Colombier 			}
369feef5247SDavid du Colombier 			/* fall thru */
370219b2ee8SDavid du Colombier 		default:
371*14f51593SDavid du Colombier 			sysfatal("invalid -o list");
372219b2ee8SDavid du Colombier 		}
373219b2ee8SDavid du Colombier 		if(s[1] == ',')
374219b2ee8SDavid du Colombier 			s++;
375219b2ee8SDavid du Colombier 	}
376219b2ee8SDavid du Colombier }
377