mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-12 11:10:07 +00:00
349 lines
6 KiB
C
349 lines
6 KiB
C
#include <u.h>
|
||
#include <libc.h>
|
||
#include <bio.h>
|
||
/* Macros for Rune support of ctype.h-like functions */
|
||
|
||
#undef isupper
|
||
#undef islower
|
||
#undef isalpha
|
||
#undef isdigit
|
||
#undef isalnum
|
||
#undef isspace
|
||
#undef tolower
|
||
#define isupper(r) ('A' <= (r) && (r) <= 'Z')
|
||
#define islower(r) ('a' <= (r) && (r) <= 'z')
|
||
#define isalpha(r) (isupper(r) || islower(r))
|
||
#define islatin1(r) (0xC0 <= (r) && (r) <= 0xFF)
|
||
|
||
#define isdigit(r) ('0' <= (r) && (r) <= '9')
|
||
|
||
#define isalnum(r) (isalpha(r) || isdigit(r))
|
||
|
||
#define isspace(r) ((r) == ' ' || (r) == '\t' \
|
||
|| (0x0A <= (r) && (r) <= 0x0D))
|
||
|
||
#define tolower(r) ((r)-'A'+'a')
|
||
|
||
#define sgn(v) ((v) < 0 ? -1 : ((v) > 0 ? 1 : 0))
|
||
|
||
#define WORDSIZ 4000
|
||
char *filename = "#9/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];
|
||
Rune latin_fold_tab[] =
|
||
{
|
||
/* Table to fold latin 1 characters to ASCII equivalents
|
||
based at Rune value 0xc0
|
||
|
||
À Á Â Ã Ä Å Æ Ç
|
||
È É Ê Ë Ì Í Î Ï
|
||
Ð Ñ Ò Ó Ô Õ Ö ×
|
||
Ø Ù Ú Û Ü Ý Þ ß
|
||
à á â ã ä å æ ç
|
||
è é ê ë ì í î ï
|
||
ð ñ ò ó ô õ ö ÷
|
||
ø ù ú û ü ý þ ÿ
|
||
*/
|
||
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c',
|
||
'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i',
|
||
'd', 'n', 'o', 'o', 'o', 'o', 'o', 0 ,
|
||
'o', 'u', 'u', 'u', 'u', 'y', 0 , 0 ,
|
||
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c',
|
||
'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i',
|
||
'd', 'n', 'o', 'o', 'o', 'o', 'o', 0 ,
|
||
'o', 'u', 'u', 'u', 'u', 'y', 0 , 'y',
|
||
};
|
||
|
||
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*);
|
||
|
||
void
|
||
main(int argc, char *argv[])
|
||
{
|
||
int n;
|
||
|
||
filename = unsharp(filename);
|
||
|
||
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,ARGF());
|
||
break;
|
||
case 'x':
|
||
exact++;
|
||
break;
|
||
default:
|
||
fprint(2, "%s: bad option %c\n", argv0, ARGC());
|
||
fprint(2, "usage: %s -[dfinx] [-t c] [string] [file]\n", argv0);
|
||
exits("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);
|
||
}
|
||
|
||
int
|
||
locate(void)
|
||
{
|
||
vlong top, bot, mid;
|
||
int c;
|
||
int n;
|
||
|
||
bot = 0;
|
||
top = Bseek(dfile, 0L, 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
|
||
*/
|
||
|
||
int
|
||
acomp(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;
|
||
}
|
||
|
||
void
|
||
torune(char *old, Rune *new)
|
||
{
|
||
do old += chartorune(new, old);
|
||
while(*new++);
|
||
}
|
||
|
||
void
|
||
rcanon(Rune *old, Rune *new)
|
||
{
|
||
Rune r;
|
||
|
||
while((r = *old++) && r != tab) {
|
||
if (islatin1(r) && latin_fold_tab[r-0xc0])
|
||
r = latin_fold_tab[r-0xc0];
|
||
if(direc)
|
||
if(!(isalnum(r) || r == ' ' || r == '\t'))
|
||
continue;
|
||
if(fold)
|
||
if(isupper(r))
|
||
r = tolower(r);
|
||
*new++ = r;
|
||
}
|
||
*new = 0;
|
||
}
|
||
|
||
int
|
||
ncomp(Rune *s, Rune *t)
|
||
{
|
||
Rune *is, *it, *js, *jt;
|
||
int a, b;
|
||
int ssgn, tsgn;
|
||
|
||
while(isspace(*s))
|
||
s++;
|
||
while(isspace(*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;
|
||
}
|
||
|
||
int
|
||
getword(Biobuf *f, Rune *rp, int n)
|
||
{
|
||
long c;
|
||
|
||
while(n-- > 0) {
|
||
c = Bgetrune(f);
|
||
if(c < 0)
|
||
return 0;
|
||
if(c == '\n') {
|
||
*rp = '\0';
|
||
return 1;
|
||
}
|
||
*rp++ = c;
|
||
}
|
||
fprint(2, "Look: word too long. Bailing out.\n");
|
||
return 0;
|
||
}
|