| look.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
| git clone git://git.suckless.org/9base | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| look.c (6122B) | |
| --- | |
| 1 #include <u.h> | |
| 2 #include <libc.h> | |
| 3 #include <bio.h> | |
| 4 /* Macros for Rune support of ctype.h-like functions */ | |
| 5 | |
| 6 #undef isupper | |
| 7 #undef islower | |
| 8 #undef isalpha | |
| 9 #undef isdigit | |
| 10 #undef isalnum | |
| 11 #undef isspace | |
| 12 #undef tolower | |
| 13 #define isupper(r) ('A' <= (r) && (r) <= 'Z') | |
| 14 #define islower(r) ('a' <= (r) && (r) <= 'z') | |
| 15 #define isalpha(r) (isupper(r) || islower(r)) | |
| 16 #define islatin1(r) (0xC0 <= (r) && (r) <= 0xFF) | |
| 17 | |
| 18 #define isdigit(r) ('0' <= (r) && (r) <= '9') | |
| 19 | |
| 20 #define isalnum(r) (isalpha(r) || isdigit(r)) | |
| 21 | |
| 22 #define isspace(r) ((r) == ' ' || (r) == '\t' \ | |
| 23 || (0x0A <= (r) && (r) <= 0x0D)) | |
| 24 | |
| 25 #define tolower(r) ((r)-'A'+'a') | |
| 26 | |
| 27 #define sgn(v) ((v) < 0 ? -1 : ((v) > 0 ? 1 : 0)) | |
| 28 | |
| 29 #define WORDSIZ 4000 | |
| 30 char *filename = "#9/lib/words"; | |
| 31 Biobuf *dfile; | |
| 32 Biobuf bout; | |
| 33 Biobuf bin; | |
| 34 | |
| 35 int fold; | |
| 36 int direc; | |
| 37 int exact; | |
| 38 int iflag; | |
| 39 int rev = 1; /*-1 for reverse-ordered file, not implemente… | |
| 40 int (*compare)(Rune*, Rune*); | |
| 41 Rune tab = '\t'; | |
| 42 Rune entry[WORDSIZ]; | |
| 43 Rune word[WORDSIZ]; | |
| 44 Rune key[50], orig[50]; | |
| 45 Rune latin_fold_tab[] = | |
| 46 { | |
| 47 /* Table to fold latin 1 characters to ASCII equivalents | |
| 48 based at Rune value 0xc0 | |
| 49 | |
| 50 À Á Â Ã Ä Å Æ Ç | |
| 51 È É Ê Ë Ì Í Î Ï | |
| 52 Ð Ñ Ò Ó Ô Õ Ö × | |
| 53 Ø Ù Ú Û Ü Ý Þ ß | |
| 54 à á â ã ä å æ ç | |
| 55 è é ê ë ì í î ï | |
| 56 ð ñ ò ó ô õ ö ÷ | |
| 57 ø ù ú û ü ý þ ÿ | |
| 58 */ | |
| 59 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c', | |
| 60 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', | |
| 61 'd', 'n', 'o', 'o', 'o', 'o', 'o', 0 , | |
| 62 'o', 'u', 'u', 'u', 'u', 'y', 0 , 0 , | |
| 63 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c', | |
| 64 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', | |
| 65 'd', 'n', 'o', 'o', 'o', 'o', 'o', 0 , | |
| 66 'o', 'u', 'u', 'u', 'u', 'y', 0 , 'y', | |
| 67 }; | |
| 68 | |
| 69 int locate(void); | |
| 70 int acomp(Rune*, Rune*); | |
| 71 int getword(Biobuf*, Rune *rp, int n); | |
| 72 void torune(char*, Rune*); | |
| 73 void rcanon(Rune*, Rune*); | |
| 74 int ncomp(Rune*, Rune*); | |
| 75 | |
| 76 void | |
| 77 main(int argc, char *argv[]) | |
| 78 { | |
| 79 int n; | |
| 80 | |
| 81 filename = unsharp(filename); | |
| 82 | |
| 83 Binit(&bin, 0, OREAD); | |
| 84 Binit(&bout, 1, OWRITE); | |
| 85 compare = acomp; | |
| 86 ARGBEGIN{ | |
| 87 case 'd': | |
| 88 direc++; | |
| 89 break; | |
| 90 case 'f': | |
| 91 fold++; | |
| 92 break; | |
| 93 case 'i': | |
| 94 iflag++; | |
| 95 break; | |
| 96 case 'n': | |
| 97 compare = ncomp; | |
| 98 break; | |
| 99 case 't': | |
| 100 chartorune(&tab,ARGF()); | |
| 101 break; | |
| 102 case 'x': | |
| 103 exact++; | |
| 104 break; | |
| 105 default: | |
| 106 fprint(2, "%s: bad option %c\n", argv0, ARGC()); | |
| 107 fprint(2, "usage: %s -[dfinx] [-t c] [string] [file]\n",… | |
| 108 exits("usage"); | |
| 109 } ARGEND | |
| 110 if(!iflag){ | |
| 111 if(argc >= 1) { | |
| 112 torune(argv[0], orig); | |
| 113 argv++; | |
| 114 argc--; | |
| 115 } else | |
| 116 iflag++; | |
| 117 } | |
| 118 if(argc < 1) { | |
| 119 direc++; | |
| 120 fold++; | |
| 121 } else | |
| 122 filename = argv[0]; | |
| 123 if (!iflag) | |
| 124 rcanon(orig, key); | |
| 125 dfile = Bopen(filename, OREAD); | |
| 126 if(dfile == 0) { | |
| 127 fprint(2, "look: can't open %s\n", filename); | |
| 128 exits("no dictionary"); | |
| 129 } | |
| 130 if(!iflag) | |
| 131 if(!locate()) | |
| 132 exits("not found"); | |
| 133 do { | |
| 134 if(iflag) { | |
| 135 Bflush(&bout); | |
| 136 if(!getword(&bin, orig, sizeof(orig)/sizeof(orig… | |
| 137 exits(0); | |
| 138 rcanon(orig, key); | |
| 139 if(!locate()) | |
| 140 continue; | |
| 141 } | |
| 142 if (!exact || !acomp(word, key)) | |
| 143 Bprint(&bout, "%S\n", entry); | |
| 144 while(getword(dfile, entry, sizeof(entry)/sizeof(entry[0… | |
| 145 rcanon(entry, word); | |
| 146 n = compare(key, word); | |
| 147 switch(n) { | |
| 148 case -1: | |
| 149 if(exact) | |
| 150 break; | |
| 151 case 0: | |
| 152 if (!exact || !acomp(word, orig)) | |
| 153 Bprint(&bout, "%S\n", entry); | |
| 154 continue; | |
| 155 } | |
| 156 break; | |
| 157 } | |
| 158 } while(iflag); | |
| 159 exits(0); | |
| 160 } | |
| 161 | |
| 162 int | |
| 163 locate(void) | |
| 164 { | |
| 165 vlong top, bot, mid; | |
| 166 int c; | |
| 167 int n; | |
| 168 | |
| 169 bot = 0; | |
| 170 top = Bseek(dfile, 0L, 2); | |
| 171 for(;;) { | |
| 172 mid = (top+bot) / 2; | |
| 173 Bseek(dfile, mid, 0); | |
| 174 do | |
| 175 c = Bgetrune(dfile); | |
| 176 while(c>=0 && c!='\n'); | |
| 177 mid = Boffset(dfile); | |
| 178 if(!getword(dfile, entry, sizeof(entry)/sizeof(entry[0])… | |
| 179 break; | |
| 180 rcanon(entry, word); | |
| 181 n = compare(key, word); | |
| 182 switch(n) { | |
| 183 case -2: | |
| 184 case -1: | |
| 185 case 0: | |
| 186 if(top <= mid) | |
| 187 break; | |
| 188 top = mid; | |
| 189 continue; | |
| 190 case 1: | |
| 191 case 2: | |
| 192 bot = mid; | |
| 193 continue; | |
| 194 } | |
| 195 break; | |
| 196 } | |
| 197 Bseek(dfile, bot, 0); | |
| 198 while(getword(dfile, entry, sizeof(entry)/sizeof(entry[0]))) { | |
| 199 rcanon(entry, word); | |
| 200 n = compare(key, word); | |
| 201 switch(n) { | |
| 202 case -2: | |
| 203 return 0; | |
| 204 case -1: | |
| 205 if(exact) | |
| 206 return 0; | |
| 207 case 0: | |
| 208 return 1; | |
| 209 case 1: | |
| 210 case 2: | |
| 211 continue; | |
| 212 } | |
| 213 } | |
| 214 return 0; | |
| 215 } | |
| 216 | |
| 217 /* | |
| 218 * acomp(s, t) returns: | |
| 219 * -2 if s strictly precedes t | |
| 220 * -1 if s is a prefix of t | |
| 221 * 0 if s is the same as t | |
| 222 * 1 if t is a prefix of s | |
| 223 * 2 if t strictly precedes s | |
| 224 */ | |
| 225 | |
| 226 int | |
| 227 acomp(Rune *s, Rune *t) | |
| 228 { | |
| 229 int cs, ct; | |
| 230 | |
| 231 for(;;) { | |
| 232 cs = *s; | |
| 233 ct = *t; | |
| 234 if(cs != ct) | |
| 235 break; | |
| 236 if(cs == 0) | |
| 237 return 0; | |
| 238 s++; | |
| 239 t++; | |
| 240 } | |
| 241 if(cs == 0) | |
| 242 return -1; | |
| 243 if(ct == 0) | |
| 244 return 1; | |
| 245 if(cs < ct) | |
| 246 return -2; | |
| 247 return 2; | |
| 248 } | |
| 249 | |
| 250 void | |
| 251 torune(char *old, Rune *new) | |
| 252 { | |
| 253 do old += chartorune(new, old); | |
| 254 while(*new++); | |
| 255 } | |
| 256 | |
| 257 void | |
| 258 rcanon(Rune *old, Rune *new) | |
| 259 { | |
| 260 Rune r; | |
| 261 | |
| 262 while((r = *old++) && r != tab) { | |
| 263 if (islatin1(r) && latin_fold_tab[r-0xc0]) | |
| 264 r = latin_fold_tab[r-0xc0]; | |
| 265 if(direc) | |
| 266 if(!(isalnum(r) || r == ' ' || r == '\t')) | |
| 267 continue; | |
| 268 if(fold) | |
| 269 if(isupper(r)) | |
| 270 r = tolower(r); | |
| 271 *new++ = r; | |
| 272 } | |
| 273 *new = 0; | |
| 274 } | |
| 275 | |
| 276 int | |
| 277 ncomp(Rune *s, Rune *t) | |
| 278 { | |
| 279 Rune *is, *it, *js, *jt; | |
| 280 int a, b; | |
| 281 int ssgn, tsgn; | |
| 282 | |
| 283 while(isspace(*s)) | |
| 284 s++; | |
| 285 while(isspace(*t)) | |
| 286 t++; | |
| 287 ssgn = tsgn = -2*rev; | |
| 288 if(*s == '-') { | |
| 289 s++; | |
| 290 ssgn = -ssgn; | |
| 291 } | |
| 292 if(*t == '-') { | |
| 293 t++; | |
| 294 tsgn = -tsgn; | |
| 295 } | |
| 296 for(is = s; isdigit(*is); is++) | |
| 297 ; | |
| 298 for(it = t; isdigit(*it); it++) | |
| 299 ; | |
| 300 js = is; | |
| 301 jt = it; | |
| 302 a = 0; | |
| 303 if(ssgn == tsgn) | |
| 304 while(it>t && is>s) | |
| 305 if(b = *--it - *--is) | |
| 306 a = b; | |
| 307 while(is > s) | |
| 308 if(*--is != '0') | |
| 309 return -ssgn; | |
| 310 while(it > t) | |
| 311 if(*--it != '0') | |
| 312 return tsgn; | |
| 313 if(a) | |
| 314 return sgn(a)*ssgn; | |
| 315 if(*(s=js) == '.') | |
| 316 s++; | |
| 317 if(*(t=jt) == '.') | |
| 318 t++; | |
| 319 if(ssgn == tsgn) | |
| 320 while(isdigit(*s) && isdigit(*t)) | |
| 321 if(a = *t++ - *s++) | |
| 322 return sgn(a)*ssgn; | |
| 323 while(isdigit(*s)) | |
| 324 if(*s++ != '0') | |
| 325 return -ssgn; | |
| 326 while(isdigit(*t)) | |
| 327 if(*t++ != '0') | |
| 328 return tsgn; | |
| 329 return 0; | |
| 330 } | |
| 331 | |
| 332 int | |
| 333 getword(Biobuf *f, Rune *rp, int n) | |
| 334 { | |
| 335 long c; | |
| 336 | |
| 337 while(n-- > 0) { | |
| 338 c = Bgetrune(f); | |
| 339 if(c < 0) | |
| 340 return 0; | |
| 341 if(c == '\n') { | |
| 342 *rp = '\0'; | |
| 343 return 1; | |
| 344 } | |
| 345 *rp++ = c; | |
| 346 } | |
| 347 fprint(2, "Look: word too long. Bailing out.\n"); | |
| 348 return 0; | |
| 349 } |