|
|
1.1 ! root 1: /* ! 2: * hyphen.c ! 3: * Nroff/Troff. ! 4: * Hyphenation. ! 5: */ ! 6: ! 7: #include <ctype.h> ! 8: #include "roff.h" ! 9: ! 10: /* ! 11: * Try to hyphenate the word found in the word buffer. ! 12: */ ! 13: hyphen(cp1, cp2) ! 14: CODE *cp1; ! 15: CODE *cp2; ! 16: { ! 17: register CODE *cpl; ! 18: register int n; ! 19: int wi1, wi2, len; ! 20: ! 21: cpl = cp1; ! 22: n = cp2 - cp1; ! 23: while (n--) ! 24: hyphbuf[n] = 0; ! 25: while (cp1 < cp2) { ! 26: n = cp2[-1].c_arg.c_code; ! 27: if (isascii(n) && isalpha(n)) ! 28: break; ! 29: --cp2; ! 30: } ! 31: len = cp2 - cp1; ! 32: while (cp1 < cp2) { ! 33: n = cp1->c_arg.c_code; ! 34: if (isascii(n) && isalpha(n)) ! 35: break; ! 36: cp1++; ! 37: } ! 38: if (len <= 4) ! 39: return; ! 40: wi1 = 0; ! 41: wi2 = len; ! 42: if (except(cpl, hyphbuf, wi1, wi2)) ! 43: return; ! 44: wi2 = 1 + suffix(cpl, hyphbuf, wi2-1, wi1-1); ! 45: wi1 = prefix(cpl, hyphbuf, wi1, wi2); ! 46: middle(cpl, hyphbuf, wi1, wi2); ! 47: n = len; ! 48: hyphbuf[0] = 0; ! 49: hyphbuf[n-3] = 0; ! 50: hyphbuf[n-2] = 0; ! 51: hyphbuf[n-1] = 0; ! 52: if (wi2-wi1 <= 2) { ! 53: hyphbuf[wi1] = 0; ! 54: hyphbuf[wi2-1] = 0; ! 55: } ! 56: n = wi2; ! 57: if (--n>=0 && cpl[n].c_arg.c_code==LEEE) { ! 58: int m; ! 59: m = 3; ! 60: while (n && m--) ! 61: hyphbuf[n--] = 0; ! 62: } ! 63: n = wi2; ! 64: if (n>=2 && cpl[--n].c_arg.c_code==LDDD && ! 65: cpl[--n].c_arg.c_code==LEEE) { ! 66: if (--n<1 || cpl[n].c_arg.c_code!=LZZZ || ! 67: cpl[n-1].c_arg.c_code!=LIII) { ! 68: if (--n >= 0) ! 69: hyphbuf[n] = 0; ! 70: if (--n >= 0) ! 71: hyphbuf[n] = 0; ! 72: } ! 73: } ! 74: } ! 75: ! 76: /* ! 77: * Look for exception words. ! 78: */ ! 79: except(wbuf, hbuf, wi1, wi2) ! 80: CODE *wbuf; ! 81: char *hbuf; ! 82: { ! 83: unsigned ti, ti0, ti1, ti2, wih, c1, c2; ! 84: register int wi, n; ! 85: register char *bp; ! 86: ! 87: ti = ti1 = 0; /* ti = 0 by c.e.f triggered by lint error */ ! 88: ti2 = EXCSIZE; ! 89: for (;;) { ! 90: ti0 = ti; ! 91: if ((ti=(ti1+ti2)/2) == ti0) ! 92: goto fail; ! 93: wi = wi1; ! 94: wih = wi1; ! 95: bp = exctab[ti]; ! 96: for (;;) { ! 97: if (*bp == LEOK) { ! 98: if (wi == wi2) ! 99: return 1; ! 100: if (wi==wi2-1 && wbuf[wi].c_arg.c_code==LSSS) ! 101: return 1; ! 102: ti1 = ti; ! 103: break; ! 104: } ! 105: if (*bp == LHYP) { ! 106: bp++; ! 107: wih = wi; ! 108: hbuf[wi-1] = 1; ! 109: continue; ! 110: } ! 111: if (wi >= wi2) { ! 112: ti1 = ti; ! 113: break; ! 114: } ! 115: if ((c1=wbuf[wi++].c_arg.c_code) != (c2 = *bp++)) { ! 116: if (c1 > c2) ! 117: ti1 = ti; ! 118: else ! 119: ti2 = ti; ! 120: break; ! 121: } ! 122: } ! 123: for (wi=wi1; wi<wih; wi++) ! 124: hbuf[wi] = 0; ! 125: } ! 126: fail: ! 127: for (n=wi1; n<wi2; n++) ! 128: hbuf[n] = 0; ! 129: return 0; ! 130: } ! 131: ! 132: /* ! 133: * Look for prefixes. ! 134: */ ! 135: prefix(wbuf, hbuf, wi1, wi2) ! 136: CODE *wbuf; ! 137: char *hbuf; ! 138: register int wi2; ! 139: { ! 140: unsigned ti, ti0, ti1, ti2, c1, c2, con; ! 141: register int wi, wih; ! 142: register char *bp; ! 143: ! 144: do { ! 145: ti0 = -1; ! 146: ti = ti1 = 0; /* ti = 0 by c.e.f triggered by lint */ ! 147: ti2 = PRESIZE; ! 148: for (;;) { ! 149: ti0 = ti; ! 150: if ((ti=(ti1+ti2)/2) == ti0) ! 151: return wi1; ! 152: wi = wi1; ! 153: wih = wi1; ! 154: bp = pretab[ti]; ! 155: for (;;) { ! 156: if (*bp == LEOK) { ! 157: bp++; ! 158: goto patn; ! 159: } ! 160: if (*bp == LHYP) { ! 161: bp++; ! 162: wih = wi; ! 163: hbuf[wi-1] = 1; ! 164: continue; ! 165: } ! 166: if (wi >= wi2) ! 167: return wi1; ! 168: if ((c1=wbuf[wi++].c_arg.c_code) != ! 169: (c2 = *bp++)) { ! 170: if (c1 > c2) ! 171: ti1 = ti; ! 172: else ! 173: ti2 = ti; ! 174: break; ! 175: } ! 176: } ! 177: for (wi=wi1; wi<wih; wi++) ! 178: hyphbuf[wi] = 0; ! 179: } ! 180: patn: ! 181: if (automate(bp, &wi1, &con, 1, wbuf, hbuf, wi, wi2) == 0) { ! 182: while (wi > wi1) ! 183: hbuf[--wi] = 0; ! 184: return wi1; ! 185: } ! 186: } while (con != 0); ! 187: return wi1; ! 188: } ! 189: ! 190: /* ! 191: * Look for suffixes. ! 192: */ ! 193: suffix(wbuf, hbuf, wi1, wi2) ! 194: CODE *wbuf; ! 195: char *hbuf; ! 196: register int wi2; ! 197: { ! 198: unsigned ti, ti0, ti1, ti2, c1, c2, con; ! 199: register int wi, wih; ! 200: register char *bp; ! 201: ! 202: do { ! 203: ti0 = -1; ! 204: ti = ti1 = 0; /* ti = 0 by cef triggered by lint */ ! 205: ti2 = SUFSIZE; ! 206: for (;;) { ! 207: ti0 = ti; ! 208: if ((ti=(ti1+ti2)/2) == ti0) ! 209: return wi1; ! 210: wi = wi1; ! 211: wih = wi1; ! 212: bp = suftab[ti]; ! 213: for (;;) { ! 214: if (*bp == LEOK) { ! 215: bp++; ! 216: goto patn; ! 217: } ! 218: if (*bp == LHYP) { ! 219: bp++; ! 220: wih = wi; ! 221: hbuf[wi] = 1; ! 222: continue; ! 223: } ! 224: if (wi <= wi2) ! 225: return wi1; ! 226: if ((c1=wbuf[wi--].c_arg.c_code) != ! 227: (c2 = *bp++)) { ! 228: if (c1 > c2) ! 229: ti1 = ti; ! 230: else ! 231: ti2 = ti; ! 232: break; ! 233: } ! 234: } ! 235: for (wi=wi1; wi>wih; wi--) ! 236: hyphbuf[wi] = 0; ! 237: } ! 238: patn: ! 239: if (automate(bp, &wi1, &con, -1, wbuf, hbuf, wi, wi2) == 0) { ! 240: while (wi < wi1) ! 241: hbuf[++wi] = 0; ! 242: return wi1; ! 243: } ! 244: } while (con != 0); ! 245: return wi1; ! 246: } ! 247: ! 248: /* ! 249: * Try to hyphenate the middle of a word. ! 250: */ ! 251: middle(wbuf, hbuf, wi1, wi2) ! 252: CODE *wbuf; ! 253: char *hbuf; ! 254: { ! 255: int new, bil, c2, c3, n; ! 256: unsigned con; ! 257: register int wi, bi, c1; ! 258: ! 259: wi = wi1; ! 260: bi = 0; ! 261: while (wi < wi2) { ! 262: c1 = wbuf[wi++].c_arg.c_code; ! 263: if (wi<wi2 && wbuf[wi].c_arg.c_code==LHHH) { ! 264: wi++; ! 265: switch (c1) { ! 266: case LCCC: ! 267: c1 = LDCH; ! 268: break; ! 269: case LGGG: ! 270: c1 = LDGH; ! 271: break; ! 272: case LPPP: ! 273: c1 = LDPH; ! 274: break; ! 275: case LSSS: ! 276: c1 = LDSH; ! 277: break; ! 278: case LTTT: ! 279: c1 = LDTH; ! 280: break; ! 281: default: ! 282: --wi; ! 283: break; ! 284: } ! 285: } ! 286: hletbuf[bi] = c1; ! 287: hindbuf[bi++] = wi-1; ! 288: } ! 289: bil = bi-2; ! 290: for (bi=0; bi<bil; bi++) { ! 291: if (!vowel(hletbuf[bi])) ! 292: continue; ! 293: c1 = hletbuf[bi+1]; ! 294: c2 = hletbuf[bi+2]; ! 295: if (c1==c2 && consn(c1)) { ! 296: if (c1 == LLLL) ! 297: continue; ! 298: if (c1 == LSSS) { ! 299: if (bi>=bil-1 || !vowel(hletbuf[bi+3])) ! 300: continue; ! 301: if (automate(mm0code, &new, &con, 1, ! 302: wbuf, hbuf, hindbuf[bi+3], wi2)==0) ! 303: continue; ! 304: } ! 305: hbuf[hindbuf[++bi]] = 1; ! 306: continue; ! 307: } ! 308: if (c1==LCCC && c2==LKKK) { ! 309: hbuf[hindbuf[bi+=2]] = 1; ! 310: continue; ! 311: } ! 312: if (c1==LQQQ && c2==LUUU) { ! 313: hbuf[hindbuf[bi]] = 1; ! 314: continue; ! 315: } ! 316: if (bi < bil-1) { ! 317: c3 = hletbuf[bi+3]; ! 318: if (!consn(c1) || !consn(c2) || !vowel(c3)) ! 319: continue; ! 320: if ((n=matpair(c1, c2)) == 2) ! 321: continue; ! 322: if (n==1 && automate(mm1code, &new, &con, 1, ! 323: wbuf, hbuf, hindbuf[bi+3], wi2)==0) ! 324: continue; ! 325: hbuf[hindbuf[++bi]] = 1; ! 326: continue; ! 327: } ! 328: } ! 329: } ! 330: ! 331: /* ! 332: * See if we match a set of double consonants. If we do, ! 333: * return the associated number in the table. ! 334: */ ! 335: matpair(c1, c2) ! 336: register int c1; ! 337: { ! 338: register int c; ! 339: register char *cp; ! 340: ! 341: cp = dbctab; ! 342: while ((c = *cp++) != LNUL) { ! 343: if (c1 < c) ! 344: return 0; ! 345: if (c1 > c) { ! 346: cp += 2; ! 347: continue; ! 348: } ! 349: if (c2 != *cp++) { ! 350: cp++; ! 351: continue; ! 352: } ! 353: return *cp; ! 354: } ! 355: return 0; ! 356: } ! 357: ! 358: /* ! 359: * Given a pattern string, execute it on the given word buffer. ! 360: */ ! 361: automate(patp, newp, conp, dirn, wbuf, hbuf, wi1, wi2) ! 362: char *patp; ! 363: int *newp; ! 364: unsigned *conp; ! 365: CODE *wbuf; ! 366: char *hbuf; ! 367: { ! 368: int wi, wis; ! 369: register int c, n; ! 370: register char *bp; ! 371: ! 372: bp = patp; ! 373: *conp = 0; ! 374: wi = wi1; ! 375: wis = wi1; ! 376: for (;;) { ! 377: switch (*bp++) { ! 378: case LNUL: ! 379: goto succ; ! 380: case LHYP: ! 381: wis = wi; ! 382: *conp = 0; ! 383: hbuf[wi-(dirn>0?1:0)] = 1; ! 384: continue; ! 385: case LRHP: ! 386: hbuf[wi-(dirn>0?1:0)] = 0; ! 387: continue; ! 388: case LCON: ! 389: *conp = 1; ! 390: continue; ! 391: case LNEW: ! 392: n = *bp++; ! 393: if (wi != wi2) { ! 394: c = wbuf[wi].c_arg.c_code; ! 395: wi += dirn; ! 396: continue; ! 397: } ! 398: if (n == 1) ! 399: goto fail; ! 400: if (n == 2) ! 401: goto succ; ! 402: bp += n-3; ! 403: continue; ! 404: case LOLD: ! 405: wi -= dirn; ! 406: c = wbuf[wi-dirn].c_arg.c_code; ! 407: continue; ! 408: case LBRF: ! 409: goto fail; ! 410: case LBRS: ! 411: goto succ; ! 412: case LCBT: ! 413: if (*bp++ != c) { ! 414: bp++; ! 415: continue; ! 416: } ! 417: if ((n = *bp++) == 1) ! 418: goto fail; ! 419: if (n == 2) ! 420: goto succ; ! 421: bp += n-3; ! 422: continue; ! 423: case LCBF: ! 424: if (*bp++ == c) { ! 425: bp++; ! 426: continue; ! 427: } ! 428: if ((n = *bp++) == 1) ! 429: goto fail; ! 430: if (n == 2) ! 431: goto succ; ! 432: bp += n-3; ! 433: continue; ! 434: default: ! 435: panic("bad pattern"); ! 436: } ! 437: } ! 438: succ: ! 439: *newp = wis; ! 440: return 1; ! 441: fail: ! 442: return 0; ! 443: } ! 444: ! 445: /* ! 446: * See if the given code is a vowel. ! 447: */ ! 448: vowel(c) ! 449: register int c; ! 450: { ! 451: if (c>=LAAA && c<=LYYY && contab[c-LAAA]==0) ! 452: return 1; ! 453: return 0; ! 454: } ! 455: ! 456: /* ! 457: * See if the given code is a consonant. ! 458: */ ! 459: consn(c) ! 460: register int c; ! 461: { ! 462: if (c>=LAAA && c<=LDTH && contab[c-LAAA]==1) ! 463: return 1; ! 464: return 0; ! 465: } ! 466: ! 467: /* ! 468: * Code to fail if we match ((er|ers)$). ! 469: */ ! 470: char mm0code[] ={ ! 471: 0005, 0002, 0012, 0051, 0002, 0005, 0002, 0012, ! 472: 0066, 0002, 0005, 0001, 0012, 0067, 0002, 0005, ! 473: 0001, 0010, 0000 ! 474: }; ! 475: ! 476: /* ! 477: * Code to fail if we match ((er|ers|age|ages|est)$). ! 478: */ ! 479: char mm1code[] ={ ! 480: 0005, 0002, 0011, 0051, 0030, 0012, 0045, 0002, ! 481: 0005, 0002, 0012, 0053, 0002, 0005, 0002, 0012, ! 482: 0051, 0002, 0005, 0001, 0012, 0067, 0002, 0005, ! 483: 0001, 0010, 0005, 0002, 0011, 0066, 0016, 0012, ! 484: 0067, 0002, 0005, 0002, 0012, 0070, 0002, 0005, ! 485: 0001, 0010, 0005, 0001, 0012, 0067, 0002, 0005, ! 486: 0001, 0010, 0000 ! 487: }; ! 488: ! 489: /* ! 490: * Table to determine whether a letter is a constant or a vowel. ! 491: */ ! 492: char contab[] ={ ! 493: 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, ! 494: 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 ! 495: }; ! 496: ! 497: /* ! 498: * Pairs of consonants which aren't allowed somewhere. ! 499: */ ! 500: char dbctab[] ={ ! 501: LBBB, LLLL, 2, ! 502: LBBB, LRRR, 2, ! 503: LCCC, LLLL, 2, ! 504: LCCC, LRRR, 2, ! 505: LFFF, LLLL, 2, ! 506: LFFF, LRRR, 2, ! 507: LFFF, LTTT, 1, ! 508: LGGG, LLLL, 2, ! 509: LGGG, LRRR, 2, ! 510: LKKK, LNNN, 2, ! 511: LLLL, LDDD, 1, ! 512: LLLL, LKKK, 2, ! 513: LLLL, LQQQ, 2, ! 514: LMMM, LPPP, 1, ! 515: LNNN, LDDD, 1, ! 516: LNNN, LGGG, 1, ! 517: LNNN, LKKK, 2, ! 518: LNNN, LSSS, 1, ! 519: LNNN, LTTT, 1, ! 520: LNNN, LXXX, 2, ! 521: LNNN, LDCH, 2, ! 522: LPPP, LLLL, 2, ! 523: LPPP, LRRR, 2, ! 524: LRRR, LGGG, 1, ! 525: LRRR, LKKK, 2, ! 526: LRRR, LMMM, 1, ! 527: LRRR, LNNN, 1, ! 528: LRRR, LTTT, 1, ! 529: LSSS, LPPP, 2, ! 530: LSSS, LQQQ, 2, ! 531: LSSS, LTTT, 1, ! 532: LTTT, LRRR, 2, ! 533: LTTT, LDCH, 2, ! 534: LWWW, LHHH, 2, ! 535: LWWW, LLLL, 2, ! 536: LWWW, LNNN, 2, ! 537: LWWW, LRRR, 2, ! 538: LDCH, LLLL, 2, ! 539: LDCH, LRRR, 2, ! 540: LDDD, LGGG, 2, ! 541: LDDD, LRRR, 2, ! 542: LDGH, LTTT, 2, ! 543: LDPH, LRRR, 2, ! 544: LDTH, LRRR, 2, ! 545: LNUL ! 546: }; ! 547: ! 548: /* end of hyphen.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.