1 
2 /************************************************************************
3  *                                                                      *
4  *              VIETNAMESE PRE-PROCESSOR FOR TROFF                      *
5  *                                                                      *
6  * Written in Pascal by Hu+~u (University of California at Berkeley)    *
7  * Converted to C & modified by Tra^`n H. Nha^n (Concurrent Computer)   *
8  *                                                                      *
9  * This program processes a text file with special vietnamese character *
10  * sequences giving an output suitable for troff processing.            *
11  *                                                                      *
12  * The default diacritical marks are define as followed:                *
13  *                                                                      *
14  * #define Dau_Sac         '\''                                         *
15  * #define Dau_Huyen       '`'                                          *
16  * #define Dau_Hoi         '?'                                          *
17  * #define Dau_Nga         '~'                                          *
18  * #define Dau_Nang        '.'                                          *
19  * #define Dau_Mu          '^'                                          *
20  * #define Dau_Trang       '('                                          *
21  * #define Dau_Rau         '+'                                          *
22  * #define Escape_Symbol   '\\'                                         *
23  *                                                                      *
24  * Change them to any symbol you are comfortable with.                  *
25  *                                                                      *
26  * Rule for writing Vietnamese:                                         *
27  *                                                                      *
28  * 1 diacritical mark: vowel followed by symbol, i.e: a' e? o` u~ a^ u+ *
29  * 2 diacritical marks: vowel followed by Dau_Mu, Dau_Trang, Dau_Rau    *
30  *                     then other symbols, i.e: a^' o+~ a(` ...         *
31  *                                                                      *
32  * DD and dd: self-explanatory, the resulting case is the same as the   *
33  * first character of [Dd][Dd].                                         *
34  *                                                                      *
35  * The Escape_Symbol is provided to avoid the confusion between the     *
36  * diacritical marks and end-of-sentence symbols (. ; ? ! ...)          *
37  * i.e: the question           Anh ddi dda^u?                           *
38  *      should be typed        Anh ddi dda^u#?                          *
39  ************************************************************************/
40 
41 #include <stdio.h>
42 #include <string.h>
43 #include <ctype.h>
44 
45 /************************************************************************
46    Customization: substitute your favorite symbol for ' ` ? ~ . ^ ( + #
47  ************************************************************************/
48 
49 #define Dau_Sac         '\''      /* type ' only not \' */
50 #define Dau_Huyen       '`'
51 #define Dau_Hoi         '?'
52 #define Dau_Nga         '~'
53 #define Dau_Nang        '.'
54 #define Dau_Mu          '^'
55 #define Dau_Trang       '('
56 #define Dau_Rau         '+'
57 #define Escape_Symbol   '\\'
58 
59 #define NON     0          /* ^ as in a^ */
60 #define RAU     1          /* + as in u+, o+ */
61 #define TRANG   2          /* ( as in a( */
62 #define NONE    3          /* no mark */
63 #define II      4          /* specify i, I */
64 
65 char List1[] = {Dau_Sac, Dau_Huyen, Dau_Hoi, Dau_Nga, Dau_Nang, '\0'};
66 char List2[] = {Dau_Sac, Dau_Huyen, Dau_Hoi, Dau_Nga, Dau_Nang,
67                 Dau_Mu, Dau_Rau, Dau_Trang, '\0'};
68 
69 #define Is_Vowel(ch)    (strchr("aeiouyAEIOUY",(ch)) != NULL)
70 #define Is_in_list1(ch) (strchr(List1,(ch)) != NULL)
71 #define Is_in_list2(ch) (strchr(List2,(ch)) != NULL)
72 
73 float extendUp, extendLeft;
74 FILE *infile;
75 
76 /***************************************************************************
77  * Move: This is a basic routine used to move a given symbol around to     *
78  *       achieve the desired Vietnamese character.                         *
79  *                                                                         *
80  * Example: to create a', first print out a, then move the symbol '        *
81  *          left 0.5 of m units and up 0 m units.  (m is a unit dependent  *
82  *          on the current point size.  Thus the program works for all     *
83  *          point sizes you specify).  If left and up are negative then    *
84  *          the symbol is moved right and down instead.                    *
85  ***************************************************************************/
86 
Move(left,up,symbol)87 void Move(left,up,symbol)
88 float left,up;
89 int symbol;
90 {
91    if (left+extendLeft != 0)
92       printf("\\h'%.2fm'",-(left+extendLeft));
93    if (up+extendUp != 0)
94       printf("\\v'%.2fm'",-(up+extendUp));
95    switch (symbol) {
96      case Dau_Sac   : printf("\\z\\'");
97 	              break;
98      case Dau_Huyen : printf("\\z\\`");
99 	              break;
100      case Dau_Hoi   : printf("\\z'");
101 	              break;
102      case Dau_Nga   : printf("\\z\\fB~\\fP");
103 	              break;
104      case Dau_Nang  : printf("\\z.");
105 	              break;
106      case '-'       : printf("\\z\\(hy");
107 	              break;
108      case Dau_Mu    : printf("\\z^");
109 	              break;
110      default        : break;
111    }
112    if (up+extendUp != 0)
113       printf("\\v'%.2fm'",up+extendUp);
114    if (left+extendLeft != 0)
115       printf("\\h'%.2fm'",left+extendLeft);
116 }
117 
118 /***************************************************************************
119  * Bo_Dau_Sac: Bo? da^'u sa('c for all cases.                              *
120  ***************************************************************************/
121 
Bo_Dau_Sac(l)122 void Bo_Dau_Sac(l)
123 int l;
124 {
125    switch (l) {
126      case NONE  : Move(0.5,0.0,Dau_Sac);        /* ex: a' e' O' ... */
127 	          break;
128      case NON   : Move(0.4,0.15,Dau_Sac);       /* ex: a^' E^' ... */
129 	          break;
130      case RAU   : Move(0.6,0.1,Dau_Sac);        /* ex: o+' U+' ... */
131 	          break;
132      case TRANG : Move(0.5,0.15,Dau_Sac);       /* ex: a(' A(' ... */
133 	          break;
134      case II    : Move(0.3,0.15,Dau_Sac);       /* ex: i' I' ... */
135 	          break;
136      default    : break;
137    }
138 }
139 
140 /***************************************************************************
141  * Bo_Dau_Huyen: Bo? da^'u huye^`n for all cases.                          *
142  ***************************************************************************/
143 
Bo_Dau_Huyen(l)144 void Bo_Dau_Huyen(l)
145 int l;
146 {
147    switch (l) {
148      case NONE  : Move(0.5,0.0,Dau_Huyen);       /* a` e` O` ... */
149 	          break;
150      case NON   : Move(0.6,0.15,Dau_Huyen);      /* a^` E^` ... */
151 	          break;
152      case II    : Move(0.4,0.15,Dau_Huyen);      /* i` I` ... */
153 	          break;
154      case RAU   : Move(0.55,0.1,Dau_Huyen);      /* u+` O+` ... */
155 	          break;
156      case TRANG : Move(0.5,0.15,Dau_Huyen);      /* a(` A(` ... */
157 	          break;
158      default    : break;
159    }
160 }
161 
162 /***************************************************************************
163  * Bo_Dau_Hoi: Bo? da^'u ho?i for all cases.                               *
164  ***************************************************************************/
165 
Bo_Dau_Hoi(l)166 void Bo_Dau_Hoi(l)
167 int l;
168 {
169    switch(l) {
170       case NONE  : Move(0.4,0.1,Dau_Hoi);       /* a? e? O? ... */
171 	           break;
172       case NON   :
173       case II    : Move(0.25,0.2,Dau_Hoi);      /* a^? E^? i? I? ... */
174 	           break;
175       case RAU   : Move(0.45,0.15,Dau_Hoi);     /* u+? o+? ... */
176                    break;
177       case TRANG : Move(0.40,0.15,Dau_Hoi);     /* a(? A(? ... */
178 	           break;
179       default    : break;
180    }
181 }
182 
183 /***************************************************************************
184  * Bo_Dau_Nga: Bo? da^'u nga~ for all cases.                               *
185  ***************************************************************************/
186 
Bo_Dau_Nga(l)187 void Bo_Dau_Nga(l)
188 int l;
189 {
190    switch (l) {
191      case NONE  : Move(0.5,0.0,Dau_Nga);       /* a~ e~ O~ ... */
192 	          break;
193      case NON   :
194      case TRANG : Move(0.5,0.15,Dau_Nga);      /* a^~ a(~ E^~ ... */
195 	          break;
196      case RAU   : Move(0.55,0.15,Dau_Nga);     /* u+~ O+~ ... */
197 	          break;
198      case II    : Move(0.4,0.06,Dau_Nga);      /* i~ I~ ... */
199 	          break;
200      default    : break;
201    }
202 }
203 
204 /***************************************************************************
205  * Bo_Dau_Nang: Bo? da^'u na(.ng for all cases.                            *
206  ***************************************************************************/
207 
Bo_Dau_Nang(l)208 void Bo_Dau_Nang(l)
209 int l;
210 {
211    extendUp = 0;
212    if (l == II)
213       Move(0.3,-0.2,Dau_Nang);       /* i. I. */
214    else
215       Move(0.4,-0.2,Dau_Nang);       /* all other cases */
216 }
217 
218 /***************************************************************************
219  * Bo_Dau: bo? da^'u cho mo.i tru+o+`ng ho+.p                              *
220  ***************************************************************************/
221 
Bo_Dau(c,nextc,loai)222 void Bo_Dau(c,nextc,loai)
223 int c,nextc,loai;
224 {
225    if (nextc == Dau_Trang)
226       switch (c) {                     /* create a( A( */
227 	 case 'a' :
228 	 case 'A' : putchar(c);
229                     getc(infile);
230 		    loai = TRANG;
231 		    Move(0.50,-0.1,Dau_Huyen);
232 		    Move(0.50-0.02,-0.1,Dau_Sac);
233 		    break;
234 	 default  : break;
235       }
236    else if (nextc == Dau_Rau)         /* create o+ u+ O+ U+ */
237       switch (c) {
238 	 case 'o' :
239 	 case 'O' :
240 	 case 'u' :
241 	 case 'U' : putchar(c);
242                     getc(infile);
243 		    loai = RAU;
244 		    if (isupper(c))
245 		       Move(0.2,-0.05,Dau_Hoi);
246 		    else
247 		       Move(0.25,-0.1,Dau_Hoi);
248 		    break;
249 	 default :  break;
250       }
251    else if (nextc == Dau_Mu)                 /* create a^ e^ o^ A^ E^ O^ */
252       switch (c) {
253 	 case 'a' :
254 	 case 'e' :
255 	 case 'o' : printf("\\o'%c^'",c);
256                     getc(infile);
257 		    loai = NON;
258 		    break;
259 	 case 'A' :
260 	 case 'E' :
261 	 case 'O' : putchar(c);
262                     getc(infile);
263                     Move(0.55,0.0,Dau_Mu);
264 		    loai = NON;
265 		    break;
266 	 default  : break;
267       }
268    if (Is_in_list1(nextchar())) {
269       c = getc(infile);                     /* If next char is ' ` ? ~ . */
270       switch(c) {                           /* then bo? da^'u */
271 	case Dau_Sac   : Bo_Dau_Sac(loai);
272 	                 break;
273 	case Dau_Huyen : Bo_Dau_Huyen(loai);
274 	                 break;
275 	case Dau_Hoi   : Bo_Dau_Hoi(loai);
276 	                 break;
277 	case Dau_Nga   : Bo_Dau_Nga(loai);
278 	                 break;
279 	case Dau_Nang  : Bo_Dau_Nang(loai);
280 	                 break;
281 	default        : break;
282       }
283    }
284 }
285 
286 /***************************************************************************
287  * nextchar(): return next character but leave buffer untouched.           *
288  ***************************************************************************/
289 
nextchar()290 int nextchar()
291 {
292    int c;
293 
294    c = getc(infile);
295    ungetc(c,infile);
296 
297    return (c);
298 }
299 
300 /***************************************************************************
301  * main: process file                                                      *
302  ***************************************************************************/
303 
main(argc,argv)304 main(argc, argv)
305 int argc;
306 char *argv[];
307 {
308    int ch,nextch,loai;
309 
310    if (argc < 2) {
311       printf("Usage: vnroff filename\n");
312       exit(0);
313    }
314    if ((infile = fopen(argv[1],"r")) == NULL) {
315       printf("Cannot open file %s\n",argv[1]);
316       exit(0);
317    }
318    while ((ch = getc(infile)) != EOF) {
319       extendUp = extendLeft = 0;
320       if (Is_Vowel(ch)) {               /* take care vowel */
321 	 nextch = nextchar();
322 	 if (Is_in_list2(nextch)) {     /* is next char diacritical marks */
323 	    if (isupper(ch)) {
324 	       extendUp = 0.2;
325 	       if (ch != 'I')
326 		  extendLeft = 0.1;
327 	    }
328 	    loai = (ch == 'i' || ch == 'I') ? II : NONE;
329 	    switch (nextch) {
330 	       case Dau_Trang :
331 	       case Dau_Mu    :
332 	       case Dau_Rau   : Bo_Dau(ch,nextch,loai);
333 			        break;
334 	       case Dau_Sac   :
335 	       case Dau_Huyen :
336 	       case Dau_Hoi   :
337 	       case Dau_Nga   :
338 	       case Dau_Nang  : putchar(ch);
339 		                Bo_Dau(ch,nextch,loai);
340 		                break;
341 	       default        : break;
342 	    }
343 	 }
344 	 else
345 	    putchar(ch);
346       }
347       else if (toupper(ch) == 'D') {       /* take care DD, dd */
348 	 putchar(ch);
349 	 if (toupper(nextchar()) == toupper(ch)) {
350 	    getc(infile);
351 	    if (ch == 'd')
352                Move(0.30,0.35,'-');
353             else
354                Move(0.70,0.15,'-');
355 	 }
356       }
357       else if (ch == Escape_Symbol)            /* print next char as is */
358 	 putchar(getc(infile));
359       else                                     /* print all other char */
360          putchar(ch);
361    }
362 }
363 
364 
365