#include #include #include #include #include "code.h" #define isvowel(c) voweltab[c] #define Tolower(c) (isupper(c)? (c)-'A'+'a': (c)) #define pair(a,b) (((a)<<8) | (b)) #define DLEV 2 typedef long Bits; #define Set(h, f) ((long)(h) & (f)) Bits nop(char*, char*, char*, int, int); Bits strip(char*, char*, char*, int, int); Bits ize(char*, char*, char*, int, int); Bits i_to_y(char*, char*, char*, int, int); Bits ily(char*, char*, char*, int, int); Bits subst(char*, char*, char*, int, int); Bits CCe(char*, char*, char*, int, int); Bits tion(char*, char*, char*, int, int); Bits an(char*, char*, char*, int, int); Bits s(char*, char*, char*, int, int); Bits es(char*, char*, char*, int, int); Bits bility(char*, char*, char*, int, int); Bits y_to_e(char*, char*, char*, int, int); Bits VCe(char*, char*, char*, int, int); Bits trypref(char*, char*, int, int); Bits tryword(char*, char*, int, int); Bits trysuff(char*, int, int); Bits dict(char*, char*); void typeprint(Bits); void pcomma(char*); void ise(void); int ordinal(void); char* skipv(char*); int inun(char*, Bits); char* ztos(char*); void readdict(char*); typedef struct Ptab Ptab; struct Ptab { char* s; int flag; }; typedef struct Suftab Suftab; struct Suftab { char *suf; Bits (*p1)(char*, char*, char*, int, int); int n1; char *d1; char *a1; int flag; int affixable; Bits (*p2)(char*, char*, char*, int, int); int n2; char *d2; char *a2; }; Suftab stabc[] = { {"citsi",strip,2,"","+ic",N_AFFIX, ADJ | N_AFFIX | NOUN}, {"citi",ize,1,"-e+ic","",N_AFFIX, ADJ }, {"cihparg",i_to_y,1,"-y+ic","",NOUN, ADJ|NOUN }, {"cipocs",ize,1,"-e+ic","",NOUN, ADJ }, {"cirtem",i_to_y,1,"-y+ic","",NOUN, ADJ }, {"cigol",i_to_y,1,"-y+ic","",NOUN, ADJ }, {"cimono",i_to_y,1,"-y+ic","",NOUN, ADJ }, 0 }; Suftab stabd[] = { {"de",strip,1,"","+d",ED,ADJ | N_AFFIX|COMP,i_to_y,2,"-y+ied","+ed"}, {"dooh",ily,4,"-y+ihood","+hood",NOUN | ADV, NOUN}, 0 }; Suftab stabe[] = { /* * V_affix for comment ->commence->commentment?? */ {"ecn",subst,1,"-t+ce","",ADJ,N_AFFIX|_Y|NOUN|VERB|ACTOR|V_AFFIX}, {"elbaif",i_to_y,4,"-y+iable","",V_IRREG,ADJ}, {"elba",CCe,4,"-e+able","+able",V_AFFIX,ADJ}, {"evi",subst,0,"-ion+ive","",N_AFFIX | V_AFFIX,NOUN | N_AFFIX| ADJ}, {"ezi",CCe,3,"-e+ize","+ize",N_AFFIX|ADJ ,V_AFFIX | VERB |ION | COMP}, {"ekil",strip,4,"","+like",N_AFFIX ,ADJ}, {"ekam",strip,4,"","+make",NOUN,V_IRREG|ACTOR}, 0 }; Suftab stabg[] = { {"gni",CCe,3,"-e+ing","+ing",V_IRREG ,ADJ|ED|NOUN}, 0 }; Suftab stabl[] = { {"laci",strip,2,"","+al",NOUN |ADJ,ADJ |NOUN|N_AFFIX}, {"latnem",strip,2,"","+al",N_AFFIX,ADJ}, {"lanoi",strip,2,"","+al",N_AFFIX,ADJ|NOUN}, {"luf",ily,3,"-y+iful","+ful",N_AFFIX,ADJ | NOUN}, 0 }; Suftab stabm[] = { /* congregational + ism */ {"msi",CCe,3,"-e+ism","ism",N_AFFIX|ADJ,NOUN}, {"margo",subst,-1,"-ph+m","",NOUN,NOUN}, 0 }; Suftab stabn[] = { {"noitacifi",i_to_y,6,"-y+ication","",ION,NOUN | N_AFFIX}, {"noitazi",ize,4,"-e+ation","",ION,NOUN| N_AFFIX}, {"noit",tion,3,"-e+ion","+ion",ION,NOUN| N_AFFIX | V_AFFIX |VERB|ACTOR}, {"naino",an,3,"","+ian",NOUN|PROP_COLLECT,NOUN| N_AFFIX}, {"namow",strip,5,"","+woman",MAN,PROP_COLLECT|N_AFFIX}, {"nam",strip,3,"","+man",MAN,PROP_COLLECT | N_AFFIX | VERB}, {"na",an,1,"","+n",NOUN|PROP_COLLECT,NOUN | N_AFFIX}, {"nemow",strip,5,"","+women",MAN,PROP_COLLECT}, {"nem",strip,3,"","+man",MAN,PROP_COLLECT}, 0 }; Suftab stabp[] = { {"pihs",strip,4,"","+ship",NOUN|PROP_COLLECT,NOUN| N_AFFIX}, 0 }; Suftab stabr[] = { {"rehparg",subst,1,"-y+er","",ACTOR,NOUN,strip,2,"","+er"}, {"reyhparg",nop,0,"","",0,NOUN}, {"re",strip,1,"","+r",ACTOR,NOUN | N_AFFIX|VERB|ADJ, i_to_y,2,"-y+ier","+er"}, {"rota",tion,2,"-e+or","",ION,NOUN| N_AFFIX|_Y}, {"rotc",tion,2,"","+or",ION,NOUN| N_AFFIX}, {"rotp",tion,2,"","+or",ION,NOUN| N_AFFIX}, 0 }; Suftab stabs[] = { {"ssen",ily,4,"-y+iness","+ness",ADJ|ADV,NOUN| N_AFFIX}, {"ssel",ily,4,"-y+i+less","+less",NOUN | PROP_COLLECT,ADJ }, {"se",s,1,"","+s",NOUN | V_IRREG,DONT_TOUCH , es,2,"-y+ies","+es"}, {"s'",s,2,"","+'s",PROP_COLLECT | NOUN,DONT_TOUCH }, {"s",s,1,"","+s",NOUN | V_IRREG,DONT_TOUCH }, 0 }; Suftab stabt[] = { {"tnem",strip,4,"","+ment",V_AFFIX,NOUN | N_AFFIX | ADJ|VERB}, {"tse",strip,2,"","+st",EST,DONT_TOUCH, i_to_y,3,"-y+iest","+est" }, {"tsigol",i_to_y,2,"-y+ist","",N_AFFIX,NOUN | N_AFFIX}, {"tsi",CCe,3,"-e+ist","+ist",N_AFFIX|ADJ,NOUN | N_AFFIX|COMP}, 0 }; Suftab staby[] = { {"ytilb",nop,0,"","",0,NOUN}, {"ycn",subst,1,"-t+cy","",ADJ | N_AFFIX,NOUN | N_AFFIX}, {"ytilib",bility,5,"-le+ility","",ADJ | V_AFFIX,NOUN | N_AFFIX}, {"ytisuo",nop,0,"","",NOUN}, {"yti",CCe,3,"-e+ity","+ity",ADJ ,NOUN | N_AFFIX }, {"ylb",y_to_e,1,"-e+y","",ADJ,ADV}, {"ylc",nop,0,"","",0}, {"yl",ily,2,"-y+ily","+ly",ADJ,ADV|COMP}, {"yrtem",subst,0,"-er+ry","",NOUN,NOUN | N_AFFIX}, {"y",CCe,1,"-e+y","+y",_Y,ADJ|COMP}, 0 }; Suftab stabz[] = { 0 }; Suftab* suftab[] = { stabz, stabz, stabc, stabd, stabe, stabz, stabg, stabz, stabz, stabz, stabz, stabl, stabm, stabn, stabz, stabp, stabz, stabr, stabs, stabt, stabz, stabz, stabz, stabz, staby, stabz, }; Ptab ptaba[] = { "anti", 0, "auto", 0, 0 }; Ptab ptabb[] = { "bio", 0, 0 }; Ptab ptabc[] = { "counter", 0, 0 }; Ptab ptabd[] = { "dis", 0, 0 }; Ptab ptabe[] = { "electro", 0, "en", 0, 0 }; Ptab ptabf[] = { "femto", 0, 0 }; Ptab ptabg[] = { "geo", 0, "giga", 0, 0 }; Ptab ptabh[] = { "hyper", 0, 0 }; Ptab ptabi[] = { "im", IN, "intra", 0, "inter", 0, "in", IN, "ir", IN, "iso", 0, 0 }; Ptab ptabj[] = { 0 }; Ptab ptabk[] = { "kilo", 0, 0 }; Ptab ptabl[] = { 0 }; Ptab ptabm[] = { "magneto", 0, "mega", 0, "meta", 0, "micro", 0, "mid", 0, "milli", 0, "mis", 0, "mono", 0, "multi", 0, 0 }; Ptab ptabn[] = { "nano", 0, "non", 0, 0 }; Ptab ptabo[] = { "out", 0, "over", 0, 0 }; Ptab ptabp[] = { "para", 0, "photo", 0, "pico", 0, "poly", 0, "pre", 0, "pseudo", 0, "psycho", 0, 0 }; Ptab ptabq[] = { "quasi", 0, 0 }; Ptab ptabr[] = { "re", 0, 0 }; Ptab ptabs[] = { "semi", 0, "stereo", 0, "sub", 0, "super", 0, 0 }; Ptab ptabt[] = { "tele", 0, "thermo", 0, 0 }; Ptab ptabu[] = { "ultra", 0, "under", 0, /*must precede un*/ "un", IN, 0 }; Ptab ptabv[] = { 0 }; Ptab ptabw[] = { 0 }; Ptab ptabx[] = { 0 }; Ptab ptaby[] = { 0 }; Ptab ptabz[] = { 0 }; Ptab* preftab[] = { ptaba, ptabb, ptabc, ptabd, ptabe, ptabf, ptabg, ptabh, ptabi, ptabj, ptabk, ptabl, ptabm, ptabn, ptabo, ptabp, ptabq, ptabr, ptabs, ptabt, ptabu, ptabv, ptabw, ptabx, ptaby, ptabz, }; int cflag; int vflag; int xflag; char word[100]; char* original; char* deriv[40]; char affix[40]; char space[300000]; /* must be as large as "words"+"space" in pcode run */ Bits encode[2048]; /* must be as long as "codes" in pcode run */ int nencode; char voweltab[128]; char* spacep[128*128+1]; /* pointer to words starting with 'xx' */ Biobuf bin; char* codefile = "/sys/lib/amspell"; char* brfile = "/sys/lib/brspell"; char* Usage = "usage"; void main(int argc, char *argv[]) { char *ep, *cp; char *dp; int j, i, c; int low; Bits h; Binit(&bin, 0, OREAD); for(i=0; c = "aeiouyAEIOUY"[i]; i++) voweltab[c] = 1; while(argc > 1) { if(argv[1][0] != '-') break; for(i=1; c = argv[1][i]; i++) switch(c) { default: fprint(2, "usage: spell [-bcvx] [-f file]\n"); exits(Usage); case 'b': ise(); codefile = brfile; continue; case 'c': cflag++; continue; case 'v': vflag++; continue; case 'x': xflag++; continue; case 'f': if(argc <= 2) { fprint(2, "spell: -f requires another argument\n"); exits(Usage); } argv++; argc--; codefile = argv[1]; goto brk; } brk: argv++; argc--; } readdict(codefile); if(argc > 1) { fprint(2, "usage: spell [-bcvx] [-f file]\n"); exits(Usage); } for(;;) { affix[0] = 0; original = Brdline(&bin, '\n'); if(original == 0) exits(0); original[Blinelen(&bin)-1] = 0; low = 0; for(ep=word,dp=original; j = *dp; ep++,dp++) { if(islower(j)) low++; if(ep >= word+sizeof(word)-1) break; *ep = j; } *ep = 0; if(isdigit(word[0]) && ordinal()) continue; h = 0; if(!low && !(h = trypref(ep,".",0,ALL|STOP|DONT_TOUCH))) for(cp=original+1,dp=word+1; dpsuf; t++) { cp = ep; while(*sp) if(*--cp != *sp++) goto next; for(sp=cp; --sp >= word && !isvowel(*sp);) ; if(sp < word) return 0; if(!(t->affixable & flag)) return 0; h = (*t->p1)(ep-t->n1, t->d1, t->a1, lev+1, t->flag|STOP); if(!h && t->p2!=0) { deriv[lev] = deriv[lev+1] = 0; h = (*t->p2)(ep-t->n2, t->d2, t->a2, lev, t->flag|STOP); } break; next:; } return h; } Bits nop(char* ep, char* d, char* a, int lev, int flag) { USED(ep, d, a, lev, flag); return 0; } Bits cstrip(char* ep, char* d, char* a, int lev, int flag) { int temp = ep[0]; if(isvowel(temp) && isvowel(ep[-1])) { switch(pair(ep[-1],ep[0])) { case pair('a', 'a'): case pair('a', 'e'): case pair('a', 'i'): case pair('e', 'a'): case pair('e', 'e'): case pair('e', 'i'): case pair('i', 'i'): case pair('o', 'a'): return 0; } } else if(temp==ep[-1]&&temp==ep[-2]) return 0; return strip(ep,d,a,lev,flag); } Bits strip(char* ep, char* d, char* a, int lev, int flag) { Bits h = trypref(ep, a, lev, flag); USED(d); if(Set(h,MONO) && isvowel(*ep) && isvowel(ep[-2])) h = 0; if(h) return h; if(isvowel(*ep) && ep[-1]==ep[-2]) { h = trypref(ep-1,a,lev,flag|MONO); if(h) return h; } return trysuff(ep,lev,flag); } Bits s(char* ep, char* d, char* a, int lev, int flag) { if(lev > DLEV+1) return 0; if(*ep=='s') { switch(ep[-1]) { case 'y': if(isvowel(ep[-2])||isupper(*word)) break; /*says Kennedys*/ case 'x': case 'z': case 's': return 0; case 'h': switch(ep[-2]) { case 'c': case 's': return 0; } } } return strip(ep,d,a,lev,flag); } Bits an(char* ep, char* d, char* a, int lev, int flag) { USED(d); if(!isupper(*word)) /*must be proper name*/ return 0; return trypref(ep,a,lev,flag); } Bits ize(char* ep, char* d, char* a, int lev, int flag) { int temp = ep[-1]; Bits h; USED(a); ep[-1] = 'e'; h = strip(ep,"",d,lev,flag); ep[-1] = temp; return h; } Bits y_to_e(char* ep, char* d, char* a, int lev, int flag) { Bits h; int temp; USED(a); switch(ep[-1]) { case 'a': case 'e': case 'i': return 0; } temp = *ep; *ep++ = 'e'; h = strip(ep,"",d,lev,flag); ep[-1] = temp; return h; } Bits ily(char* ep, char* d, char* a, int lev, int flag) { int temp = ep[0]; char *cp = ep; if(temp==ep[-1]&&temp==ep[-2]) /* sillly */ return 0; if(*--cp=='y' && !isvowel(*--cp)) /* happyly */ while(cp>word) if(isvowel(*--cp)) /* shyness */ return 0; if(ep[-1]=='i') return i_to_y(ep,d,a,lev,flag); return cstrip(ep,d,a,lev,flag); } Bits bility(char* ep, char* d, char* a, int lev, int flag) { *ep++ = 'l'; return y_to_e(ep,d,a,lev,flag); } Bits i_to_y(char* ep, char* d, char* a, int lev, int flag) { Bits h; int temp; if(isupper(*word)) return 0; if((temp=ep[-1])=='i' && !isvowel(ep[-2])) { ep[-1] = 'y'; a = d; } h = cstrip(ep,"",a,lev,flag); ep[-1] = temp; return h; } Bits es(char* ep, char* d, char* a, int lev, int flag) { if(lev>DLEV) return 0; switch(ep[-1]) { default: return 0; case 'i': return i_to_y(ep,d,a,lev,flag); case 'h': switch(ep[-2]) { default: return 0; case 'c': case 's': break; } case 's': case 'z': case 'x': return strip(ep,d,a,lev,flag); } } Bits subst(char* ep, char* d, char* a, int lev, int flag) { char *u,*t; Bits h; USED(a); if(skipv(skipv(ep-1)) < word) return 0; for(t=d; *t!='+'; t++) continue; for(u=ep; *--t!='-';) *--u = *t; h = strip(ep,"",d,lev,flag); while(*++t != '+') continue; while(*++t) *u++ = *t; return h; } Bits tion(char* ep, char* d, char* a, int lev, int flag) { switch(ep[-2]) { case 's': case 'c': case 'r': case 'p': return trypref(ep,a,lev,flag); case 'a': case 'e': case 'i': case 'o': case 'u': return y_to_e(ep,d,a,lev,flag); } return 0; } /* * possible consonant-consonant-e ending */ Bits CCe(char* ep, char* d, char* a, int lev, int flag) { Bits h; switch(ep[-1]) { case 'l': if(isvowel(ep[-2])) break; switch(ep[-2]) { case 'l': case 'r': case 'w': break; default: return y_to_e(ep,d,a,lev,flag); } break; case 'c': case 'g': if(*ep == 'a') /* prevent -able for -eable */ return 0; case 's': case 'v': case 'z': if(ep[-2]==ep[-1]) break; if(isvowel(ep[-2])) break; case 'u': if(h = y_to_e(ep,d,a,lev,flag)) return h; if(!(ep[-2]=='n' && ep[-1]=='g')) return 0; } return VCe(ep,d,a,lev,flag); } /* * possible consonant-vowel-consonant-e ending */ Bits VCe(char* ep, char* d, char* a, int lev, int flag) { int c; Bits h; c = ep[-1]; if(c=='e') return 0; if(!isvowel(c) && isvowel(ep[-2])) { c = *ep; *ep++ = 'e'; h = trypref(ep,d,lev,flag); if(!h) h = trysuff(ep,lev,flag); if(h) return h; ep--; *ep = c; } return cstrip(ep,d,a,lev,flag); } Ptab* lookuppref(char** wp, char* ep) { Ptab *sp; char *bp,*cp; int initchar = Tolower(**wp); if(!isalpha(initchar)) return 0; for(sp=preftab[initchar-'a'];sp->s;sp++) { bp = *wp; for(cp= sp->s;*cp; ) if(*bp++!=*cp++) goto next; for(cp=bp;cps; while(*pp = *cp++) pp++; h = tryword(bp,ep,lev+1,flag); if(Set(h,NOPREF) || ((tp->flag&IN) && inun(bp-2,h)==0)) { h = 0; break; } if(Set(h,flag&~MONO) && (flag&MONO) <= Set(h, MONO)) break; h = 0; } deriv[lev+1] = deriv[lev+2] = 0; return h; } Bits tryword(char* bp, char* ep, int lev, int flag) { int j; Bits h = 0; char duple[3]; if(ep-bp <= 1) return h; if(flag&MONO) { deriv[++lev] = duple; duple[0] = '+'; duple[1] = *ep; duple[2] = 0; } h = dict(bp, ep); if(vflag==0 || h==0) return h; /* * when derivations are wanted, collect them * for printing */ j = lev; do { if(deriv[j]) strcat(affix, deriv[j]); } while(--j > 0); return h; } int inun(char* bp, Bits h) { if(*bp == 'u') return Set(h, IN) == 0; /* *bp == 'i' */ if(Set(h, IN) == 0) return 0; switch(bp[2]) { case 'r': return bp[1] == 'r'; case 'm': case 'p': return bp[1] == 'm'; } return 1; } char* skipv(char *s) { if(s >= word && isvowel(*s)) s--; while(s >= word && !isvowel(*s)) s--; return s; } /* * crummy way to Britishise */ void ise(void) { Suftab *p; int i; for(i=0; i<26; i++) for(p = suftab[i]; p->suf; p++) { p->suf = ztos(p->suf); p->d1 = ztos(p->d1); p->a1 = ztos(p->a1); } } char* ztos(char *as) { char *s, *ds; for(s=as; *s; s++) if(*s == 'z') goto copy; return as; copy: ds = strdup(as); for(s=ds; *s; s++) if(*s == 'z') *s = 's'; return ds; } Bits dict(char* bp, char* ep) { char *cp, *cp1, *w, *wp, *we; int n, f; w = bp; we = ep; n = ep-bp; if(n <= 1) return NOUN; f = w[0] & 0x7f; f *= 128; f += w[1] & 0x7f; bp = spacep[f]; ep = spacep[f+1]; loop: if(bp >= ep) { if(xflag) fprint(2, "=%.*s\n", n, w); return 0; } /* * find the beginning of some word in the middle */ cp = bp + (ep-bp)/2; while(cp > bp && !(*cp & 0x80)) cp--; while(cp > bp && (cp[-1] & 0x80)) cp--; wp = w + 2; /* skip two letters */ cp1 = cp + 2; for(;;) { if(wp >= we) { if(*cp1 & 0x80) goto found; f = 1; break; } if(*cp1 & 0x80) { f = -1; break; } f = *cp1++ - *wp++; if(f != 0) break; } if(f < 0) { while(!(*cp1 & 0x80)) cp1++; bp = cp1; goto loop; } ep = cp; goto loop; found: f = ((cp[0] & 0x7) << 8) | (cp[1] & 0xff); if(xflag) { fprint(2, "=%.*s ", n, w); typeprint(encode[f]); } return encode[f]; } void typeprint(Bits h) { pcomma(""); if(h & NOUN) pcomma("n"); if(h & PROP_COLLECT) pcomma("pc"); if(h & VERB) { if((h & VERB) == VERB) pcomma("v"); else if((h & VERB) == V_IRREG) pcomma("vi"); else if(h & ED) pcomma("ed"); } if(h & ADJ) pcomma("a"); if(h & COMP) { if((h & COMP) == ACTOR) pcomma("er"); else pcomma("comp"); } if(h & DONT_TOUCH) pcomma("d"); if(h & N_AFFIX) pcomma("na"); if(h & ADV) pcomma("adv"); if(h & ION) pcomma("ion"); if(h & V_AFFIX) pcomma("va"); if(h & MAN) pcomma("man"); if(h & NOPREF) pcomma("nopref"); if(h & MONO) pcomma("ms"); if(h & IN) pcomma("in"); if(h & _Y) pcomma("y"); if(h & STOP) pcomma("s"); fprint(2, "\n"); } void pcomma(char *s) { static flag; if(*s == 0) { flag = 0; return; } if(!flag) { fprint(2, "%s", s); flag = 1; } else fprint(2, ",%s", s); } /* * is the word on of the following * 12th teen * 21st end in 1 * 23rd end in 3 * 77th default * called knowing word[0] is a digit */ int ordinal(void) { char *cp; int ch1, ch2; cp = word+1; while(isdigit(*cp)) cp++; ch1 = Tolower(cp[0]); ch2 = Tolower(cp[1]); if(cp[2]) return 0; if(cp <= word+1 || cp[-2] != '1') switch(cp[-1]) { case '1': return ch1 == 's' && ch2 == 't'; case '2': return ch1 == 'n' && ch2 == 'd'; case '3': return ch1 == 'r' && ch2 == 'd'; } return ch1 == 't' && ch2 == 'h'; } /* * read in the dictionary. * format is * { * short nencode; * long encode[nencode]; * char space[*]; * }; * * the encodings are a table all different * affixes. * the dictionary proper has 2 bytes * that demark and then the rest of the * word. the 2 bytes have the following * 0x80 0x00 flag * 0x78 0x00 count of prefix bytes * common with prev word * 0x07 0xff affix code * * all ints are big endians in the file. */ void readdict(char *file) { char *s, *is, *lasts, *ls; int c, i, sp, p; int f; long l; f = open(file, 0); if(f == -1) { fprint(2, "cannot open %s\n", file); exits("open"); } if(read(f, space, 2) != 2) goto bad; nencode = ((space[0]&0xff)<<8) | (space[1]&0xff); if(read(f, space, 4*nencode) != 4*nencode) goto bad; s = space; for(i=0; i is) goto noroom; if(c < 0) { close(f); while(sp < 128*128) spacep[++sp] = s; *s = 0x80; /* fence */ return; } p = (c>>3) & 0xf; *s++ = c; *s++ = *is++ & 0xff; if(p <= 0) i = (*is++ & 0xff)*128; if(p <= 1) { if(!(*is & 0x80)) i = i/128*128 + (*is++ & 0xff); if(i <= sp) { fprint(2, "the dict isnt sorted or \n"); fprint(2, "memmove didn't work\n"); goto bad; } while(sp < i) spacep[++sp] = s-2; } ls = lasts; lasts = s; for(p-=2; p>0; p--) *s++ = *ls++; for(;;) { if(is >= space+sizeof(space)) { c = -1; break; } c = *is++ & 0xff; if(c & 0x80) break; *s++ = c; } *s = 0; goto loop; bad: fprint(2, "trouble reading %s\n", file); exits("read"); noroom: fprint(2, "not enough space for dictionary\n"); exits("space"); }