1*219b2ee8SDavid du Colombier /* join F1 F2 on stuff */ 2*219b2ee8SDavid du Colombier #include <u.h> 3*219b2ee8SDavid du Colombier #include <libc.h> 4*219b2ee8SDavid du Colombier #include <stdio.h> 5*219b2ee8SDavid du Colombier #include <ctype.h> 6*219b2ee8SDavid du Colombier #define F1 0 7*219b2ee8SDavid du Colombier #define F2 1 8*219b2ee8SDavid du Colombier #define F0 3 9*219b2ee8SDavid du Colombier #define NFLD 100 /* max field per line */ 10*219b2ee8SDavid du Colombier #define comp() runecmp(ppi[F1][j1],ppi[F2][j2]) 11*219b2ee8SDavid du Colombier FILE *f[2]; 12*219b2ee8SDavid du Colombier Rune buf[2][BUFSIZ]; /*input lines */ 13*219b2ee8SDavid du Colombier Rune *ppi[2][NFLD+1]; /* pointers to fields in lines */ 14*219b2ee8SDavid du Colombier Rune *s1,*s2; 15*219b2ee8SDavid du Colombier int j1 = 1; /* join of this field of file 1 */ 16*219b2ee8SDavid du Colombier int j2 = 1; /* join of this field of file 2 */ 17*219b2ee8SDavid du Colombier int olist[2*NFLD]; /* output these fields */ 18*219b2ee8SDavid du Colombier int olistf[2*NFLD]; /* from these files */ 19*219b2ee8SDavid du Colombier int no; /* number of entries in olist */ 20*219b2ee8SDavid du Colombier Rune sep1 = ' '; /* default field separator */ 21*219b2ee8SDavid du Colombier Rune sep2 = '\t'; 22*219b2ee8SDavid du Colombier char *sepstr=" "; 23*219b2ee8SDavid du Colombier int discard; /* count of truncated lines */ 24*219b2ee8SDavid du Colombier Rune null[BUFSIZ] = L""; 25*219b2ee8SDavid du Colombier int a1; 26*219b2ee8SDavid du Colombier int a2; 27*219b2ee8SDavid du Colombier 28*219b2ee8SDavid du Colombier char *getoptarg(int*, char***); 29*219b2ee8SDavid du Colombier void output(int, int); 30*219b2ee8SDavid du Colombier int input(int); 31*219b2ee8SDavid du Colombier void oparse(char*); 32*219b2ee8SDavid du Colombier void error(char*, char*); 33*219b2ee8SDavid du Colombier void seek1(void), seek2(void); 34*219b2ee8SDavid du Colombier Rune *strtorune(Rune *, char *); 35*219b2ee8SDavid du Colombier 36*219b2ee8SDavid du Colombier 37*219b2ee8SDavid du Colombier void 38*219b2ee8SDavid du Colombier main(int argc, char **argv) 39*219b2ee8SDavid du Colombier { 40*219b2ee8SDavid du Colombier int i; 41*219b2ee8SDavid du Colombier 42*219b2ee8SDavid du Colombier while (argc > 1 && argv[1][0] == '-') { 43*219b2ee8SDavid du Colombier if (argv[1][1] == '\0') 44*219b2ee8SDavid du Colombier break; 45*219b2ee8SDavid du Colombier switch (argv[1][1]) { 46*219b2ee8SDavid du Colombier case '-': 47*219b2ee8SDavid du Colombier argc--; 48*219b2ee8SDavid du Colombier argv++; 49*219b2ee8SDavid du Colombier goto proceed; 50*219b2ee8SDavid du Colombier case 'a': 51*219b2ee8SDavid du Colombier switch(*getoptarg(&argc, &argv)) { 52*219b2ee8SDavid du Colombier case '1': 53*219b2ee8SDavid du Colombier a1++; 54*219b2ee8SDavid du Colombier break; 55*219b2ee8SDavid du Colombier case '2': 56*219b2ee8SDavid du Colombier a2++; 57*219b2ee8SDavid du Colombier break; 58*219b2ee8SDavid du Colombier default: 59*219b2ee8SDavid du Colombier error("incomplete option -a",""); 60*219b2ee8SDavid du Colombier } 61*219b2ee8SDavid du Colombier break; 62*219b2ee8SDavid du Colombier case 'e': 63*219b2ee8SDavid du Colombier strtorune(null, getoptarg(&argc, &argv)); 64*219b2ee8SDavid du Colombier break; 65*219b2ee8SDavid du Colombier case 't': 66*219b2ee8SDavid du Colombier sepstr=getoptarg(&argc, &argv); 67*219b2ee8SDavid du Colombier chartorune(&sep1, sepstr); 68*219b2ee8SDavid du Colombier sep2 = sep1; 69*219b2ee8SDavid du Colombier break; 70*219b2ee8SDavid du Colombier case 'o': 71*219b2ee8SDavid du Colombier if(argv[1][2]!=0 || 72*219b2ee8SDavid du Colombier argc>2 && strchr(argv[2],',')!=0) 73*219b2ee8SDavid du Colombier oparse(getoptarg(&argc, &argv)); 74*219b2ee8SDavid du Colombier else for (no = 0; no<2*NFLD && argc>2; no++){ 75*219b2ee8SDavid du Colombier if (argv[2][0] == '1' && argv[2][1] == '.') { 76*219b2ee8SDavid du Colombier olistf[no] = F1; 77*219b2ee8SDavid du Colombier olist[no] = atoi(&argv[2][2]); 78*219b2ee8SDavid du Colombier } else if (argv[2][0] == '2' && argv[2][1] == '.') { 79*219b2ee8SDavid du Colombier olist[no] = atoi(&argv[2][2]); 80*219b2ee8SDavid du Colombier olistf[no] = F2; 81*219b2ee8SDavid du Colombier } else if (argv[2][0] == '0') 82*219b2ee8SDavid du Colombier olistf[no] = F0; 83*219b2ee8SDavid du Colombier else 84*219b2ee8SDavid du Colombier break; 85*219b2ee8SDavid du Colombier argc--; 86*219b2ee8SDavid du Colombier argv++; 87*219b2ee8SDavid du Colombier } 88*219b2ee8SDavid du Colombier break; 89*219b2ee8SDavid du Colombier case 'j': 90*219b2ee8SDavid du Colombier if(argc <= 2) 91*219b2ee8SDavid du Colombier break; 92*219b2ee8SDavid du Colombier if (argv[1][2] == '1') 93*219b2ee8SDavid du Colombier j1 = atoi(argv[2]); 94*219b2ee8SDavid du Colombier else if (argv[1][2] == '2') 95*219b2ee8SDavid du Colombier j2 = atoi(argv[2]); 96*219b2ee8SDavid du Colombier else 97*219b2ee8SDavid du Colombier j1 = j2 = atoi(argv[2]); 98*219b2ee8SDavid du Colombier argc--; 99*219b2ee8SDavid du Colombier argv++; 100*219b2ee8SDavid du Colombier break; 101*219b2ee8SDavid du Colombier case '1': 102*219b2ee8SDavid du Colombier j1 = atoi(getoptarg(&argc, &argv)); 103*219b2ee8SDavid du Colombier break; 104*219b2ee8SDavid du Colombier case '2': 105*219b2ee8SDavid du Colombier j2 = atoi(getoptarg(&argc, &argv)); 106*219b2ee8SDavid du Colombier break; 107*219b2ee8SDavid du Colombier } 108*219b2ee8SDavid du Colombier argc--; 109*219b2ee8SDavid du Colombier argv++; 110*219b2ee8SDavid du Colombier } 111*219b2ee8SDavid du Colombier proceed: 112*219b2ee8SDavid du Colombier for (i = 0; i < no; i++) 113*219b2ee8SDavid du Colombier if (olist[i]-- > NFLD) /* 0 origin */ 114*219b2ee8SDavid du Colombier error("field number too big in -o",""); 115*219b2ee8SDavid du Colombier if (argc != 3) 116*219b2ee8SDavid du Colombier error("usage: join [-1 x -2 y] [-o list] file1 file2",""); 117*219b2ee8SDavid du Colombier j1--; 118*219b2ee8SDavid du Colombier j2--; /* everyone else believes in 0 origin */ 119*219b2ee8SDavid du Colombier s1 = ppi[F1][j1]; 120*219b2ee8SDavid du Colombier s2 = ppi[F2][j2]; 121*219b2ee8SDavid du Colombier if (strcmp(argv[1], "-") == 0) 122*219b2ee8SDavid du Colombier f[F1] = stdin; 123*219b2ee8SDavid du Colombier else if ((f[F1] = fopen(argv[1], "r")) == 0) 124*219b2ee8SDavid du Colombier error("can't open %s", argv[1]); 125*219b2ee8SDavid du Colombier if(strcmp(argv[2], "-") == 0) { 126*219b2ee8SDavid du Colombier f[F2] = stdin; 127*219b2ee8SDavid du Colombier } else if ((f[F2] = fopen(argv[2], "r")) == 0) 128*219b2ee8SDavid du Colombier error("can't open %s", argv[2]); 129*219b2ee8SDavid du Colombier 130*219b2ee8SDavid du Colombier if(ftell(f[F2]) >= 0) 131*219b2ee8SDavid du Colombier seek2(); 132*219b2ee8SDavid du Colombier else if(ftell(f[F1]) >= 0) 133*219b2ee8SDavid du Colombier seek1(); 134*219b2ee8SDavid du Colombier else 135*219b2ee8SDavid du Colombier error("neither file is randomly accessible",""); 136*219b2ee8SDavid du Colombier if (discard) 137*219b2ee8SDavid du Colombier error("some input line was truncated", ""); 138*219b2ee8SDavid du Colombier exits(""); 139*219b2ee8SDavid du Colombier } 140*219b2ee8SDavid du Colombier int runecmp(Rune *a, Rune *b){ 141*219b2ee8SDavid du Colombier while(*a==*b){ 142*219b2ee8SDavid du Colombier if(*a=='\0') return 0; 143*219b2ee8SDavid du Colombier a++; 144*219b2ee8SDavid du Colombier b++; 145*219b2ee8SDavid du Colombier } 146*219b2ee8SDavid du Colombier if(*a<*b) return -1; 147*219b2ee8SDavid du Colombier return 1; 148*219b2ee8SDavid du Colombier } 149*219b2ee8SDavid du Colombier char *runetostr(char *buf, Rune *r){ 150*219b2ee8SDavid du Colombier char *s; 151*219b2ee8SDavid du Colombier for(s=buf;*r;r++) s+=runetochar(s, r); 152*219b2ee8SDavid du Colombier *s='\0'; 153*219b2ee8SDavid du Colombier return buf; 154*219b2ee8SDavid du Colombier } 155*219b2ee8SDavid du Colombier Rune *strtorune(Rune *buf, char *s){ 156*219b2ee8SDavid du Colombier Rune *r; 157*219b2ee8SDavid du Colombier for(r=buf;*s;r++) s+=chartorune(r, s); 158*219b2ee8SDavid du Colombier *r='\0'; 159*219b2ee8SDavid du Colombier return buf; 160*219b2ee8SDavid du Colombier } 161*219b2ee8SDavid du Colombier /* lazy. there ought to be a clean way to combine seek1 & seek2 */ 162*219b2ee8SDavid du Colombier #define get1() n1=input(F1) 163*219b2ee8SDavid du Colombier #define get2() n2=input(F2) 164*219b2ee8SDavid du Colombier void 165*219b2ee8SDavid du Colombier seek2() 166*219b2ee8SDavid du Colombier { 167*219b2ee8SDavid du Colombier int n1, n2; 168*219b2ee8SDavid du Colombier int top2=0; 169*219b2ee8SDavid du Colombier int bot2 = ftell(f[F2]); 170*219b2ee8SDavid du Colombier get1(); 171*219b2ee8SDavid du Colombier get2(); 172*219b2ee8SDavid du Colombier while(n1>0 && n2>0 || (a1||a2) && n1+n2>0) { 173*219b2ee8SDavid du Colombier if(n1>0 && n2>0 && comp()>0 || n1==0) { 174*219b2ee8SDavid du Colombier if(a2) output(0, n2); 175*219b2ee8SDavid du Colombier bot2 = ftell(f[F2]); 176*219b2ee8SDavid du Colombier get2(); 177*219b2ee8SDavid du Colombier } else if(n1>0 && n2>0 && comp()<0 || n2==0) { 178*219b2ee8SDavid du Colombier if(a1) output(n1, 0); 179*219b2ee8SDavid du Colombier get1(); 180*219b2ee8SDavid du Colombier } else /*(n1>0 && n2>0 && comp()==0)*/ { 181*219b2ee8SDavid du Colombier while(n2>0 && comp()==0) { 182*219b2ee8SDavid du Colombier output(n1, n2); 183*219b2ee8SDavid du Colombier top2 = ftell(f[F2]); 184*219b2ee8SDavid du Colombier get2(); 185*219b2ee8SDavid du Colombier } 186*219b2ee8SDavid du Colombier fseek(f[F2], bot2, 0); 187*219b2ee8SDavid du Colombier get2(); 188*219b2ee8SDavid du Colombier get1(); 189*219b2ee8SDavid du Colombier for(;;) { 190*219b2ee8SDavid du Colombier if(n1>0 && n2>0 && comp()==0) { 191*219b2ee8SDavid du Colombier output(n1, n2); 192*219b2ee8SDavid du Colombier get2(); 193*219b2ee8SDavid du Colombier } else if(n1>0 && n2>0 && comp()<0 || n2==0) { 194*219b2ee8SDavid du Colombier fseek(f[F2], bot2, 0); 195*219b2ee8SDavid du Colombier get2(); 196*219b2ee8SDavid du Colombier get1(); 197*219b2ee8SDavid du Colombier } else /*(n1>0 && n2>0 && comp()>0 || n1==0)*/{ 198*219b2ee8SDavid du Colombier fseek(f[F2], top2, 0); 199*219b2ee8SDavid du Colombier bot2 = top2; 200*219b2ee8SDavid du Colombier get2(); 201*219b2ee8SDavid du Colombier break; 202*219b2ee8SDavid du Colombier } 203*219b2ee8SDavid du Colombier } 204*219b2ee8SDavid du Colombier } 205*219b2ee8SDavid du Colombier } 206*219b2ee8SDavid du Colombier } 207*219b2ee8SDavid du Colombier void 208*219b2ee8SDavid du Colombier seek1() 209*219b2ee8SDavid du Colombier { 210*219b2ee8SDavid du Colombier int n1, n2; 211*219b2ee8SDavid du Colombier int top1=0; 212*219b2ee8SDavid du Colombier int bot1 = ftell(f[F1]); 213*219b2ee8SDavid du Colombier get1(); 214*219b2ee8SDavid du Colombier get2(); 215*219b2ee8SDavid du Colombier while(n1>0 && n2>0 || (a1||a2) && n1+n2>0) { 216*219b2ee8SDavid du Colombier if(n1>0 && n2>0 && comp()>0 || n1==0) { 217*219b2ee8SDavid du Colombier if(a2) output(0, n2); 218*219b2ee8SDavid du Colombier get2(); 219*219b2ee8SDavid du Colombier } else if(n1>0 && n2>0 && comp()<0 || n2==0) { 220*219b2ee8SDavid du Colombier if(a1) output(n1, 0); 221*219b2ee8SDavid du Colombier bot1 = ftell(f[F1]); 222*219b2ee8SDavid du Colombier get1(); 223*219b2ee8SDavid du Colombier } else /*(n1>0 && n2>0 && comp()==0)*/ { 224*219b2ee8SDavid du Colombier while(n2>0 && comp()==0) { 225*219b2ee8SDavid du Colombier output(n1, n2); 226*219b2ee8SDavid du Colombier top1 = ftell(f[F1]); 227*219b2ee8SDavid du Colombier get1(); 228*219b2ee8SDavid du Colombier } 229*219b2ee8SDavid du Colombier fseek(f[F1], bot1, 0); 230*219b2ee8SDavid du Colombier get2(); 231*219b2ee8SDavid du Colombier get1(); 232*219b2ee8SDavid du Colombier for(;;) { 233*219b2ee8SDavid du Colombier if(n1>0 && n2>0 && comp()==0) { 234*219b2ee8SDavid du Colombier output(n1, n2); 235*219b2ee8SDavid du Colombier get1(); 236*219b2ee8SDavid du Colombier } else if(n1>0 && n2>0 && comp()>0 || n1==0) { 237*219b2ee8SDavid du Colombier fseek(f[F1], bot1, 0); 238*219b2ee8SDavid du Colombier get2(); 239*219b2ee8SDavid du Colombier get1(); 240*219b2ee8SDavid du Colombier } else /*(n1>0 && n2>0 && comp()<0 || n2==0)*/{ 241*219b2ee8SDavid du Colombier fseek(f[F1], top1, 0); 242*219b2ee8SDavid du Colombier bot1 = top1; 243*219b2ee8SDavid du Colombier get1(); 244*219b2ee8SDavid du Colombier break; 245*219b2ee8SDavid du Colombier } 246*219b2ee8SDavid du Colombier } 247*219b2ee8SDavid du Colombier } 248*219b2ee8SDavid du Colombier } 249*219b2ee8SDavid du Colombier } 250*219b2ee8SDavid du Colombier 251*219b2ee8SDavid du Colombier int 252*219b2ee8SDavid du Colombier input(int n) /* get input line and split into fields */ 253*219b2ee8SDavid du Colombier { 254*219b2ee8SDavid du Colombier register int i, c; 255*219b2ee8SDavid du Colombier Rune *bp; 256*219b2ee8SDavid du Colombier Rune **pp; 257*219b2ee8SDavid du Colombier char line[BUFSIZ]; 258*219b2ee8SDavid du Colombier 259*219b2ee8SDavid du Colombier bp = buf[n]; 260*219b2ee8SDavid du Colombier pp = ppi[n]; 261*219b2ee8SDavid du Colombier if (fgets(line, BUFSIZ, f[n]) == 0) 262*219b2ee8SDavid du Colombier return(0); 263*219b2ee8SDavid du Colombier strtorune(bp, line); 264*219b2ee8SDavid du Colombier i = 0; 265*219b2ee8SDavid du Colombier do { 266*219b2ee8SDavid du Colombier i++; 267*219b2ee8SDavid du Colombier if (sep1 == ' ') /* strip multiples */ 268*219b2ee8SDavid du Colombier while ((c = *bp) == sep1 || c == sep2) 269*219b2ee8SDavid du Colombier bp++; /* skip blanks */ 270*219b2ee8SDavid du Colombier *pp++ = bp; /* record beginning */ 271*219b2ee8SDavid du Colombier while ((c = *bp) != sep1 && c != '\n' && c != sep2 && c != '\0') 272*219b2ee8SDavid du Colombier bp++; 273*219b2ee8SDavid du Colombier *bp++ = '\0'; /* mark end by overwriting blank */ 274*219b2ee8SDavid du Colombier } while (c != '\n' && c != '\0' && i < NFLD-1); 275*219b2ee8SDavid du Colombier if (c != '\n') 276*219b2ee8SDavid du Colombier discard++; 277*219b2ee8SDavid du Colombier 278*219b2ee8SDavid du Colombier *pp = 0; 279*219b2ee8SDavid du Colombier return(i); 280*219b2ee8SDavid du Colombier } 281*219b2ee8SDavid du Colombier 282*219b2ee8SDavid du Colombier void 283*219b2ee8SDavid du Colombier output(int on1, int on2) /* print items from olist */ 284*219b2ee8SDavid du Colombier { 285*219b2ee8SDavid du Colombier int i; 286*219b2ee8SDavid du Colombier Rune *temp; 287*219b2ee8SDavid du Colombier char buf[BUFSIZ]; 288*219b2ee8SDavid du Colombier 289*219b2ee8SDavid du Colombier if (no <= 0) { /* default case */ 290*219b2ee8SDavid du Colombier printf("%s", runetostr(buf, on1? ppi[F1][j1]: ppi[F2][j2])); 291*219b2ee8SDavid du Colombier for (i = 0; i < on1; i++) 292*219b2ee8SDavid du Colombier if (i != j1) 293*219b2ee8SDavid du Colombier printf("%s%s", sepstr, runetostr(buf, ppi[F1][i])); 294*219b2ee8SDavid du Colombier for (i = 0; i < on2; i++) 295*219b2ee8SDavid du Colombier if (i != j2) 296*219b2ee8SDavid du Colombier printf("%s%s", sepstr, runetostr(buf, ppi[F2][i])); 297*219b2ee8SDavid du Colombier printf("\n"); 298*219b2ee8SDavid du Colombier } else { 299*219b2ee8SDavid du Colombier for (i = 0; i < no; i++) { 300*219b2ee8SDavid du Colombier if (olistf[i]==F0 && on1>j1) 301*219b2ee8SDavid du Colombier temp = ppi[F1][j1]; 302*219b2ee8SDavid du Colombier else if (olistf[i]==F0 && on2>j2) 303*219b2ee8SDavid du Colombier temp = ppi[F2][j2]; 304*219b2ee8SDavid du Colombier else { 305*219b2ee8SDavid du Colombier temp = ppi[olistf[i]][olist[i]]; 306*219b2ee8SDavid du Colombier if(olistf[i]==F1 && on1<=olist[i] || 307*219b2ee8SDavid du Colombier olistf[i]==F2 && on2<=olist[i] || 308*219b2ee8SDavid du Colombier *temp==0) 309*219b2ee8SDavid du Colombier temp = null; 310*219b2ee8SDavid du Colombier } 311*219b2ee8SDavid du Colombier printf("%s", runetostr(buf, temp)); 312*219b2ee8SDavid du Colombier if (i == no - 1) 313*219b2ee8SDavid du Colombier printf("\n"); 314*219b2ee8SDavid du Colombier else 315*219b2ee8SDavid du Colombier printf("%s", sepstr); 316*219b2ee8SDavid du Colombier } 317*219b2ee8SDavid du Colombier } 318*219b2ee8SDavid du Colombier } 319*219b2ee8SDavid du Colombier 320*219b2ee8SDavid du Colombier void 321*219b2ee8SDavid du Colombier error(char *s1, char *s2) 322*219b2ee8SDavid du Colombier { 323*219b2ee8SDavid du Colombier fprintf(stderr, "join: "); 324*219b2ee8SDavid du Colombier fprintf(stderr, s1, s2); 325*219b2ee8SDavid du Colombier fprintf(stderr, "\n"); 326*219b2ee8SDavid du Colombier exits(s1); 327*219b2ee8SDavid du Colombier } 328*219b2ee8SDavid du Colombier 329*219b2ee8SDavid du Colombier char * 330*219b2ee8SDavid du Colombier getoptarg(int *argcp, char ***argvp) 331*219b2ee8SDavid du Colombier { 332*219b2ee8SDavid du Colombier int argc = *argcp; 333*219b2ee8SDavid du Colombier char **argv = *argvp; 334*219b2ee8SDavid du Colombier if(argv[1][2] != 0) 335*219b2ee8SDavid du Colombier return &argv[1][2]; 336*219b2ee8SDavid du Colombier if(argc<=2 || argv[2][0]=='-') 337*219b2ee8SDavid du Colombier error("incomplete option %s", argv[1]); 338*219b2ee8SDavid du Colombier *argcp = argc-1; 339*219b2ee8SDavid du Colombier *argvp = ++argv; 340*219b2ee8SDavid du Colombier return argv[1]; 341*219b2ee8SDavid du Colombier } 342*219b2ee8SDavid du Colombier 343*219b2ee8SDavid du Colombier void 344*219b2ee8SDavid du Colombier oparse(char *s) 345*219b2ee8SDavid du Colombier { 346*219b2ee8SDavid du Colombier for (no = 0; no<2*NFLD && *s; no++, s++) { 347*219b2ee8SDavid du Colombier switch(*s) { 348*219b2ee8SDavid du Colombier case 0: 349*219b2ee8SDavid du Colombier return; 350*219b2ee8SDavid du Colombier case '0': 351*219b2ee8SDavid du Colombier olistf[no] = F0; 352*219b2ee8SDavid du Colombier break; 353*219b2ee8SDavid du Colombier case '1': 354*219b2ee8SDavid du Colombier case '2': 355*219b2ee8SDavid du Colombier if(s[1] == '.' && isdigit(s[2])) { 356*219b2ee8SDavid du Colombier olistf[no] = *s=='1'? F1: F2; 357*219b2ee8SDavid du Colombier olist[no] = atoi(s += 2); 358*219b2ee8SDavid du Colombier break; 359*219b2ee8SDavid du Colombier } /* fall thru */ 360*219b2ee8SDavid du Colombier default: 361*219b2ee8SDavid du Colombier error("invalid -o list", ""); 362*219b2ee8SDavid du Colombier } 363*219b2ee8SDavid du Colombier if(s[1] == ',') 364*219b2ee8SDavid du Colombier s++; 365*219b2ee8SDavid du Colombier } 366*219b2ee8SDavid du Colombier } 367