henesyinit from p9fd787fda5 years agoHistory
1752 lines · 27.7 KB · C
RawDownload
#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[256]; 	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	int	latinmap[];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*, 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 1752.