xref: /original-bsd/usr.bin/join/join.c (revision 7bad34b3)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1991 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)join.c	4.3 (Berkeley) 04/17/91";
16 #endif /* not lint */
17 
18 /*	join F1 F2 on stuff */
19 
20 #include	<stdio.h>
21 #define F1 0
22 #define F2 1
23 #define	NFLD	20	/* max field per line */
24 #define comp() cmp(ppi[F1][j1],ppi[F2][j2])
25 
26 FILE *f[2];
27 char buf[2][BUFSIZ];	/*input lines */
28 char *ppi[2][NFLD];	/* pointers to fields in lines */
29 char *s1,*s2;
30 int	j1	= 1;	/* join of this field of file 1 */
31 int	j2	= 1;	/* join of this field of file 2 */
32 int	olist[2*NFLD];	/* output these fields */
33 int	olistf[2*NFLD];	/* from these files */
34 int	no;	/* number of entries in olist */
35 int	sep1	= ' ';	/* default field separator */
36 int	sep2	= '\t';
37 char*	null	= "";
38 int	unpub1;
39 int	unpub2;
40 int	aflg;
41 
42 main(argc, argv)
43 char *argv[];
44 {
45 	int i;
46 	int n1, n2;
47 	long top2, bot2;
48 	long ftell();
49 
50 	while (argc > 1 && argv[1][0] == '-') {
51 		if (argv[1][1] == '\0')
52 			break;
53 		switch (argv[1][1]) {
54 		case 'a':
55 			switch(argv[1][2]) {
56 			case '1':
57 				aflg |= 1;
58 				break;
59 			case '2':
60 				aflg |= 2;
61 				break;
62 			default:
63 				aflg |= 3;
64 			}
65 			break;
66 		case 'e':
67 			null = argv[2];
68 			argv++;
69 			argc--;
70 			break;
71 		case 't':
72 			sep1 = sep2 = argv[1][2];
73 			break;
74 		case 'o':
75 			for (no = 0; no < 2*NFLD; no++) {
76 				if (argv[2][0] == '1' && argv[2][1] == '.') {
77 					olistf[no] = F1;
78 					olist[no] = atoi(&argv[2][2]);
79 				} else if (argv[2][0] == '2' && argv[2][1] == '.') {
80 					olist[no] = atoi(&argv[2][2]);
81 					olistf[no] = F2;
82 				} else
83 					break;
84 				argc--;
85 				argv++;
86 			}
87 			break;
88 		case 'j':
89 			if (argv[1][2] == '1')
90 				j1 = atoi(argv[2]);
91 			else if (argv[1][2] == '2')
92 				j2 = atoi(argv[2]);
93 			else
94 				j1 = j2 = atoi(argv[2]);
95 			argc--;
96 			argv++;
97 			break;
98 		}
99 		argc--;
100 		argv++;
101 	}
102 	for (i = 0; i < no; i++)
103 		olist[i]--;	/* 0 origin */
104 	if (argc != 3)
105 error("usage: join [-an] [-estring] [-j1 x -j2 y] [-o list] [-tc] file1 file2");
106 	j1--;
107 	j2--;	/* everyone else believes in 0 origin */
108 	s1 = ppi[F1][j1];
109 	s2 = ppi[F2][j2];
110 	if (argv[1][0] == '-')
111 		f[F1] = stdin;
112 	else if ((f[F1] = fopen(argv[1], "r")) == NULL)
113 		error("can't open %s", argv[1]);
114 	if ((f[F2] = fopen(argv[2], "r")) == NULL)
115 		error("can't open %s", argv[2]);
116 
117 #define get1() n1=input(F1)
118 #define get2() n2=input(F2)
119 	get1();
120 	bot2 = ftell(f[F2]);
121 	get2();
122 	while(n1>0 && n2>0 || aflg!=0 && n1+n2>0) {
123 		if(n1>0 && n2>0 && comp()>0 || n1==0) {
124 			if(aflg&2) output(0, n2);
125 			bot2 = ftell(f[F2]);
126 			get2();
127 		} else if(n1>0 && n2>0 && comp()<0 || n2==0) {
128 			if(aflg&1) output(n1, 0);
129 			get1();
130 		} else /*(n1>0 && n2>0 && comp()==0)*/ {
131 			while(n2>0 && comp()==0) {
132 				output(n1, n2);
133 				top2 = ftell(f[F2]);
134 				get2();
135 			}
136 			fseek(f[F2], bot2, 0);
137 			get2();
138 			get1();
139 			for(;;) {
140 				if(n1>0 && n2>0 && comp()==0) {
141 					output(n1, n2);
142 					get2();
143 				} else if(n1>0 && n2>0 && comp()<0 || n2==0) {
144 					fseek(f[F2], bot2, 0);
145 					get2();
146 					get1();
147 				} else /*(n1>0 && n2>0 && comp()>0 || n1==0)*/{
148 					fseek(f[F2], top2, 0);
149 					bot2 = top2;
150 					get2();
151 					break;
152 				}
153 			}
154 		}
155 	}
156 	return(0);
157 }
158 
159 input(n)		/* get input line and split into fields */
160 {
161 	register int i, c;
162 	char *bp;
163 	char **pp;
164 
165 	bp = buf[n];
166 	pp = ppi[n];
167 	if (fgets(bp, BUFSIZ, f[n]) == NULL)
168 		return(0);
169 	for (i = 0; ; i++) {
170 		if (sep1 == ' ')	/* strip multiples */
171 			while ((c = *bp) == sep1 || c == sep2)
172 				bp++;	/* skip blanks */
173 		else
174 			c = *bp;
175 		if (c == '\n' || c == '\0')
176 			break;
177 		*pp++ = bp;	/* record beginning */
178 		while ((c = *bp) != sep1 && c != '\n' && c != sep2 && c != '\0')
179 			bp++;
180 		*bp++ = '\0';	/* mark end by overwriting blank */
181 			/* fails badly if string doesn't have \n at end */
182 	}
183 	*pp = 0;
184 	return(i);
185 }
186 
187 output(on1, on2)	/* print items from olist */
188 int on1, on2;
189 {
190 	int i;
191 	char *temp;
192 
193 	if (no <= 0) {	/* default case */
194 		printf("%s", on1? ppi[F1][j1]: ppi[F2][j2]);
195 		for (i = 0; i < on1; i++)
196 			if (i != j1)
197 				printf("%c%s", sep1, ppi[F1][i]);
198 		for (i = 0; i < on2; i++)
199 			if (i != j2)
200 				printf("%c%s", sep1, ppi[F2][i]);
201 		printf("\n");
202 	} else {
203 		for (i = 0; i < no; i++) {
204 			temp = ppi[olistf[i]][olist[i]];
205 			if(olistf[i]==F1 && on1<=olist[i] ||
206 			   olistf[i]==F2 && on2<=olist[i] ||
207 			   *temp==0)
208 				temp = null;
209 			printf("%s", temp);
210 			if (i == no - 1)
211 				printf("\n");
212 			else
213 				printf("%c", sep1);
214 		}
215 	}
216 }
217 
218 error(s1, s2, s3, s4, s5)
219 char *s1;
220 {
221 	fprintf(stderr, "join: ");
222 	fprintf(stderr, s1, s2, s3, s4, s5);
223 	fprintf(stderr, "\n");
224 	exit(1);
225 }
226 
227 cmp(s1, s2)
228 char *s1, *s2;
229 {
230 	return(strcmp(s1, s2));
231 }
232