source: trunk/minix/commands/simple/join.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 7.6 KB
Line 
1/* join - relation data base operator Author: Saeko Hirabayashi */
2
3/* Written by Saeko Hirabayashi, 1989.
4 * 1992-01-28 Modified by Kouichi Hirabayashi to add some POSIX1003.2 options.
5 *
6 * This a free program.
7 */
8
9#include <string.h>
10#include <stdio.h>
11
12#define MAXFLD 200 /* maximum # of fields to accept */
13
14_PROTOTYPE(void main, (int argc, char **argv));
15_PROTOTYPE(void error, (char *s, char *t));
16_PROTOTYPE(void usage, (void));
17_PROTOTYPE(void match, (void));
18_PROTOTYPE(void f1_only, (void));
19_PROTOTYPE(void f2_only, (void));
20_PROTOTYPE(void output, (int flag));
21_PROTOTYPE(void outfld, (int file));
22_PROTOTYPE(void outputf, (int flag));
23_PROTOTYPE(int compare, (void));
24_PROTOTYPE(int get1, (void));
25_PROTOTYPE(int get2, (int back));
26_PROTOTYPE(int getrec, (int file));
27_PROTOTYPE(int split, (int file));
28_PROTOTYPE(int atoi, (char *str));
29_PROTOTYPE(int exit, (int val));
30_PROTOTYPE(FILE * efopen, (char *file, char *mode));
31_PROTOTYPE(void (*outfun), (int file)); /* output func: output() or outputf()*/
32
33#define F1 1
34#define F2 2
35#define SEP (sep ? sep : ' ')
36
37FILE *fp[2]; /* file pointer for file1 and file2 */
38long head; /* head of the current (same)key group of the
39 * file2 */
40
41char buf[2][BUFSIZ]; /* input buffer for file1 and file2 */
42char *fld[2][MAXFLD]; /* field vector for file1 and file2 */
43int nfld[2]; /* # of fields for file1 and file2 */
44
45int kpos[2]; /* key field position for file1 and file2
46 * (from 0) */
47char oldkey[BUFSIZ]; /* previous key of the file1 */
48
49struct { /* output list by -o option */
50 int o_file; /* file #: 0 or 1 */
51 int o_field; /* field #: 0, 1, 2, .. */
52} olist[MAXFLD];
53int nout; /* # of output filed */
54
55int aflag; /* n for '-an': F1 or F2 or both */
56int vflag; /* n for '-vn': F1 or F2 or both */
57char *es; /* s for '-e s' */
58char sep; /* c for -tc: filed separator */
59char *cmd; /* name of this program */
60
61void main(argc, argv)
62int argc;
63char **argv;
64{
65 register char *s;
66 int c, i, j;
67
68 cmd = argv[0];
69 outfun = output; /* default output form */
70
71 while (--argc > 0 && (*++argv)[0] == '-' && (*argv)[1]) {
72 /* "-" is a file name (stdin) */
73 s = argv[0] + 1;
74 if ((c = *s) == '-' && !s[1]) {
75 ++argv;
76 --argc;
77 break; /* -- */
78 }
79 if (*++s == '\0') {
80 s = *++argv;
81 --argc;
82 }
83 switch (c) {
84 case 'a': /* add unpairable line to output */
85 vflag = 0;
86 switch (*s) {
87 case '1': aflag |= F1; break;
88 case '2': aflag |= F2; break;
89 default: aflag |= (F1 | F2); break;
90 }
91 break;
92
93 case 'e': /* replace empty field by es */
94 es = s;
95 break;
96
97 case 'j': /* key field (obsolute) */
98 c = *s++;
99 if (*s == '\0') {
100 s = *++argv;
101 --argc;
102 }
103
104 case '1': /* key field of file1 */
105 case '2': /* key field of file2 */
106 i = atoi(s) - 1;
107
108 switch (c) {
109 case '1': kpos[0] = i; break;
110 case '2': kpos[1] = i; break;
111 default: kpos[0] = kpos[1] = i;
112 break;
113 }
114 break;
115
116 case 'o': /* specify output format */
117 do {
118 i = j = 0;
119 sscanf(s, "%d.%d", &i, &j);
120 if (i < 1 || j < 1 || i > 2) usage();
121 olist[nout].o_file = i - 1;
122 olist[nout].o_field = j - 1;
123 nout++;
124 if ((s = strchr(s, ',')) != (char *) 0)
125 s++;
126 else {
127 s = *++argv;
128 --argc;
129 }
130 } while (argc > 2 && *s != '-');
131 ++argc;
132 --argv; /* compensation */
133 outfun = outputf;
134 break;
135
136 case 't': /* tab char */
137 sep = *s;
138 break;
139
140 case 'v': /* output unpairable line only */
141 aflag = 0;
142 switch (*s) {
143 case '1': vflag |= F1; break;
144 case '2': vflag |= F2; break;
145 default: vflag |= (F1 | F2); break;
146 }
147 break;
148
149 default: usage();
150 }
151 }
152 if (argc != 2) usage();
153
154 fp[0] = strcmp(argv[0], "-") ? efopen(argv[0], "r") : stdin;
155 fp[1] = efopen(argv[1], "r");
156
157 nfld[0] = get1(); /* read file1 */
158 nfld[1] = get2(0); /* read file2 */
159
160 while (nfld[0] || nfld[1]) {
161 if ((i = compare()) == 0)
162 match();
163 else if (i < 0)
164 f1_only();
165 else
166 f2_only();
167 }
168 fflush(stdout);
169
170 exit(0);
171}
172
173void usage()
174{
175 fprintf(stderr,
176 "Usage: %s [-an|-vn] [-e str] [-o list] [-tc] [-1 f] [-2 f] file1 file2\n",
177 cmd);
178 exit(1);
179}
180
181int compare()
182{ /* compare key field */
183 register int r;
184
185 if (nfld[1] == 0) /* file2 EOF */
186 r = -1;
187 else if (nfld[0] == 0) /* file1 EOF */
188 r = 1;
189 else {
190 if (nfld[0] <= kpos[0])
191 error("missing key field in file1", (char *) 0);
192 if (nfld[1] <= kpos[1])
193 error("missing key field in file2", (char *) 0);
194
195 r = strcmp(fld[0][kpos[0]], fld[1][kpos[1]]);
196 }
197 return r;
198}
199
200void match()
201{
202 long p;
203
204 if (!vflag) (*outfun) (F1 | F2);
205
206 p = ftell(fp[1]);
207 nfld[1] = get2(0); /* check key order */
208 if (nfld[1] == 0 || strcmp(fld[0][kpos[0]], fld[1][kpos[1]])) {
209 nfld[0] = get1();
210 if (strcmp(fld[0][kpos[0]], oldkey) == 0) {
211 fseek(fp[1], head, 0); /* re-do from head */
212 nfld[1] = get2(1); /* don't check key order */
213 } else
214 head = p; /* mark here */
215 }
216}
217
218void f1_only()
219{
220 if ((aflag & F1) || (vflag & F1)) (*outfun) (F1);
221 nfld[0] = get1();
222}
223
224void f2_only()
225{
226 if ((aflag & F2) || (vflag & F2)) (*outfun) (F2);
227 head = ftell(fp[1]); /* mark */
228 nfld[1] = get2(0); /* check key order */
229}
230
231void output(f)
232{ /* default output form */
233 if (f & F1)
234 fputs(fld[0][kpos[0]], stdout);
235 else
236 fputs(fld[1][kpos[1]], stdout);
237 if (f & F1) outfld(0);
238 if (f & F2) outfld(1);
239 fputc('\n', stdout);
240}
241
242void outfld(file)
243{ /* output all fields except key_field */
244 register int i;
245 int k, n;
246
247 k = kpos[file];
248 n = nfld[file];
249 for (i = 0; i < n; i++)
250 if (i != k) {
251 fputc(SEP, stdout);
252 fputs(fld[file][i], stdout);
253 }
254}
255
256void outputf(f)
257{ /* output by '-o list' */
258 int i, j, k;
259 register char *s;
260
261 for (i = k = 0; i < nout; i++) {
262 j = olist[i].o_file;
263 if ((f & (j + 1)) && (olist[i].o_field < nfld[j]))
264 s = fld[j][olist[i].o_field];
265 else
266 s = es;
267 if (s) {
268 if (k++) fputc(SEP, stdout);
269 fputs(s, stdout);
270 }
271 }
272 fputc('\n', stdout);
273}
274
275int get1()
276{ /* read file1 */
277 int r;
278 static char oldkey1[BUFSIZ];
279
280 if (fld[0][kpos[0]]) {
281 strcpy(oldkey, fld[0][kpos[0]]); /* save previous key for control */
282 }
283 r = getrec(0);
284
285 if (r) {
286 if (strcmp(oldkey1, fld[0][kpos[0]]) > 0)
287 error("file1 is not sorted", (char *) 0);
288 strcpy(oldkey1, fld[0][kpos[0]]); /* save prev key for sort check */
289 }
290 return r;
291}
292
293int get2(back)
294{ /* read file2 */
295 static char oldkey2[BUFSIZ];
296 int r;
297
298 r = getrec(1);
299
300 if (r) {
301 if (!back && strcmp(oldkey2, fld[1][kpos[1]]) > 0)
302 error("file2 is not sorted", (char *) 0);
303 strcpy(oldkey2, fld[1][kpos[1]]); /* save prev key for sort check */
304 }
305 return r;
306}
307
308int getrec(file)
309{ /* read one line to split it */
310 if (fgets(buf[file], BUFSIZ, fp[file]) == (char *) 0)
311 *buf[file] = '\0';
312 else if (*buf[file] == '\n' || *buf[file] == '\r')
313 error("null line in file%s", file ? "1" : "0");
314
315 return split(file);
316}
317
318int split(file)
319{ /* setup fields */
320 register int n;
321 register char *s, *t;
322
323 for (n = 0, s = buf[file]; *s && *s != '\n' && *s != '\r';) {
324 if (sep) {
325 for (t = s; *s && *s != sep && *s != '\n' && *s != '\r'; s++);
326 } else {
327 while (*s == ' ' || *s == '\t')
328 s++; /* skip leading white space */
329 for (t = s; *s && *s != ' ' && *s != '\t'
330 && *s != '\n' && *s != '\r'; s++);
331 /* We will treat trailing white space as NULL field */
332 }
333 if (*s) *s++ = '\0';
334 fld[file][n++] = t;
335 if (n == MAXFLD) error("too many filed in file%s", file ? "1" : "0");
336 }
337 fld[file][n] = (char *) 0;
338
339 return n;
340}
341
342FILE *efopen(file, mode)
343char *file, *mode;
344{
345 FILE *fp;
346
347 if ((fp = fopen(file, mode)) == (FILE *) 0) error("can't open %s", file);
348
349 return fp;
350}
351
352void error(s, t)
353char *s, *t;
354{
355 fprintf(stderr, "%s: ", cmd);
356 fprintf(stderr, s, t);
357 fprintf(stderr, "\n");
358
359 exit(1);
360}
Note: See TracBrowser for help on using the repository browser.