|
|
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.