new utilities.
the .C files compile but are renamed to avoid building automatically.
This commit is contained in:
parent
f08fdedcee
commit
bc7cb1a15a
45 changed files with 16585 additions and 0 deletions
369
src/cmd/join.c
Normal file
369
src/cmd/join.c
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
/* join F1 F2 on stuff */
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#define F1 0
|
||||
#define F2 1
|
||||
#define F0 3
|
||||
#define NFLD 100 /* max field per line */
|
||||
#define comp() runecmp(ppi[F1][j1],ppi[F2][j2])
|
||||
FILE *f[2];
|
||||
Rune buf[2][BUFSIZ]; /*input lines */
|
||||
Rune *ppi[2][NFLD+1]; /* pointers to fields in lines */
|
||||
Rune *s1,*s2;
|
||||
#define j1 joinj1
|
||||
#define j2 joinj2
|
||||
|
||||
int j1 = 1; /* join of this field of file 1 */
|
||||
int j2 = 1; /* join of this field of file 2 */
|
||||
int olist[2*NFLD]; /* output these fields */
|
||||
int olistf[2*NFLD]; /* from these files */
|
||||
int no; /* number of entries in olist */
|
||||
Rune sep1 = ' '; /* default field separator */
|
||||
Rune sep2 = '\t';
|
||||
char *sepstr=" ";
|
||||
int discard; /* count of truncated lines */
|
||||
Rune null[BUFSIZ]/* = L""*/;
|
||||
int a1;
|
||||
int a2;
|
||||
|
||||
char *getoptarg(int*, char***);
|
||||
void output(int, int);
|
||||
int input(int);
|
||||
void oparse(char*);
|
||||
void error(char*, char*);
|
||||
void seek1(void), seek2(void);
|
||||
Rune *strtorune(Rune *, char *);
|
||||
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
while (argc > 1 && argv[1][0] == '-') {
|
||||
if (argv[1][1] == '\0')
|
||||
break;
|
||||
switch (argv[1][1]) {
|
||||
case '-':
|
||||
argc--;
|
||||
argv++;
|
||||
goto proceed;
|
||||
case 'a':
|
||||
switch(*getoptarg(&argc, &argv)) {
|
||||
case '1':
|
||||
a1++;
|
||||
break;
|
||||
case '2':
|
||||
a2++;
|
||||
break;
|
||||
default:
|
||||
error("incomplete option -a","");
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
strtorune(null, getoptarg(&argc, &argv));
|
||||
break;
|
||||
case 't':
|
||||
sepstr=getoptarg(&argc, &argv);
|
||||
chartorune(&sep1, sepstr);
|
||||
sep2 = sep1;
|
||||
break;
|
||||
case 'o':
|
||||
if(argv[1][2]!=0 ||
|
||||
argc>2 && strchr(argv[2],',')!=0)
|
||||
oparse(getoptarg(&argc, &argv));
|
||||
else for (no = 0; no<2*NFLD && argc>2; no++){
|
||||
if (argv[2][0] == '1' && argv[2][1] == '.') {
|
||||
olistf[no] = F1;
|
||||
olist[no] = atoi(&argv[2][2]);
|
||||
} else if (argv[2][0] == '2' && argv[2][1] == '.') {
|
||||
olist[no] = atoi(&argv[2][2]);
|
||||
olistf[no] = F2;
|
||||
} else if (argv[2][0] == '0')
|
||||
olistf[no] = F0;
|
||||
else
|
||||
break;
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
break;
|
||||
case 'j':
|
||||
if(argc <= 2)
|
||||
break;
|
||||
if (argv[1][2] == '1')
|
||||
j1 = atoi(argv[2]);
|
||||
else if (argv[1][2] == '2')
|
||||
j2 = atoi(argv[2]);
|
||||
else
|
||||
j1 = j2 = atoi(argv[2]);
|
||||
argc--;
|
||||
argv++;
|
||||
break;
|
||||
case '1':
|
||||
j1 = atoi(getoptarg(&argc, &argv));
|
||||
break;
|
||||
case '2':
|
||||
j2 = atoi(getoptarg(&argc, &argv));
|
||||
break;
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
proceed:
|
||||
for (i = 0; i < no; i++)
|
||||
if (olist[i]-- > NFLD) /* 0 origin */
|
||||
error("field number too big in -o","");
|
||||
if (argc != 3)
|
||||
error("usage: join [-1 x -2 y] [-o list] file1 file2","");
|
||||
j1--;
|
||||
j2--; /* everyone else believes in 0 origin */
|
||||
s1 = ppi[F1][j1];
|
||||
s2 = ppi[F2][j2];
|
||||
if (strcmp(argv[1], "-") == 0)
|
||||
f[F1] = stdin;
|
||||
else if ((f[F1] = fopen(argv[1], "r")) == 0)
|
||||
error("can't open %s", argv[1]);
|
||||
if(strcmp(argv[2], "-") == 0) {
|
||||
f[F2] = stdin;
|
||||
} else if ((f[F2] = fopen(argv[2], "r")) == 0)
|
||||
error("can't open %s", argv[2]);
|
||||
|
||||
if(ftell(f[F2]) >= 0)
|
||||
seek2();
|
||||
else if(ftell(f[F1]) >= 0)
|
||||
seek1();
|
||||
else
|
||||
error("neither file is randomly accessible","");
|
||||
if (discard)
|
||||
error("some input line was truncated", "");
|
||||
exits("");
|
||||
}
|
||||
int runecmp(Rune *a, Rune *b){
|
||||
while(*a==*b){
|
||||
if(*a=='\0') return 0;
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
if(*a<*b) return -1;
|
||||
return 1;
|
||||
}
|
||||
char *runetostr(char *buf, Rune *r){
|
||||
char *s;
|
||||
for(s=buf;*r;r++) s+=runetochar(s, r);
|
||||
*s='\0';
|
||||
return buf;
|
||||
}
|
||||
Rune *strtorune(Rune *buf, char *s){
|
||||
Rune *r;
|
||||
for(r=buf;*s;r++) s+=chartorune(r, s);
|
||||
*r='\0';
|
||||
return buf;
|
||||
}
|
||||
/* lazy. there ought to be a clean way to combine seek1 & seek2 */
|
||||
#define get1() n1=input(F1)
|
||||
#define get2() n2=input(F2)
|
||||
void
|
||||
seek2()
|
||||
{
|
||||
int n1, n2;
|
||||
int top2=0;
|
||||
int bot2 = ftell(f[F2]);
|
||||
get1();
|
||||
get2();
|
||||
while(n1>0 && n2>0 || (a1||a2) && n1+n2>0) {
|
||||
if(n1>0 && n2>0 && comp()>0 || n1==0) {
|
||||
if(a2) output(0, n2);
|
||||
bot2 = ftell(f[F2]);
|
||||
get2();
|
||||
} else if(n1>0 && n2>0 && comp()<0 || n2==0) {
|
||||
if(a1) output(n1, 0);
|
||||
get1();
|
||||
} else /*(n1>0 && n2>0 && comp()==0)*/ {
|
||||
while(n2>0 && comp()==0) {
|
||||
output(n1, n2);
|
||||
top2 = ftell(f[F2]);
|
||||
get2();
|
||||
}
|
||||
fseek(f[F2], bot2, 0);
|
||||
get2();
|
||||
get1();
|
||||
for(;;) {
|
||||
if(n1>0 && n2>0 && comp()==0) {
|
||||
output(n1, n2);
|
||||
get2();
|
||||
} else if(n1>0 && n2>0 && comp()<0 || n2==0) {
|
||||
fseek(f[F2], bot2, 0);
|
||||
get2();
|
||||
get1();
|
||||
} else /*(n1>0 && n2>0 && comp()>0 || n1==0)*/{
|
||||
fseek(f[F2], top2, 0);
|
||||
bot2 = top2;
|
||||
get2();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void
|
||||
seek1()
|
||||
{
|
||||
int n1, n2;
|
||||
int top1=0;
|
||||
int bot1 = ftell(f[F1]);
|
||||
get1();
|
||||
get2();
|
||||
while(n1>0 && n2>0 || (a1||a2) && n1+n2>0) {
|
||||
if(n1>0 && n2>0 && comp()>0 || n1==0) {
|
||||
if(a2) output(0, n2);
|
||||
get2();
|
||||
} else if(n1>0 && n2>0 && comp()<0 || n2==0) {
|
||||
if(a1) output(n1, 0);
|
||||
bot1 = ftell(f[F1]);
|
||||
get1();
|
||||
} else /*(n1>0 && n2>0 && comp()==0)*/ {
|
||||
while(n2>0 && comp()==0) {
|
||||
output(n1, n2);
|
||||
top1 = ftell(f[F1]);
|
||||
get1();
|
||||
}
|
||||
fseek(f[F1], bot1, 0);
|
||||
get2();
|
||||
get1();
|
||||
for(;;) {
|
||||
if(n1>0 && n2>0 && comp()==0) {
|
||||
output(n1, n2);
|
||||
get1();
|
||||
} else if(n1>0 && n2>0 && comp()>0 || n1==0) {
|
||||
fseek(f[F1], bot1, 0);
|
||||
get2();
|
||||
get1();
|
||||
} else /*(n1>0 && n2>0 && comp()<0 || n2==0)*/{
|
||||
fseek(f[F1], top1, 0);
|
||||
bot1 = top1;
|
||||
get1();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
input(int n) /* get input line and split into fields */
|
||||
{
|
||||
register int i, c;
|
||||
Rune *bp;
|
||||
Rune **pp;
|
||||
char line[BUFSIZ];
|
||||
|
||||
bp = buf[n];
|
||||
pp = ppi[n];
|
||||
if (fgets(line, BUFSIZ, f[n]) == 0)
|
||||
return(0);
|
||||
strtorune(bp, line);
|
||||
i = 0;
|
||||
do {
|
||||
i++;
|
||||
if (sep1 == ' ') /* strip multiples */
|
||||
while ((c = *bp) == sep1 || c == sep2)
|
||||
bp++; /* skip blanks */
|
||||
*pp++ = bp; /* record beginning */
|
||||
while ((c = *bp) != sep1 && c != '\n' && c != sep2 && c != '\0')
|
||||
bp++;
|
||||
*bp++ = '\0'; /* mark end by overwriting blank */
|
||||
} while (c != '\n' && c != '\0' && i < NFLD-1);
|
||||
if (c != '\n')
|
||||
discard++;
|
||||
|
||||
*pp = 0;
|
||||
return(i);
|
||||
}
|
||||
|
||||
void
|
||||
output(int on1, int on2) /* print items from olist */
|
||||
{
|
||||
int i;
|
||||
Rune *temp;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
if (no <= 0) { /* default case */
|
||||
printf("%s", runetostr(buf, on1? ppi[F1][j1]: ppi[F2][j2]));
|
||||
for (i = 0; i < on1; i++)
|
||||
if (i != j1)
|
||||
printf("%s%s", sepstr, runetostr(buf, ppi[F1][i]));
|
||||
for (i = 0; i < on2; i++)
|
||||
if (i != j2)
|
||||
printf("%s%s", sepstr, runetostr(buf, ppi[F2][i]));
|
||||
printf("\n");
|
||||
} else {
|
||||
for (i = 0; i < no; i++) {
|
||||
if (olistf[i]==F0 && on1>j1)
|
||||
temp = ppi[F1][j1];
|
||||
else if (olistf[i]==F0 && on2>j2)
|
||||
temp = ppi[F2][j2];
|
||||
else {
|
||||
temp = ppi[olistf[i]][olist[i]];
|
||||
if(olistf[i]==F1 && on1<=olist[i] ||
|
||||
olistf[i]==F2 && on2<=olist[i] ||
|
||||
*temp==0)
|
||||
temp = null;
|
||||
}
|
||||
printf("%s", runetostr(buf, temp));
|
||||
if (i == no - 1)
|
||||
printf("\n");
|
||||
else
|
||||
printf("%s", sepstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
error(char *s1, char *s2)
|
||||
{
|
||||
fprintf(stderr, "join: ");
|
||||
fprintf(stderr, s1, s2);
|
||||
fprintf(stderr, "\n");
|
||||
exits(s1);
|
||||
}
|
||||
|
||||
char *
|
||||
getoptarg(int *argcp, char ***argvp)
|
||||
{
|
||||
int argc = *argcp;
|
||||
char **argv = *argvp;
|
||||
if(argv[1][2] != 0)
|
||||
return &argv[1][2];
|
||||
if(argc<=2 || argv[2][0]=='-')
|
||||
error("incomplete option %s", argv[1]);
|
||||
*argcp = argc-1;
|
||||
*argvp = ++argv;
|
||||
return argv[1];
|
||||
}
|
||||
|
||||
void
|
||||
oparse(char *s)
|
||||
{
|
||||
for (no = 0; no<2*NFLD && *s; no++, s++) {
|
||||
switch(*s) {
|
||||
case 0:
|
||||
return;
|
||||
case '0':
|
||||
olistf[no] = F0;
|
||||
break;
|
||||
case '1':
|
||||
case '2':
|
||||
if(s[1] == '.' && isdigit(s[2])) {
|
||||
olistf[no] = *s=='1'? F1: F2;
|
||||
olist[no] = atoi(s += 2);
|
||||
break;
|
||||
} /* fall thru */
|
||||
default:
|
||||
error("invalid -o list", "");
|
||||
}
|
||||
if(s[1] == ',')
|
||||
s++;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue