1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2015 Gary Mills
  24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  25  * Use is subject to license terms.
  26  */
  27 
  28 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  29 /*        All Rights Reserved   */
  30 
  31 #include <stdlib.h>
  32 #include <unistd.h>
  33 #include <limits.h>
  34 #include <string.h>
  35 #include <stdio.h>
  36 #include <ctype.h>
  37 #include <locale.h>
  38 #include "hash.h"
  39 
  40 #define Tolower(c) (isupper(c)?tolower(c):c)
  41 #define DLEV 2
  42 
  43 /*
  44  * ANSI prototypes
  45  */
  46 static int      ily(char *, char *, char *, int);
  47 static int      s(char *, char *, char *, int);
  48 static int      es(char *, char *, char *, int);
  49 static int      subst(char *, char *, char *, int);
  50 static int      nop(void);
  51 static int      bility(char *, char *, char *, int);
  52 static int      i_to_y(char *, char *, char *, int);
  53 static int      CCe(char *, char *, char *, int);
  54 static int      y_to_e(char *, char *, char *, int);
  55 static int      strip(char *, char *, char *, int);
  56 static int      ize(char *, char *, char *, int);
  57 static int      tion(char *, char *, char *, int);
  58 static int      an(char *, char *, char *, int);
  59 int             prime(char *);
  60 static int      tryword(char *, char *, int);
  61 static int      trypref(char *, char *, int);
  62 static int      trysuff(char *, int);
  63 static int      vowel(int);
  64 static int      dict(char *, char *);
  65 static int      monosyl(char *, char *);
  66 static int      VCe(char *, char *, char *, int);
  67 static char     *skipv(char *);
  68 
  69 struct suftab {
  70         char *suf;
  71         int (*p1)();
  72         int n1;
  73         char *d1;
  74         char *a1;
  75         int (*p2)();
  76         int n2;
  77         char *d2;
  78         char *a2;
  79 };
  80 
  81 static struct suftab sufa[] = {
  82         {"ssen", ily, 4, "-y+iness", "+ness" },
  83         {"ssel", ily, 4, "-y+i+less", "+less" },
  84         {"se", s, 1, "", "+s",  es, 2, "-y+ies", "+es" },
  85         {"s'", s, 2, "", "+'s"},
  86         {"s", s, 1, "", "+s"},
  87         {"ecn", subst, 1, "-t+ce", ""},
  88         {"ycn", subst, 1, "-t+cy", ""},
  89         {"ytilb", nop, 0, "", ""},
  90         {"ytilib", bility, 5, "-le+ility", ""},
  91         {"elbaif", i_to_y, 4, "-y+iable", ""},
  92         {"elba", CCe, 4, "-e+able", "+able"},
  93         {"yti", CCe, 3, "-e+ity", "+ity"},
  94         {"ylb", y_to_e, 1, "-e+y", ""},
  95         {"yl", ily, 2, "-y+ily", "+ly"},
  96         {"laci", strip, 2, "", "+al"},
  97         {"latnem", strip, 2, "", "+al"},
  98         {"lanoi", strip, 2, "", "+al"},
  99         {"tnem", strip, 4, "", "+ment"},
 100         {"gni", CCe, 3, "-e+ing", "+ing"},
 101         {"reta", nop, 0, "", ""},
 102         {"retc", nop, 0, "", ""},
 103         {"re", strip, 1, "", "+r", i_to_y, 2, "-y+ier", "+er"},
 104         {"de", strip, 1, "", "+d", i_to_y, 2, "-y+ied", "+ed"},
 105         {"citsi", strip, 2, "", "+ic"},
 106         {"citi", ize, 1, "-ic+e", ""},
 107         {"cihparg", i_to_y, 1, "-y+ic", ""},
 108         {"tse", strip, 2, "", "+st",    i_to_y, 3, "-y+iest", "+est"},
 109         {"cirtem", i_to_y, 1, "-y+ic", ""},
 110         {"yrtem", subst, 0, "-er+ry", ""},
 111         {"cigol", i_to_y, 1, "-y+ic", ""},
 112         {"tsigol", i_to_y, 2, "-y+ist", ""},
 113         {"tsi", CCe, 3, "-e+ist", "+ist"},
 114         {"msi", CCe, 3, "-e+ism", "+ist"},
 115         {"noitacifi", i_to_y, 6, "-y+ication", ""},
 116         {"noitazi", ize, 4, "-e+ation", ""},
 117         {"rota", tion, 2, "-e+or", ""},
 118         {"rotc", tion, 2, "", "+or"},
 119         {"noit", tion, 3, "-e+ion", "+ion"},
 120         {"naino", an, 3, "", "+ian"},
 121         {"na", an, 1, "", "+n"},
 122         {"evi", subst, 0, "-ion+ive", ""},
 123         {"ezi", CCe, 3, "-e+ize", "+ize"},
 124         {"pihs", strip, 4, "", "+ship"},
 125         {"dooh", ily, 4, "-y+ihood", "+hood"},
 126         {"luf", ily, 3, "-y+iful", "+ful"},
 127         {"ekil", strip, 4, "", "+like"},
 128         0
 129 };
 130 
 131 static struct suftab sufb[] = {
 132         {"ssen", ily, 4, "-y+iness", "+ness" },
 133         {"ssel", ily, 4, "-y+i+less", "+less" },
 134         {"se", s, 1, "", "+s",  es, 2, "-y+ies", "+es" },
 135         {"s'", s, 2, "", "+'s"},
 136         {"s", s, 1, "", "+s"},
 137         {"ecn", subst, 1, "-t+ce", ""},
 138         {"ycn", subst, 1, "-t+cy", ""},
 139         {"ytilb", nop, 0, "", ""},
 140         {"ytilib", bility, 5, "-le+ility", ""},
 141         {"elbaif", i_to_y, 4, "-y+iable", ""},
 142         {"elba", CCe, 4, "-e+able", "+able"},
 143         {"yti", CCe, 3, "-e+ity", "+ity"},
 144         {"ylb", y_to_e, 1, "-e+y", ""},
 145         {"yl", ily, 2, "-y+ily", "+ly"},
 146         {"laci", strip, 2, "", "+al"},
 147         {"latnem", strip, 2, "", "+al"},
 148         {"lanoi", strip, 2, "", "+al"},
 149         {"tnem", strip, 4, "", "+ment"},
 150         {"gni", CCe, 3, "-e+ing", "+ing"},
 151         {"reta", nop, 0, "", ""},
 152         {"retc", nop, 0, "", ""},
 153         {"re", strip, 1, "", "+r", i_to_y, 2, "-y+ier", "+er"},
 154         {"de", strip, 1, "", "+d", i_to_y, 2, "-y+ied", "+ed"},
 155         {"citsi", strip, 2, "", "+ic"},
 156         {"citi", ize, 1, "-ic+e", ""},
 157         {"cihparg", i_to_y, 1, "-y+ic", ""},
 158         {"tse", strip, 2, "", "+st",    i_to_y, 3, "-y+iest", "+est"},
 159         {"cirtem", i_to_y, 1, "-y+ic", ""},
 160         {"yrtem", subst, 0, "-er+ry", ""},
 161         {"cigol", i_to_y, 1, "-y+ic", ""},
 162         {"tsigol", i_to_y, 2, "-y+ist", ""},
 163         {"tsi", CCe, 3, "-e+ist", "+ist"},
 164         {"msi", CCe, 3, "-e+ism", "+ist"},
 165         {"noitacifi", i_to_y, 6, "-y+ication", ""},
 166         {"noitasi", ize, 4, "-e+ation", ""},
 167         {"rota", tion, 2, "-e+or", ""},
 168         {"rotc", tion, 2, "", "+or"},
 169         {"noit", tion, 3, "-e+ion", "+ion"},
 170         {"naino", an, 3, "", "+ian"},
 171         {"na", an, 1, "", "+n"},
 172         {"evi", subst, 0, "-ion+ive", ""},
 173         {"esi", CCe, 3, "-e+ise", "+ise"},
 174         {"pihs", strip, 4, "", "+ship"},
 175         {"dooh", ily, 4, "-y+ihood", "+hood"},
 176         {"luf", ily, 3, "-y+iful", "+ful"},
 177         {"ekil", strip, 4, "", "+like"},
 178         0
 179 };
 180 
 181 static char *preftab[] = {
 182         "anti",
 183         "auto",
 184         "bio",
 185         "counter",
 186         "dis",
 187         "electro",
 188         "en",
 189         "fore",
 190         "geo",
 191         "hyper",
 192         "intra",
 193         "inter",
 194         "iso",
 195         "kilo",
 196         "magneto",
 197         "meta",
 198         "micro",
 199         "mid",
 200         "milli",
 201         "mis",
 202         "mono",
 203         "multi",
 204         "non",
 205         "out",
 206         "over",
 207         "photo",
 208         "poly",
 209         "pre",
 210         "pseudo",
 211         "psycho",
 212         "re",
 213         "semi",
 214         "stereo",
 215         "sub",
 216         "super",
 217         "tele",
 218         "thermo",
 219         "ultra",
 220         "under",        /* must precede un */
 221         "un",
 222         0
 223 };
 224 
 225 static int bflag;
 226 static int vflag;
 227 static int xflag;
 228 static struct suftab *suftab;
 229 static char *prog;
 230 static char word[LINE_MAX];
 231 static char original[LINE_MAX];
 232 static char *deriv[LINE_MAX];
 233 static char affix[LINE_MAX];
 234 static FILE *file, *found;
 235 /*
 236  *      deriv is stack of pointers to notes like +micro +ed
 237  *      affix is concatenated string of notes
 238  *      the buffer size 141 stems from the sizes of original and affix.
 239  */
 240 
 241 /*
 242  *      in an attempt to defray future maintenance misunderstandings, here is
 243  *      an attempt to describe the input/output expectations of the spell
 244  *      program.
 245  *
 246  *      spellprog is intended to be called from the shell file spell.
 247  *      because of this, there is little error checking (this is historical, not
 248  *      necessarily advisable).
 249  *
 250  *      spellprog options hashed-list pass
 251  *
 252  *      the hashed-list is a list of the form made by spellin.
 253  *      there are 2 types of hashed lists:
 254  *              1. a stop list: this specifies words that by the rules embodied
 255  *                 in spellprog would be recognized as correct, BUT are really
 256  *                 errors.
 257  *              2. a dictionary of correctly spelled words.
 258  *      the pass number determines how the words found in the specified
 259  *      hashed-list are treated. If the pass number is 1, the hashed-list is
 260  *      treated as the stop-list, otherwise, it is treated as the regular
 261  *      dictionary list. in this case, the value of "pass" is a filename. Found
 262  *      words are written to this file.
 263  *
 264  *      In the normal case, the filename = /dev/null. However, if the v option
 265  *      is specified, the derivations are written to this file.
 266  *      The spellprog looks up words in the hashed-list; if a word is found, it
 267  *      is printed to the stdout. If the hashed-list was the stop-list, the
 268  *      words found are presumed to be misspellings. in this case,
 269  *      a control character is printed ( a "-" is appended to the word.
 270  *      a hyphen will never occur naturally in the input list because deroff
 271  *      is used in the shell file before calling spellprog.)
 272  *      If the regualar spelling list was used (hlista or hlistb), the words
 273  *      are correct, and may be ditched. (unless the -v option was used -
 274  *      see the manual page).
 275  *
 276  *      spellprog should be called twice : first with the stop-list, to flag all
 277  *      a priori incorrectly spelled words; second with the dictionary.
 278  *
 279  *      spellprog hstop 1 |\
 280  *      spellprog hlista /dev/null
 281  *
 282  *      for a complete scenario, see the shell file: spell.
 283  *
 284  */
 285 
 286 int
 287 main(int argc, char **argv)
 288 {
 289         char *ep, *cp;
 290         char *dp;
 291         int fold;
 292         int c, j;
 293         int pass;
 294 
 295         /* Set locale environment variables local definitions */
 296         (void) setlocale(LC_ALL, "");
 297 #if !defined(TEXT_DOMAIN)       /* Should be defined by cc -D */
 298 #define TEXT_DOMAIN "SYS_TEST"  /* Use this only if it wasn't */
 299 #endif
 300         (void) textdomain(TEXT_DOMAIN);
 301 
 302 
 303         prog = argv[0];
 304         while ((c = getopt(argc, argv, "bvx")) != EOF) {
 305                 switch (c) {
 306                 case 'b':
 307                         bflag++;
 308                         break;
 309                 case 'v':
 310                         vflag++;
 311                         break;
 312                 case 'x':
 313                         xflag++;
 314                         break;
 315                 }
 316         }
 317 
 318         argc -= optind;
 319         argv = &argv[optind];
 320 
 321         if ((argc < 2) || !prime(*argv)) {
 322                 (void) fprintf(stderr,
 323                     gettext("%s: cannot initialize hash table\n"), prog);
 324                 exit(1);
 325         }
 326         argc--;
 327         argv++;
 328 
 329         /* Select the correct suffix table */
 330         suftab = (bflag == 0) ? sufa : sufb;
 331 
 332 /*
 333  *      if pass is not 1, it is assumed to be a filename.
 334  *      found words are written to this file.
 335  */
 336         pass = **argv;
 337         if (pass != '1')
 338                 found = fopen(*argv, "w");
 339 
 340         for (;;) {
 341                 affix[0] = 0;
 342                 file = stdout;
 343                 for (ep = word; (*ep = j = getchar()) != '\n'; ep++)
 344                         if (j == EOF)
 345                                 exit(0);
 346 /*
 347  *      here is the hyphen processing. these words were found in the stop
 348  *      list. however, if they exist as is, (no derivations tried) in the
 349  *      dictionary, let them through as correct.
 350  *
 351  */
 352                 if (ep[-1] == '-') {
 353                         *--ep = 0;
 354                         if (!tryword(word, ep, 0))
 355                                 (void) fprintf(file, "%s\n", word);
 356                         continue;
 357                 }
 358                 for (cp = word, dp = original; cp < ep; )
 359                         *dp++ = *cp++;
 360                 *dp = 0;
 361                 fold = 0;
 362                 for (cp = word; cp < ep; cp++)
 363                         if (islower(*cp))
 364                                 goto lcase;
 365                 if (((ep - word) == 1) &&
 366                     ((word[0] == 'A') || (word[0] == 'I')))
 367                         continue;
 368                 if (trypref(ep, ".", 0))
 369                         goto foundit;
 370                 ++fold;
 371                 for (cp = original+1, dp = word+1; dp < ep; dp++, cp++)
 372                         *dp = Tolower(*cp);
 373 lcase:
 374                 if (((ep - word) == 1) && (word[0] == 'a'))
 375                         continue;
 376                 if (trypref(ep, ".", 0)||trysuff(ep, 0))
 377                         goto foundit;
 378                 if (isupper(word[0])) {
 379                         for (cp = original, dp = word; *dp = *cp++; dp++)
 380                                 if (fold) *dp = Tolower(*dp);
 381                         word[0] = Tolower(word[0]);
 382                         goto lcase;
 383                 }
 384                 (void) fprintf(file, "%s\n", original);
 385                 continue;
 386 
 387 foundit:
 388                 if (pass == '1')
 389                         (void) fprintf(file, "%s-\n", original);
 390                 else if (affix[0] != 0 && affix[0] != '.') {
 391                         file = found;
 392                         (void) fprintf(file, "%s\t%s\n", affix,
 393                             original);
 394                 }
 395         }
 396 }
 397 
 398 /*
 399  *      strip exactly one suffix and do
 400  *      indicated routine(s), which may recursively
 401  *      strip suffixes
 402  */
 403 
 404 static int
 405 trysuff(char *ep, int lev)
 406 {
 407         struct suftab   *t;
 408         char *cp, *sp;
 409 
 410         lev += DLEV;
 411         deriv[lev] = deriv[lev-1] = 0;
 412         for (t = &suftab[0]; (t != 0 && (sp = t->suf) != 0); t++) {
 413                 cp = ep;
 414                 while (*sp)
 415                         if (*--cp != *sp++)
 416                                 goto next;
 417                 for (sp = cp; --sp >= word && !vowel(*sp); )
 418                         ;
 419                 if (sp < word)
 420                         return (0);
 421                 if ((*t->p1)(ep-t->n1, t->d1, t->a1, lev+1))
 422                         return (1);
 423                 if (t->p2 != 0) {
 424                         deriv[lev] = deriv[lev+1] = 0;
 425                         return ((*t->p2)(ep-t->n2, t->d2, t->a2, lev));
 426                 }
 427                 return (0);
 428 next:;
 429         }
 430         return (0);
 431 }
 432 
 433 static int
 434 nop(void)
 435 {
 436         return (0);
 437 }
 438 
 439 /* ARGSUSED */
 440 static int
 441 strip(char *ep, char *d, char *a, int lev)
 442 {
 443         return (trypref(ep, a, lev)||trysuff(ep, lev));
 444 }
 445 
 446 static int
 447 s(char *ep, char *d, char *a, int lev)
 448 {
 449         if (lev > DLEV+1)
 450                 return (0);
 451         if (*ep == 's' && ep[-1] == 's')
 452                 return (0);
 453         return (strip(ep, d, a, lev));
 454 }
 455 
 456 /* ARGSUSED */
 457 static int
 458 an(char *ep, char *d, char *a, int lev)
 459 {
 460         if (!isupper(*word))    /* must be proper name */
 461                 return (0);
 462         return (trypref(ep, a, lev));
 463 }
 464 
 465 /* ARGSUSED */
 466 static int
 467 ize(char *ep, char *d, char *a, int lev)
 468 {
 469         ep[-1] = 'e';
 470         return (strip(ep, "", d, lev));
 471 }
 472 
 473 /* ARGSUSED */
 474 static int
 475 y_to_e(char *ep, char *d, char *a, int lev)
 476 {
 477         *ep++ = 'e';
 478         return (strip(ep, "", d, lev));
 479 }
 480 
 481 static int
 482 ily(char *ep, char *d, char *a, int lev)
 483 {
 484         if (ep[-1] == 'i')
 485                 return (i_to_y(ep, d, a, lev));
 486         else
 487                 return (strip(ep, d, a, lev));
 488 }
 489 
 490 static int
 491 bility(char *ep, char *d, char *a, int lev)
 492 {
 493         *ep++ = 'l';
 494         return (y_to_e(ep, d, a, lev));
 495 }
 496 
 497 static int
 498 i_to_y(char *ep, char *d, char *a, int lev)
 499 {
 500         if (ep[-1] == 'i') {
 501                 ep[-1] = 'y';
 502                 a = d;
 503         }
 504         return (strip(ep, "", a, lev));
 505 }
 506 
 507 static int
 508 es(char *ep, char *d, char *a, int lev)
 509 {
 510         if (lev > DLEV)
 511                 return (0);
 512         switch (ep[-1]) {
 513         default:
 514                 return (0);
 515         case 'i':
 516                 return (i_to_y(ep, d, a, lev));
 517         case 's':
 518         case 'h':
 519         case 'z':
 520         case 'x':
 521                 return (strip(ep, d, a, lev));
 522         }
 523 }
 524 
 525 /* ARGSUSED */
 526 static int
 527 subst(char *ep, char *d, char *a, int lev)
 528 {
 529         char *u, *t;
 530 
 531         if (skipv(skipv(ep-1)) < word)
 532                 return (0);
 533         for (t = d; *t != '+'; t++)
 534                 continue;
 535         for (u = ep; *--t != '-'; )
 536                 *--u = *t;
 537         return (strip(ep, "", d, lev));
 538 }
 539 
 540 
 541 static int
 542 tion(char *ep, char *d, char *a, int lev)
 543 {
 544         switch (ep[-2]) {
 545         case 'c':
 546         case 'r':
 547                 return (trypref(ep, a, lev));
 548         case 'a':
 549                 return (y_to_e(ep, d, a, lev));
 550         }
 551         return (0);
 552 }
 553 
 554 /*      possible consonant-consonant-e ending */
 555 static int
 556 CCe(char *ep, char *d, char *a, int lev)
 557 {
 558         switch (ep[-1]) {
 559         case 'r':
 560                 if (ep[-2] == 't')
 561                         return (y_to_e(ep, d, a, lev));
 562                 break;
 563         case 'l':
 564                 if (vowel(ep[-2]))
 565                         break;
 566                 switch (ep[-2]) {
 567                 case 'l':
 568                 case 'r':
 569                 case 'w':
 570                         break;
 571                 default:
 572                         return (y_to_e(ep, d, a, lev));
 573                 }
 574                 break;
 575         case 's':
 576                 if (ep[-2] == 's')
 577                         break;
 578                 if (*ep == 'a')
 579                         return (0);
 580                 if (vowel(ep[-2]))
 581                         break;
 582                 if (y_to_e(ep, d, a, lev))
 583                         return (1);
 584                 if (!(ep[-2] == 'n' && ep[-1] == 'g'))
 585                         return (0);
 586                 break;
 587         case 'c':
 588         case 'g':
 589                 if (*ep == 'a')
 590                         return (0);
 591                 if (vowel(ep[-2]))
 592                         break;
 593                 if (y_to_e(ep, d, a, lev))
 594                         return (1);
 595                 if (!(ep[-2] == 'n' && ep[-1] == 'g'))
 596                         return (0);
 597                 break;
 598         case 'v':
 599         case 'z':
 600                 if (vowel(ep[-2]))
 601                         break;
 602                 if (y_to_e(ep, d, a, lev))
 603                         return (1);
 604                 if (!(ep[-2] == 'n' && ep[-1] == 'g'))
 605                         return (0);
 606                 break;
 607         case 'u':
 608                 if (y_to_e(ep, d, a, lev))
 609                         return (1);
 610                 if (!(ep[-2] == 'n' && ep[-1] == 'g'))
 611                         return (0);
 612                 break;
 613         }
 614         return (VCe(ep, d, a, lev));
 615 }
 616 
 617 /*      possible consonant-vowel-consonant-e ending */
 618 static int
 619 VCe(char *ep, char *d, char *a, int lev)
 620 {
 621         char c;
 622         c = ep[-1];
 623         if (c == 'e')
 624                 return (0);
 625         if (!vowel(c) && vowel(ep[-2])) {
 626                 c = *ep;
 627                 *ep++ = 'e';
 628                 if (trypref(ep, d, lev)||trysuff(ep, lev))
 629                         return (1);
 630                 ep--;
 631                 *ep = c;
 632         }
 633         return (strip(ep, d, a, lev));
 634 }
 635 
 636 static char *
 637 lookuppref(char **wp, char *ep)
 638 {
 639         char **sp;
 640         char *bp, *cp;
 641 
 642         for (sp = preftab; *sp; sp++) {
 643                 bp = *wp;
 644                 for (cp = *sp; *cp; cp++, bp++)
 645                         if (Tolower(*bp) != *cp)
 646                                 goto next;
 647                 for (cp = bp; cp < ep; cp++)
 648                         if (vowel(*cp)) {
 649                                 *wp = bp;
 650                                 return (*sp);
 651                         }
 652 next:;
 653         }
 654         return (0);
 655 }
 656 
 657 /*
 658  *      while word is not in dictionary try stripping
 659  *      prefixes. Fail if no more prefixes.
 660  */
 661 static int
 662 trypref(char *ep, char *a, int lev)
 663 {
 664         char *cp;
 665         char *bp;
 666         char *pp;
 667         int val = 0;
 668         char space[LINE_MAX * 2];
 669         deriv[lev] = a;
 670         if (tryword(word, ep, lev))
 671                 return (1);
 672         bp = word;
 673         pp = space;
 674         deriv[lev+1] = pp;
 675         while (cp = lookuppref(&bp, ep)) {
 676                 *pp++ = '+';
 677                 while (*pp = *cp++)
 678                         pp++;
 679                 if (tryword(bp, ep, lev+1)) {
 680                         val = 1;
 681                         break;
 682                 }
 683         }
 684         deriv[lev+1] = deriv[lev+2] = 0;
 685         return (val);
 686 }
 687 
 688 static int
 689 tryword(char *bp, char *ep, int lev)
 690 {
 691         int i, j;
 692         char duple[3];
 693         if (ep-bp <= 1)
 694                 return (0);
 695         if (vowel(*ep)) {
 696                 if (monosyl(bp, ep))
 697                         return (0);
 698         }
 699         i = dict(bp, ep);
 700         if (i == 0 && vowel(*ep) && ep[-1] == ep[-2] && monosyl(bp, ep-1)) {
 701                 ep--;
 702                 deriv[++lev] = duple;
 703                 duple[0] = '+';
 704                 duple[1] = *ep;
 705                 duple[2] = 0;
 706                 i = dict(bp, ep);
 707         }
 708         if (vflag == 0 || i == 0)
 709                 return (i);
 710         /*
 711          *      when derivations are wanted, collect them
 712          *      for printing
 713          */
 714         j = lev;
 715         do {
 716                 if (deriv[j])
 717                         (void) strcat(affix, deriv[j]);
 718         } while (--j > 0);
 719         return (i);
 720 }
 721 
 722 
 723 static int
 724 monosyl(char *bp, char *ep)
 725 {
 726         if (ep < bp+2)
 727                 return (0);
 728         if (vowel(*--ep) || !vowel(*--ep) || ep[1] == 'x' || ep[1] == 'w')
 729                 return (0);
 730         while (--ep >= bp)
 731                 if (vowel(*ep))
 732                         return (0);
 733         return (1);
 734 }
 735 
 736 static char *
 737 skipv(char *s)
 738 {
 739         if (s >= word&&vowel(*s))
 740                 s--;
 741         while (s >= word && !vowel(*s))
 742                 s--;
 743         return (s);
 744 }
 745 
 746 static int
 747 vowel(int c)
 748 {
 749         switch (Tolower(c)) {
 750         case 'a':
 751         case 'e':
 752         case 'i':
 753         case 'o':
 754         case 'u':
 755         case 'y':
 756                 return (1);
 757         }
 758         return (0);
 759 }
 760 
 761 static int
 762 dict(char *bp, char *ep)
 763 {
 764         int temp, result;
 765         if (xflag)
 766                 (void) fprintf(stdout, "=%.*s\n", ep-bp, bp);
 767         temp = *ep;
 768         *ep = 0;
 769         result = hashlook(bp);
 770         *ep = temp;
 771         return (result);
 772 }