Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <bio.h>
        /* Macros for Rune support of ctype.h-like functions */

#define isupper(r)      (L'A' <= (r) && (r) <= L'Z')
#define islower(r)      (L'a' <= (r) && (r) <= L'z')
#define isalpha(r)      (isupper(r) || islower(r))
#define islatin1(r)     (0xC0 <= (r) && (r) <= 0xFF)

#define isdigit(r)      (L'0' <= (r) && (r) <= L'9')

#define isalnum(r)      (isalpha(r) || isdigit(r))

#define isspace(r)      ((r) == L' ' || (r) == L'\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 = "/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
usage(void)
{
        fprint(2, "usage: %s [-dfinx] [-t c] [string] [file]\n", argv0);
        exits("usage");
}

void
main(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);
}

int
locate(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
 */

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 == L' ' || r == L'\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 = L'\0';
                        return 1;
                }
                *rp++ = c;
        }
        fprint(2, "Look: word too long.  Bailing out.\n");
        return 0;
}