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 */
15 int j1 = 1; /* join of this field of file 1 */
16 int j2 = 1; /* join of this field of file 2 */
17 int olist[2*NFLD]; /* output these fields */
18 int olistf[2*NFLD]; /* from these files */
19 int no; /* number of entries in olist */
20 Rune sep1 = ' '; /* default field separator */
23 int discard; /* count of truncated lines */
24 Rune null[BUFSIZ] = L"";
28 char *getoptarg(int*, char***);
29 void output(int, int);
32 void error(char*, char*);
33 void seek1(void), seek2(void);
34 Rune *strtorune(Rune *, char *);
38 main(int argc, char **argv)
42 while (argc > 1 && argv[1][0] == '-') {
43 if (argv[1][1] == '\0')
51 switch(*getoptarg(&argc, &argv)) {
59 error("incomplete option -a","");
63 strtorune(null, getoptarg(&argc, &argv));
66 sepstr=getoptarg(&argc, &argv);
67 chartorune(&sep1, sepstr);
72 argc>2 && strchr(argv[2],',')!=0)
73 oparse(getoptarg(&argc, &argv));
74 else for (no = 0; no<2*NFLD && argc>2; no++){
75 if (argv[2][0] == '1' && argv[2][1] == '.') {
77 olist[no] = atoi(&argv[2][2]);
78 } else if (argv[2][0] == '2' && argv[2][1] == '.') {
79 olist[no] = atoi(&argv[2][2]);
81 } else if (argv[2][0] == '0')
92 if (argv[1][2] == '1')
94 else if (argv[1][2] == '2')
97 j1 = j2 = atoi(argv[2]);
102 j1 = atoi(getoptarg(&argc, &argv));
105 j2 = atoi(getoptarg(&argc, &argv));
112 for (i = 0; i < no; i++)
113 if (olist[i]-- > NFLD) /* 0 origin */
114 error("field number too big in -o","");
116 error("usage: join [-1 x -2 y] [-o list] file1 file2","");
117 if (j1 < 1 || j2 < 1)
118 error("invalid field indices", "");
120 j2--; /* everyone else believes in 0 origin */
123 if (strcmp(argv[1], "-") == 0)
125 else if ((f[F1] = fopen(argv[1], "r")) == 0)
126 error("can't open %s", argv[1]);
127 if(strcmp(argv[2], "-") == 0) {
129 } else if ((f[F2] = fopen(argv[2], "r")) == 0)
130 error("can't open %s", argv[2]);
132 if(ftell(f[F2]) >= 0)
134 else if(ftell(f[F1]) >= 0)
137 error("neither file is randomly accessible","");
139 error("some input line was truncated", "");
142 int runecmp(Rune *a, Rune *b){
144 if(*a=='\0') return 0;
151 char *runetostr(char *buf, Rune *r){
153 for(s=buf;*r;r++) s+=runetochar(s, r);
157 Rune *strtorune(Rune *buf, char *s){
159 for(r=buf;*s;r++) s+=chartorune(r, s);
163 /* lazy. there ought to be a clean way to combine seek1 & seek2 */
164 #define get1() n1=input(F1)
165 #define get2() n2=input(F2)
171 int bot2 = ftell(f[F2]);
174 while(n1>0 && n2>0 || (a1||a2) && n1+n2>0) {
175 if(n1>0 && n2>0 && comp()>0 || n1==0) {
176 if(a2) output(0, n2);
179 } else if(n1>0 && n2>0 && comp()<0 || n2==0) {
180 if(a1) output(n1, 0);
182 } else /*(n1>0 && n2>0 && comp()==0)*/ {
183 while(n2>0 && comp()==0) {
188 fseek(f[F2], bot2, 0);
192 if(n1>0 && n2>0 && comp()==0) {
195 } else if(n1>0 && n2>0 && comp()<0 || n2==0) {
196 fseek(f[F2], bot2, 0);
199 } else /*(n1>0 && n2>0 && comp()>0 || n1==0)*/{
200 fseek(f[F2], top2, 0);
214 int bot1 = ftell(f[F1]);
217 while(n1>0 && n2>0 || (a1||a2) && n1+n2>0) {
218 if(n1>0 && n2>0 && comp()>0 || n1==0) {
219 if(a2) output(0, n2);
221 } else if(n1>0 && n2>0 && comp()<0 || n2==0) {
222 if(a1) output(n1, 0);
225 } else /*(n1>0 && n2>0 && comp()==0)*/ {
226 while(n2>0 && comp()==0) {
231 fseek(f[F1], bot1, 0);
235 if(n1>0 && n2>0 && comp()==0) {
238 } else if(n1>0 && n2>0 && comp()>0 || n1==0) {
239 fseek(f[F1], bot1, 0);
242 } else /*(n1>0 && n2>0 && comp()<0 || n2==0)*/{
243 fseek(f[F1], top1, 0);
254 input(int n) /* get input line and split into fields */
263 if (fgets(line, BUFSIZ, f[n]) == 0)
269 if (sep1 == ' ') /* strip multiples */
270 while ((c = *bp) == sep1 || c == sep2)
271 bp++; /* skip blanks */
272 *pp++ = bp; /* record beginning */
273 while ((c = *bp) != sep1 && c != '\n' && c != sep2 && c != '\0')
275 *bp++ = '\0'; /* mark end by overwriting blank */
276 } while (c != '\n' && c != '\0' && i < NFLD-1);
285 output(int on1, int on2) /* print items from olist */
291 if (no <= 0) { /* default case */
292 printf("%s", runetostr(buf, on1? ppi[F1][j1]: ppi[F2][j2]));
293 for (i = 0; i < on1; i++)
295 printf("%s%s", sepstr, runetostr(buf, ppi[F1][i]));
296 for (i = 0; i < on2; i++)
298 printf("%s%s", sepstr, runetostr(buf, ppi[F2][i]));
301 for (i = 0; i < no; i++) {
302 if (olistf[i]==F0 && on1>j1)
304 else if (olistf[i]==F0 && on2>j2)
307 temp = ppi[olistf[i]][olist[i]];
308 if(olistf[i]==F1 && on1<=olist[i] ||
309 olistf[i]==F2 && on2<=olist[i] ||
313 printf("%s", runetostr(buf, temp));
317 printf("%s", sepstr);
323 error(char *s1, char *s2)
325 fprintf(stderr, "join: ");
326 fprintf(stderr, s1, s2);
327 fprintf(stderr, "\n");
332 getoptarg(int *argcp, char ***argvp)
335 char **argv = *argvp;
338 if(argc<=2 || argv[2][0]=='-')
339 error("incomplete option %s", argv[1]);
348 for (no = 0; no<2*NFLD && *s; no++, s++) {
357 if(s[1] == '.' && isdigit(s[2])) {
358 olistf[no] = *s=='1'? F1: F2;
359 olist[no] = atoi(s += 2);
363 error("invalid -o list", "");