#include <u.h>#include <libc.h>#include <bio.h> /*bugs: 00/ff for end of file can conflict with 00/ff characters*/ enum{ Nline = 100000, /* default max number of lines saved in memory */ Nmerge = 10, /* max number of temporary files merged */ Nfield = 20, /* max number of argument fields */ Bflag = 1<<0, /* flags per field */ B1flag = 1<<1, Dflag = 1<<2, Fflag = 1<<3, Gflag = 1<<4, Iflag = 1<<5, Mflag = 1<<6, Nflag = 1<<7, Rflag = 1<<8, Wflag = 1<<9, NSstart = 0, /* states for number to key decoding */ NSsign, NSzero, NSdigit, NSpoint, NSfract, NSzerofract, NSexp, NSexpsign, NSexpdigit,}; typedef struct Line Line;typedef struct Key Key;typedef struct Merge Merge;typedef struct Field Field; struct Line{ Key* key; int llen; /* always >= 1 */ uchar line[1]; /* always ends in '\n' */}; struct Merge{ Key* key; /* copy of line->key so (Line*) looks like (Merge*) */ Line* line; /* line at the head of a merged temp file */ int fd; /* file descriptor */ Biobuf b; /* iobuf for reading a temp file */}; struct Key{ int klen; uchar key[1];}; struct Field{ int beg1; int beg2; int end1; int end2; long flags; uchar mapto[1+255]; void (*dokey)(Key*, uchar*, uchar*, Field*);}; struct args{ char* ofile; char* tname; Rune tabchar; char cflag; char uflag; char vflag; int nfield; int nfile; Field field[Nfield]; Line** linep; long nline; /* number of lines in this temp file */ long lineno; /* overall ordinal for -s option */ int ntemp; long mline; /* max lines per file */} args; extern Rune* month[12]; void buildkey(Line*);void doargs(int, char*[]);void dofield(char*, int*, int*, int, int);void dofile(Biobuf*);void dokey_(Key*, uchar*, uchar*, Field*);void dokey_dfi(Key*, uchar*, uchar*, Field*);void dokey_gn(Key*, uchar*, uchar*, Field*);void dokey_m(Key*, uchar*, uchar*, Field*);void dokey_r(Key*, uchar*, uchar*, Field*);void done(char*);int kcmp(Key*, Key*);void makemapd(Field*);void makemapm(Field*);void mergefiles(int, int, Biobuf*);void mergeout(Biobuf*);void newfield(void);Line* newline(Biobuf*);void nomem(void);void notifyf(void*, char*);void printargs(void);void printout(Biobuf*);void setfield(int, int);uchar* skip(uchar*, int, int, int, int);void sort4(void*, ulong);char* tempfile(int);void tempout(void);void lineout(Biobuf*, Line*); voidmain(int argc, char *argv[]){ int i, f; char *s; Biobuf bbuf; notify(notifyf); /**/ doargs(argc, argv); if(args.vflag) printargs(); for(i=1; i<argc; i++) { s = argv[i]; if(s == 0) continue; if(strcmp(s, "-") == 0) { Binit(&bbuf, 0, OREAD); dofile(&bbuf); Bterm(&bbuf); continue; } f = open(s, OREAD); if(f < 0) { fprint(2, "sort: open %s: %r\n", s); done("open"); } Binit(&bbuf, f, OREAD); dofile(&bbuf); Bterm(&bbuf); close(f); } if(args.nfile == 0) { Binit(&bbuf, 0, OREAD); dofile(&bbuf); Bterm(&bbuf); } if(args.cflag) done(0); if(args.vflag) fprint(2, "=========\n"); f = 1; if(args.ofile) { f = create(args.ofile, OWRITE, 0666); if(f < 0) { fprint(2, "sort: create %s: %r\n", args.ofile); done("create"); } } Binit(&bbuf, f, OWRITE); if(args.ntemp) { tempout(); mergeout(&bbuf); } else { printout(&bbuf); } Bterm(&bbuf); done(0);} voiddofile(Biobuf *b){ Line *l, *ol; int n; if(args.cflag) { ol = newline(b); if(ol == 0) return; for(;;) { l = newline(b); if(l == 0) break; n = kcmp(ol->key, l->key); if(n > 0 || (n == 0 && args.uflag)) { fprint(2, "sort: -c file not in sort\n"); /**/ done("order"); } free(ol->key); free(ol); ol = l; } return; } if(args.linep == 0) { args.linep = malloc(args.mline * sizeof(args.linep)); if(args.linep == 0) nomem(); } for(;;) { l = newline(b); if(l == 0) break; if(args.nline >= args.mline) tempout(); args.linep[args.nline] = l; args.nline++; args.lineno++; }} voidnotifyf(void* p, char *s){ if(strcmp(s, "interrupt") == 0) done(0); if(strcmp(s, "hangup") == 0) done(0); if(strcmp(s, "kill") == 0) done(0); if(strncmp(s, "sys: write on closed pipe", 25) == 0) done(0); fprint(2, "sort: note: %s\n", s); abort();} Line*newline(Biobuf *b){ Line *l; char *p; int n, c; p = Brdline(b, '\n'); n = Blinelen(b); if(p == 0) { if(n == 0) return 0; l = 0; for(n=0;;) { if((n & 31) == 0) { l = realloc(l, sizeof(Line) + (n+31)*sizeof(l->line[0])); if(l == 0) nomem(); } c = Bgetc(b); if(c < 0) { fprint(2, "sort: newline added\n"); c = '\n'; } l->line[n++] = c; if(c == '\n') break; } l->llen = n; buildkey(l); return l; } l = malloc(sizeof(Line) + (n-1)*sizeof(l->line[0])); if(l == 0) nomem(); l->llen = n; memmove(l->line, p, n); buildkey(l); return l;} voidlineout(Biobuf *b, Line *l){ int n, m; n = l->llen; m = Bwrite(b, l->line, n); if(n != m) exits("write");} voidtempout(void){ long n; Line **lp, *l; char *tf; int f; Biobuf tb; sort4(args.linep, args.nline); tf = tempfile(args.ntemp); args.ntemp++; f = create(tf, OWRITE, 0666); if(f < 0) { fprint(2, "sort: create %s: %r\n", tf); done("create"); } Binit(&tb, f, OWRITE); lp = args.linep; for(n=args.nline; n>0; n--) { l = *lp++; lineout(&tb, l); free(l->key); free(l); } args.nline = 0; Bterm(&tb); close(f);} voiddone(char *xs){ int i; for(i=0; i<args.ntemp; i++) remove(tempfile(i)); exits(xs);} voidnomem(void){ fprint(2, "sort: out of memory\n"); done("mem");} char*tempfile(int n){ static char file[100]; static uint pid; char *dir; dir = "/tmp"; if(args.tname) dir = args.tname; if(strlen(dir) >= nelem(file)-20) { fprint(2, "temp file directory name is too long: %s\n", dir); done("tdir"); } if(pid == 0) { pid = getpid(); if(pid == 0) { pid = time(0); if(pid == 0) pid = 1; } } sprint(file, "%s/sort.%.4d.%.4d", dir, pid%10000, n); return file;} voidmergeout(Biobuf *b){ int n, i, f; char *tf; Biobuf tb; for(i=0; i<args.ntemp; i+=n) { n = args.ntemp - i; if(n > Nmerge) { tf = tempfile(args.ntemp); args.ntemp++; f = create(tf, OWRITE, 0666); if(f < 0) { fprint(2, "sort: create %s: %r\n", tf); done("create"); } Binit(&tb, f, OWRITE); n = Nmerge; mergefiles(i, n, &tb); Bterm(&tb); close(f); } else mergefiles(i, n, b); }} voidmergefiles(int t, int n, Biobuf *b){ Merge *m, *mp, **mmp; Key *ok; Line *l; char *tf; int i, f, nn; mmp = malloc(n*sizeof(*mmp)); mp = malloc(n*sizeof(*mp)); if(mmp == 0 || mp == 0) nomem(); nn = 0; m = mp; for(i=0; i<n; i++,m++) { tf = tempfile(t+i); f = open(tf, OREAD); if(f < 0) { fprint(2, "sort: reopen %s: %r\n", tf); done("open"); } m->fd = f; Binit(&m->b, f, OREAD); mmp[nn] = m; l = newline(&m->b); if(l == 0) continue; nn++; m->line = l; m->key = l->key; } ok = 0; for(;;) { sort4(mmp, nn); m = *mmp; if(nn == 0) break; for(;;) { l = m->line; if(args.uflag && ok && kcmp(ok, l->key) == 0) { free(l->key); free(l); } else { lineout(b, l); if(ok) free(ok); ok = l->key; free(l); } l = newline(&m->b); if(l == 0) { nn--; mmp[0] = mmp[nn]; break; } m->line = l; m->key = l->key; if(nn > 1 && kcmp(mmp[0]->key, mmp[1]->key) > 0) break; } } if(ok) free(ok); m = mp; for(i=0; i<n; i++,m++) { Bterm(&m->b); close(m->fd); } free(mp); free(mmp);} intkcmp(Key *ka, Key *kb){ int n, m; /* * set n to length of smaller key */ n = ka->klen; m = kb->klen; if(n > m) n = m; return memcmp(ka->key, kb->key, n);}Lines 1–500 of 1716. Load more
#include <u.h> #include <libc.h> #include <bio.h> /* bugs: 00/ff for end of file can conflict with 00/ff characters */ enum { Nline = 100000, /* default max number of lines saved in memory */ Nmerge = 10, /* max number of temporary files merged */ Nfield = 20, /* max number of argument fields */ Bflag = 1<<0, /* flags per field */ B1flag = 1<<1, Dflag = 1<<2, Fflag = 1<<3, Gflag = 1<<4, Iflag = 1<<5, Mflag = 1<<6, Nflag = 1<<7, Rflag = 1<<8, Wflag = 1<<9, NSstart = 0, /* states for number to key decoding */ NSsign, NSzero, NSdigit, NSpoint, NSfract, NSzerofract, NSexp, NSexpsign, NSexpdigit, }; typedef struct Line Line; typedef struct Key Key; typedef struct Merge Merge; typedef struct Field Field; struct Line { Key* key; int llen; /* always >= 1 */ uchar line[1]; /* always ends in '\n' */ }; struct Merge { Key* key; /* copy of line->key so (Line*) looks like (Merge*) */ Line* line; /* line at the head of a merged temp file */ int fd; /* file descriptor */ Biobuf b; /* iobuf for reading a temp file */ }; struct Key { int klen; uchar key[1]; }; struct Field { int beg1; int beg2; int end1; int end2; long flags; uchar mapto[1+255]; void (*dokey)(Key*, uchar*, uchar*, Field*); }; struct args { char* ofile; char* tname; Rune tabchar; char cflag; char uflag; char vflag; int nfield; int nfile; Field field[Nfield]; Line** linep; long nline; /* number of lines in this temp file */ long lineno; /* overall ordinal for -s option */ int ntemp; long mline; /* max lines per file */ } args; extern Rune* month[12]; void buildkey(Line*); void doargs(int, char*[]); void dofield(char*, int*, int*, int, int); void dofile(Biobuf*); void dokey_(Key*, uchar*, uchar*, Field*); void dokey_dfi(Key*, uchar*, uchar*, Field*); void dokey_gn(Key*, uchar*, uchar*, Field*); void dokey_m(Key*, uchar*, uchar*, Field*); void dokey_r(Key*, uchar*, uchar*, Field*); void done(char*); int kcmp(Key*, Key*); void makemapd(Field*); void makemapm(Field*); void mergefiles(int, int, Biobuf*); void mergeout(Biobuf*); void newfield(void); Line* newline(Biobuf*); void nomem(void); void notifyf(void*, char*); void printargs(void); void printout(Biobuf*); void setfield(int, int); uchar* skip(uchar*, int, int, int, int); void sort4(void*, ulong); char* tempfile(int); void tempout(void); void lineout(Biobuf*, Line*); void main(int argc, char *argv[]) { int i, f; char *s; Biobuf bbuf; notify(notifyf); /**/ doargs(argc, argv); if(args.vflag) printargs(); for(i=1; i<argc; i++) { s = argv[i]; if(s == 0) continue; if(strcmp(s, "-") == 0) { Binit(&bbuf, 0, OREAD); dofile(&bbuf); Bterm(&bbuf); continue; } f = open(s, OREAD); if(f < 0) { fprint(2, "sort: open %s: %r\n", s); done("open"); } Binit(&bbuf, f, OREAD); dofile(&bbuf); Bterm(&bbuf); close(f); } if(args.nfile == 0) { Binit(&bbuf, 0, OREAD); dofile(&bbuf); Bterm(&bbuf); } if(args.cflag) done(0); if(args.vflag) fprint(2, "=========\n"); f = 1; if(args.ofile) { f = create(args.ofile, OWRITE, 0666); if(f < 0) { fprint(2, "sort: create %s: %r\n", args.ofile); done("create"); } } Binit(&bbuf, f, OWRITE); if(args.ntemp) { tempout(); mergeout(&bbuf); } else { printout(&bbuf); } Bterm(&bbuf); done(0); } void dofile(Biobuf *b) { Line *l, *ol; int n; if(args.cflag) { ol = newline(b); if(ol == 0) return; for(;;) { l = newline(b); if(l == 0) break; n = kcmp(ol->key, l->key); if(n > 0 || (n == 0 && args.uflag)) { fprint(2, "sort: -c file not in sort\n"); /**/ done("order"); } free(ol->key); free(ol); ol = l; } return; } if(args.linep == 0) { args.linep = malloc(args.mline * sizeof(args.linep)); if(args.linep == 0) nomem(); } for(;;) { l = newline(b); if(l == 0) break; if(args.nline >= args.mline) tempout(); args.linep[args.nline] = l; args.nline++; args.lineno++; } } void notifyf(void* p, char *s) { if(strcmp(s, "interrupt") == 0) done(0); if(strcmp(s, "hangup") == 0) done(0); if(strcmp(s, "kill") == 0) done(0); if(strncmp(s, "sys: write on closed pipe", 25) == 0) done(0); fprint(2, "sort: note: %s\n", s); abort(); } Line* newline(Biobuf *b) { Line *l; char *p; int n, c; p = Brdline(b, '\n'); n = Blinelen(b); if(p == 0) { if(n == 0) return 0; l = 0; for(n=0;;) { if((n & 31) == 0) { l = realloc(l, sizeof(Line) + (n+31)*sizeof(l->line[0])); if(l == 0) nomem(); } c = Bgetc(b); if(c < 0) { fprint(2, "sort: newline added\n"); c = '\n'; } l->line[n++] = c; if(c == '\n') break; } l->llen = n; buildkey(l); return l; } l = malloc(sizeof(Line) + (n-1)*sizeof(l->line[0])); if(l == 0) nomem(); l->llen = n; memmove(l->line, p, n); buildkey(l); return l; } void lineout(Biobuf *b, Line *l) { int n, m; n = l->llen; m = Bwrite(b, l->line, n); if(n != m) exits("write"); } void tempout(void) { long n; Line **lp, *l; char *tf; int f; Biobuf tb; sort4(args.linep, args.nline); tf = tempfile(args.ntemp); args.ntemp++; f = create(tf, OWRITE, 0666); if(f < 0) { fprint(2, "sort: create %s: %r\n", tf); done("create"); } Binit(&tb, f, OWRITE); lp = args.linep; for(n=args.nline; n>0; n--) { l = *lp++; lineout(&tb, l); free(l->key); free(l); } args.nline = 0; Bterm(&tb); close(f); } void done(char *xs) { int i; for(i=0; i<args.ntemp; i++) remove(tempfile(i)); exits(xs); } void nomem(void) { fprint(2, "sort: out of memory\n"); done("mem"); } char* tempfile(int n) { static char file[100]; static uint pid; char *dir; dir = "/tmp"; if(args.tname) dir = args.tname; if(strlen(dir) >= nelem(file)-20) { fprint(2, "temp file directory name is too long: %s\n", dir); done("tdir"); } if(pid == 0) { pid = getpid(); if(pid == 0) { pid = time(0); if(pid == 0) pid = 1; } } sprint(file, "%s/sort.%.4d.%.4d", dir, pid%10000, n); return file; } void mergeout(Biobuf *b) { int n, i, f; char *tf; Biobuf tb; for(i=0; i<args.ntemp; i+=n) { n = args.ntemp - i; if(n > Nmerge) { tf = tempfile(args.ntemp); args.ntemp++; f = create(tf, OWRITE, 0666); if(f < 0) { fprint(2, "sort: create %s: %r\n", tf); done("create"); } Binit(&tb, f, OWRITE); n = Nmerge; mergefiles(i, n, &tb); Bterm(&tb); close(f); } else mergefiles(i, n, b); } } void mergefiles(int t, int n, Biobuf *b) { Merge *m, *mp, **mmp; Key *ok; Line *l; char *tf; int i, f, nn; mmp = malloc(n*sizeof(*mmp)); mp = malloc(n*sizeof(*mp)); if(mmp == 0 || mp == 0) nomem(); nn = 0; m = mp; for(i=0; i<n; i++,m++) { tf = tempfile(t+i); f = open(tf, OREAD); if(f < 0) { fprint(2, "sort: reopen %s: %r\n", tf); done("open"); } m->fd = f; Binit(&m->b, f, OREAD); mmp[nn] = m; l = newline(&m->b); if(l == 0) continue; nn++; m->line = l; m->key = l->key; } ok = 0; for(;;) { sort4(mmp, nn); m = *mmp; if(nn == 0) break; for(;;) { l = m->line; if(args.uflag && ok && kcmp(ok, l->key) == 0) { free(l->key); free(l); } else { lineout(b, l); if(ok) free(ok); ok = l->key; free(l); } l = newline(&m->b); if(l == 0) { nn--; mmp[0] = mmp[nn]; break; } m->line = l; m->key = l->key; if(nn > 1 && kcmp(mmp[0]->key, mmp[1]->key) > 0) break; } } if(ok) free(ok); m = mp; for(i=0; i<n; i++,m++) { Bterm(&m->b); close(m->fd); } free(mp); free(mmp); } int kcmp(Key *ka, Key *kb) { int n, m; /* * set n to length of smaller key */ n = ka->klen; m = kb->klen; if(n > m) n = m; return memcmp(ka->key, kb->key, n); }