307 lines · 4.6 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <bio.h> #define	isdigit(r)	(L'0' <= (r) && (r) <= L'9')#define	sgn(v)		((v) < 0 ? -1 : ((v) > 0 ? 1 : 0)) #define	WORDSIZ	4000char	*filename = "/lib/words";Biobuf	*dfile;Biobuf	bout;Biobuf	bin; int	fold;int	direc;int	exact;int	iflag;int	rev = 1;	/*-1 for reverse-ordered file, not implemented*/int	(*compare)(Rune*, Rune*);Rune	tab = '\t';Rune	entry[WORDSIZ];Rune	word[WORDSIZ];Rune	key[50], orig[50]; int	locate(void);int	acomp(Rune*, Rune*);int	getword(Biobuf*, Rune *rp, int n);void	torune(char*, Rune*);void	rcanon(Rune*, Rune*);int	ncomp(Rune*, Rune*); voidusage(void){	fprint(2, "usage: %s [-dfinx] [-t c] [string] [file]\n", argv0);	exits("usage");} voidmain(int argc, char *argv[]){	int n; 	Binit(&bin, 0, OREAD);	Binit(&bout, 1, OWRITE);	compare = acomp;	ARGBEGIN{	case 'd':		direc++;		break;	case 'f':		fold++;		break;	case 'i': 		iflag++;		break;	case 'n':		compare = ncomp;		break;	case 't':		chartorune(&tab, EARGF(usage()));		break;	case 'x':		exact++;		break;	default:		fprint(2, "%s: bad option %c\n", argv0, ARGC());		usage();	} ARGEND	if(!iflag){		if(argc >= 1) {			torune(argv[0], orig);			argv++;			argc--;		} else			iflag++;	}	if(argc < 1) {		direc++;		fold++;	} else 		filename = argv[0];	if (!iflag)		rcanon(orig, key);	dfile = Bopen(filename, OREAD);	if(dfile == 0) {		fprint(2, "look: can't open %s\n", filename);		exits("no dictionary");	}	if(!iflag)		if(!locate())			exits("not found");	do {		if(iflag) {			Bflush(&bout);			if(!getword(&bin, orig, sizeof(orig)/sizeof(orig[0])))				exits(0);			rcanon(orig, key);			if(!locate())				continue;		}		if (!exact || !acomp(word, key))			Bprint(&bout, "%S\n", entry);		while(getword(dfile, entry, sizeof(entry)/sizeof(entry[0]))) {			rcanon(entry, word);			n = compare(key, word);			switch(n) {			case -1:				if(exact)					break;			case 0:				if (!exact || !acomp(word, orig))					Bprint(&bout, "%S\n", entry);				continue;			}			break;		}	} while(iflag);	exits(0);} intlocate(void){	vlong top, bot, mid;	long c;	int n; 	bot = 0;	top = Bseek(dfile, 0, 2);	for(;;) {		mid = (top+bot) / 2;		Bseek(dfile, mid, 0);		do			c = Bgetrune(dfile);		while(c>=0 && c!='\n');		mid = Boffset(dfile);		if(!getword(dfile, entry, sizeof(entry)/sizeof(entry[0])))			break;		rcanon(entry, word);		n = compare(key, word);		switch(n) {		case -2:		case -1:		case 0:			if(top <= mid)				break;			top = mid;			continue;		case 1:		case 2:			bot = mid;			continue;		}		break;	}	Bseek(dfile, bot, 0);	while(getword(dfile, entry, sizeof(entry)/sizeof(entry[0]))) {		rcanon(entry, word);		n = compare(key, word);		switch(n) {		case -2:			return 0;		case -1:			if(exact)				return 0;		case 0:			return 1;		case 1:		case 2:			continue;		}	}	return 0;} /* *	acomp(s, t) returns: *		-2 if s strictly precedes t *		-1 if s is a prefix of t *		0 if s is the same as t *		1 if t is a prefix of s *		2 if t strictly precedes s */ intacomp(Rune *s, Rune *t){	int cs, ct; 	for(;;) {		cs = *s;		ct = *t;		if(cs != ct)			break;		if(cs == 0)			return 0;		s++;		t++;	}	if(cs == 0)		return -1;	if(ct == 0)		return 1;	if(cs < ct)		return -2;	return 2;} voidtorune(char *old, Rune *new){	do old += chartorune(new, old);	while(*new++);} voidrcanon(Rune *old, Rune *new){	Rune r; 	while((r = *old++) && r != tab) {		r = tobaserune(r);		if(direc && !isdigitrune(r) && !isalpharune(r))		if(r != ' ' && r != '\t')			continue;		if(fold)			r = tolowerrune(r);		*new++ = r;	}	*new = 0;} intncomp(Rune *s, Rune *t){	Rune *is, *it, *js, *jt;	int a, b;	int ssgn, tsgn; 	while(isspacerune(*s))		s++;	while(isspacerune(*t))		t++;	ssgn = tsgn = -2*rev;	if(*s == '-') {		s++;		ssgn = -ssgn;	}	if(*t == '-') {		t++;		tsgn = -tsgn;	}	for(is = s; isdigit(*is); is++)		;	for(it = t; isdigit(*it); it++)		;	js = is;	jt = it;	a = 0;	if(ssgn == tsgn)		while(it>t && is>s)			if(b = *--it - *--is)				a = b;	while(is > s)		if(*--is != '0')			return -ssgn;	while(it > t)		if(*--it != '0')			return tsgn;	if(a)		return sgn(a)*ssgn;	if(*(s=js) == '.')		s++;	if(*(t=jt) == '.')		t++;	if(ssgn == tsgn)		while(isdigit(*s) && isdigit(*t))			if(a = *t++ - *s++)				return sgn(a)*ssgn;	while(isdigit(*s))		if(*s++ != '0')			return -ssgn;	while(isdigit(*t))		if(*t++ != '0')			return tsgn;	return 0;} intgetword(Biobuf *f, Rune *rp, int n){	long c; 	while(n-- > 0) {		c = Bgetrune(f);		if(c < 0)			return 0;		if(c == '\n') {			*rp = L'\0';			return 1;		}		*rp++ = c;	}	fprint(2, "Look: word too long.  Bailing out.\n");	return 0;}