1
/* join F1 F2 on stuff */
9
#define NFLD 100 /* max field per line */
10
#define comp() runecmp(ppi[F1][j1],ppi[F2][j2])
12
Rune buf[2][BUFSIZ]; /*input lines */
13
Rune *ppi[2][NFLD+1]; /* pointers to fields in lines */
18
int j1 = 1; /* join of this field of file 1 */
19
int j2 = 1; /* join of this field of file 2 */
20
int olist[2*NFLD]; /* output these fields */
21
int olistf[2*NFLD]; /* from these files */
22
int no; /* number of entries in olist */
23
Rune sep1 = ' '; /* default field separator */
26
int discard; /* count of truncated lines */
27
Rune null[BUFSIZ]/* = L""*/;
31
char *getoptarg(int*, char***);
32
void output(int, int);
35
void error(char*, char*);
36
void seek1(void), seek2(void);
37
Rune *strtorune(Rune *, char *);
41
main(int argc, char **argv)
45
while (argc > 1 && argv[1][0] == '-') {
46
if (argv[1][1] == '\0')
54
switch(*getoptarg(&argc, &argv)) {
62
error("incomplete option -a","");
66
strtorune(null, getoptarg(&argc, &argv));
69
sepstr=getoptarg(&argc, &argv);
70
chartorune(&sep1, sepstr);
75
argc>2 && strchr(argv[2],',')!=0)
76
oparse(getoptarg(&argc, &argv));
77
else for (no = 0; no<2*NFLD && argc>2; no++){
78
if (argv[2][0] == '1' && argv[2][1] == '.') {
80
olist[no] = atoi(&argv[2][2]);
81
} else if (argv[2][0] == '2' && argv[2][1] == '.') {
82
olist[no] = atoi(&argv[2][2]);
84
} else if (argv[2][0] == '0')
95
if (argv[1][2] == '1')
97
else if (argv[1][2] == '2')
100
j1 = j2 = atoi(argv[2]);
105
j1 = atoi(getoptarg(&argc, &argv));
108
j2 = atoi(getoptarg(&argc, &argv));
115
for (i = 0; i < no; i++)
116
if (olist[i]-- > NFLD) /* 0 origin */
117
error("field number too big in -o","");
119
error("usage: join [-1 x -2 y] [-o list] file1 file2","");
121
j2--; /* everyone else believes in 0 origin */
124
if (strcmp(argv[1], "-") == 0)
126
else if ((f[F1] = fopen(argv[1], "r")) == 0)
127
error("can't open %s", argv[1]);
128
if(strcmp(argv[2], "-") == 0) {
130
} else if ((f[F2] = fopen(argv[2], "r")) == 0)
131
error("can't open %s", argv[2]);
133
if(ftell(f[F2]) >= 0)
135
else if(ftell(f[F1]) >= 0)
138
error("neither file is randomly accessible","");
140
error("some input line was truncated", "");
143
int runecmp(Rune *a, Rune *b){
145
if(*a=='\0') return 0;
152
char *runetostr(char *buf, Rune *r){
154
for(s=buf;*r;r++) s+=runetochar(s, r);
158
Rune *strtorune(Rune *buf, char *s){
160
for(r=buf;*s;r++) s+=chartorune(r, s);
164
/* lazy. there ought to be a clean way to combine seek1 & seek2 */
165
#define get1() n1=input(F1)
166
#define get2() n2=input(F2)
172
int bot2 = ftell(f[F2]);
175
while(n1>0 && n2>0 || (a1||a2) && n1+n2>0) {
176
if(n1>0 && n2>0 && comp()>0 || n1==0) {
177
if(a2) output(0, n2);
180
} else if(n1>0 && n2>0 && comp()<0 || n2==0) {
181
if(a1) output(n1, 0);
183
} else /*(n1>0 && n2>0 && comp()==0)*/ {
184
while(n2>0 && comp()==0) {
189
fseek(f[F2], bot2, 0);
193
if(n1>0 && n2>0 && comp()==0) {
196
} else if(n1>0 && n2>0 && comp()<0 || n2==0) {
197
fseek(f[F2], bot2, 0);
200
} else /*(n1>0 && n2>0 && comp()>0 || n1==0)*/{
201
fseek(f[F2], top2, 0);
215
int bot1 = ftell(f[F1]);
218
while(n1>0 && n2>0 || (a1||a2) && n1+n2>0) {
219
if(n1>0 && n2>0 && comp()>0 || n1==0) {
220
if(a2) output(0, n2);
222
} else if(n1>0 && n2>0 && comp()<0 || n2==0) {
223
if(a1) output(n1, 0);
226
} else /*(n1>0 && n2>0 && comp()==0)*/ {
227
while(n2>0 && comp()==0) {
232
fseek(f[F1], bot1, 0);
236
if(n1>0 && n2>0 && comp()==0) {
239
} else if(n1>0 && n2>0 && comp()>0 || n1==0) {
240
fseek(f[F1], bot1, 0);
243
} else /*(n1>0 && n2>0 && comp()<0 || n2==0)*/{
244
fseek(f[F1], top1, 0);
255
input(int n) /* get input line and split into fields */
264
if (fgets(line, BUFSIZ, f[n]) == 0)
270
if (sep1 == ' ') /* strip multiples */
271
while ((c = *bp) == sep1 || c == sep2)
272
bp++; /* skip blanks */
273
*pp++ = bp; /* record beginning */
274
while ((c = *bp) != sep1 && c != '\n' && c != sep2 && c != '\0')
276
*bp++ = '\0'; /* mark end by overwriting blank */
277
} while (c != '\n' && c != '\0' && i < NFLD-1);
286
output(int on1, int on2) /* print items from olist */
292
if (no <= 0) { /* default case */
293
printf("%s", runetostr(buf, on1? ppi[F1][j1]: ppi[F2][j2]));
294
for (i = 0; i < on1; i++)
296
printf("%s%s", sepstr, runetostr(buf, ppi[F1][i]));
297
for (i = 0; i < on2; i++)
299
printf("%s%s", sepstr, runetostr(buf, ppi[F2][i]));
302
for (i = 0; i < no; i++) {
303
if (olistf[i]==F0 && on1>j1)
305
else if (olistf[i]==F0 && on2>j2)
308
temp = ppi[olistf[i]][olist[i]];
309
if(olistf[i]==F1 && on1<=olist[i] ||
310
olistf[i]==F2 && on2<=olist[i] ||
314
printf("%s", runetostr(buf, temp));
318
printf("%s", sepstr);
324
error(char *s1, char *s2)
326
fprintf(stderr, "join: ");
327
fprintf(stderr, s1, s2);
328
fprintf(stderr, "\n");
333
getoptarg(int *argcp, char ***argvp)
336
char **argv = *argvp;
339
if(argc<=2 || argv[2][0]=='-')
340
error("incomplete option %s", argv[1]);
349
for (no = 0; no<2*NFLD && *s; no++, s++) {
358
if(s[1] == '.' && isdigit((uchar)s[2])) {
359
olistf[no] = *s=='1'? F1: F2;
360
olist[no] = atoi(s += 2);
364
error("invalid -o list", "");