1 /* $Id: devnag.c,v 1.15 2008-03-09 15:57:59 icebearsoft Exp $
2 Version 2.15
3
4 *
5 Preprocessor for Devanagari for TeX package
6 Copyright (C) 1991-1998 University of Groningen, The Netherlands
7 *
8 Author : Frans J. Velthuis <velthuis@rc.rug.nl>
9 Date : 09 May 1991
10 *
11 The maintainer of this program is now Zdenek Wagner <zdenek.wagner@gmail.com>.
12 *
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 1, or (at your option)
16 any later version.
17 *
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22 *
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 */
27
28 /*
29 Modified by Marc Csernel, March 1998, to support LaTeX commands
30 with arguments and environments between the dn delimiters.
31 */
32
33 /*
34 Version 2.0 of devnag is the first major revision of the program
35 since its original release. It is based on version 1.6 (there are
36 no releases 1.7, 1.8 or 1.9), and, in addition to Marc Csernel's
37 LaTeX extensions, it incorporates the following modifications made
38 by John Smith in 1998-9:
39
40 1. A major change has been made to the way in which the
41 preprocessor handles "@" commands. Previously it was only
42 possible to use these at the start of the .dn file; now they may
43 be placed anywhere in the text, provided that they do not occur
44 within passages of Devanagari (where "@" has its own meaning).
45 New "negative" commands have been added to reverse the effect of
46 most existing commands: thus it is now possible to enable or
47 disable specific features for specific passages of text. @hindi
48 may be disabled with @sanskrit; @dollars with @nodollars or
49 @dolmode0; @hyphen with @nohyphen; @tabs (a new LaTeX feature
50 added by Marc Csernel) with @notabs. Since "@" is a perfectly
51 legal character in TeX, lines beginning with "@" that do not
52 match any valid "@" command are flagged with a warning, but
53 processing of the file continues. (In the somewhat unlikely
54 event that you actually need to have a line of TeX text
55 consisting exactly of, say, "@hindi", the preprocessor may be
56 fooled by typing "{}@hindi", "{@hindi}", or anything similar.)
57
58 2. The old line-splitting code and the @obeylines preprocessor
59 command to disable it have been withdrawn, so that the program
60 now outputs one line to the .tex file for every line of the
61 .dn file. In devnag 2.0, attempted use of @obeylines produces
62 a specific warning; this is likely to be withdrawn in a future
63 release, after which attempts to use it will cause "@obeylines"
64 to be typeset as a part of the text of the document (see 1.
65 above).
66
67 3. To complete the line-by-line correspondence between the input
68 and output files, comments are no longer stripped out, and
69 preprocessor commands (such as "@hyphen") are passed through
70 into the output file in the form of comments ("%@hyphen").
71
72 4. There is now an option to show the version of the program. If
73 devnag is invoked as "devnag -v" it will print a banner giving
74 the version number and other information, and then exit.
75
76 5. If the input file has a name such as "x.y.dn", the output file
77 will now be "x.y.tex", not, as previously, "x.tex". In addition,
78 it is now mandatory for the files to have the suffixes ".dn" and
79 ".tex", though as before these are supplied by the program if
80 omitted by the user. This change has been made for safety
81 reasons: formerly, typing "devnag myfile.tex" would delete
82 the contents of myfile.tex.
83
84 6. The sequence ~nj~na now produces the correct form.
85
86 7. The sequences r.l and r.L now produce the correct forms.
87
88 8. The sequences ttrya, ttrva, khrya and khrva now produce the
89 correct forms.
90
91 9. The correct "caret" form of -r is now produced under kh, ch,
92 etc., even when a subscript vowel or viraama follows. This has
93 necessitated a new macro (\qc), which must be defined in
94 dnmacs.tex (for Plain TeX) or dev.sty (for LaTeX). The
95 definition is:
96
97 \def\qc#1#2{\setbox0=\hbox{#1}#1\subscr{\char126\kern1.5ex\lower1.25ex
98 \hbox{\char#2}\kern-1.5ex}}
99
100 Suitable versions of the files are distributed with the current
101 release of the devnag package.
102
103 10. A fragment of code which permitted hyphenation in the middle of
104 a consonant sequence containing a viraama has been removed.
105 All hyphenation before consonants stopped with viraama has
106 also been eliminated.
107
108 11. A change has been introduced in the output that devnag produces
109 from input such as {\dn .sa.t"siraa.h}, i.e. in cases where an
110 i-matra vowel is associated with a consonant sequence containing
111 a viraama. The previous behaviour was to treat the consonant
112 sequence as if it were a normal conjunct by placing the vowel
113 symbol before the sequence as a whole. The majority opinion
114 seems to be that this is undesirable, and that the vowel symbol
115 should follow the consonant to which the viraama is attached.
116 A change has therefore been made to implement this. However, the
117 previous behaviour can be reinstated by means of a new
118 preprocessor command, @vconjuncts.
119
120 12. Tab characters in the input file, which previously were treated
121 as fatal errors, are now silently converted to spaces.
122
123 13. (Internal coding changes) The order of the C code has been
124 normalised from the original Pascal-like bottom-up sequence
125 to a more conventional top-down version. Numerous comments have
126 been added to assist potential future developers in understanding
127 the way the program works. A number of bug-fixes and other
128 improvements have been applied. The insecure gets() calls used
129 in prompting for user input have been replaced by fgets().
130 Variables used only within a single function have been declared
131 local to that function. Some variables have been renamed in
132 the interests of clarity and consistency, and some redundant
133 ones have been eliminated. The functions ch_find() and st_find(),
134 which simply duplicated the standard library functions strchr()
135 and strstr(), have also been eliminated.
136 */
137
138 /*
139 Version 2.01 is a bugfix release, containing two changes in
140 coding. (1) Previous versions of devnag have output "[" and "]"
141 for Devanagari half-"sa and half-gha. Under some circumstances
142 this can interact badly with LaTeX, and the form of output has
143 been changed to avoid the problem. (2) \cline has been added to
144 the list of LaTeX commands which devnag knows how to handle.
145 -- John Smith
146 */
147
148 /*
149 Version 2.02 redefines all ^^* characters to be output as
150 \3XXw because it is more robust. It puts a definition
151 of \DevnagVersion at the beginning of the output file so
152 that the new preprocessed files can be automatically recognized
153 (Z. Wagner, zdenek.wagner@gmail.com, http://icebearsoft.euweb.cz).
154 This version also defines a new preprodessor directive
155 @modernhindi, which functions in the same way as @hindi but
156 uses far fewer Sanskrit-style ligatures, preferring conjuncts
157 built from half-consonant forms wherever possible. (Thanks to
158 Raymond Doctor for helpful advice on which ligatures to permit
159 and which to suppress.) The definition of @sanskrit has been
160 changed so that it now restores all the ligatures disabled by
161 @modernhindi, not just those disabled by @hindi. The sequences
162 kk.sa, .tk.sa, dmya and hmya have been modified to produce
163 k+k.sa, .t+k.sa, d+mya, h+mya (rather than, as previously,
164 kk+.sa, .tk+.sa dm+ya, hm+ya). The code which handles all such
165 substitutions has been radically improved. The special warning
166 message prompted by the long-defunct preprocessor directive
167 @obeylines has been removed.
168 -- John Smith
169 */
170
171 /*
172 Version 2.1 makes the following changes:
173 *
174 * Material within {\dn ... } (or $ ... $) may be enclosed within
175 angle brackets < ... >; it is then not processed, but is passed
176 through verbatim to the output file, e.g.
177 {\dn eka do <\hrule width 10 em> tiina caara}
178 * Changes to the fonts have made an "open ya" glyph available. This
179 is now used wherever the preprocessor would previously have
180 produced consonant + viraama + ya.
181 * The fonts now contain defined glyphs for .n.na; the preprocessor
182 uses these.
183 * In previous releases the "half j~na" glyph was not used in @hindi
184 and @modernhindi modes (the program output "half ja + half ~na").
185 This has been corrected.
186 * The output now avoids using the following control symbols: \", \#,
187 \$, \%, \&, \'.
188 -- John Smith
189 */
190
191 /*
192 Version 2.11 is a bugfix release to deal with two problems:
193 *
194 * Newline characters were not being properly handled in material
195 enclosed within angle brackets < ... >;
196 * The input sequence ~a was producing the wrong output for the
197 initial form of the vowel.
198 -- John Smith
199 */
200
201 /*
202 Version 2.12 contains two modification by Kevin Carmody, one to add
203 the ligature disabling character "+", and one bug fix to avoid the use
204 of non-standard syntax in invocations of fixconj().
205 */
206
207 /*
208 Bug fix suggested by John Smith: put_syll() just after case '<' in order
209 to emit pending syllable. The verbatim material should appear between
210 words but you can even write {\dn pa<\kern -2pt >de} if you know what
211 you are doing. However, such use is strongly discouraged.
212 */
213
214 /*
215 Version 2.13: ~m is now a synonym for /, i.e. candrabindu
216 */
217
218 /*
219 Version 2.14 contains the following modifications:
220
221 Accented characters with codes >= 128 are allowed in \dn texts
222 within {\rm ...} and <...>
223 UTF-8 is not yet supported.
224
225 The filename extensions are not fixed but have reasoanble defaults
226 defined by constants DEFAULT_SRC_EXT (= ".dn") and
227 DEFAULT_DEST_EXT (= ".tex"). It is explicitly forbidden for the source
228 file to have the extension defined by DEFAULT_DEST_EXT. The file names
229 are examined as follows:
230
231 1. If the source filename does not have the default extension, it is
232 appended. If such a file does not exist, the preprocessor tries
233 again with the original file name.
234
235 2. If the destination filename was given, its extension is checked.
236 It is explicitly forbidden for the destination file to have the
237 extension defined by DEFAULT_SRC_EXT. If the filename is equal
238 to the name of the source file, DEFAULT_DEST_EXT is appended,
239 otherwise the file name is used as is.
240
241 3. If the destination filename was not given, it is based upon the
242 source filename. If the source filename contains the
243 DEFAULT_SRC_EXT extension, it is stripped of. Afterwards the
244 DEFAULT_DEST_EXT extension is appended.
245
246 The algorithm was designed to prevent typing errors but it is far
247 from foolproof. The filesystem properties are not examined and all
248 filename tests are case insensitive. The file names are not expanded.
249 For instance, if the working directory is "/some/path", then "x.y",
250 "./x.y", "../path/x.y" as well as "/some/path/x.y" refer to the same
251 file but they will be treated as different by the preprocessor.
252 Moreover, the algorithm does not try to follow symlinks neither does it
253 examine inodes in order to discover hard links.
254
255 Notes for compilation:
256 Some C libraries do not contain strcasecmp but contain either stricmp
257 or strcmpi (or both) with the same syntax. If it is the case of your
258 compiler, use -DHAS_STRCMPI or -DHAS_STRICMP. GCC/EMX for OS/2
259 requires -DHAS_STRICMP, gcc 3.3.3 in Linux as well as gcc 2.95.2
260 from mingw (Windows) know strcasecmp.
261
262 The preprocessor can read files with any line endings on all platforms
263 (i.e. DOS CRLF, UNIX LF as well as Macintosh CR). More precisely: each
264 CR followed by LF is ignored and each CR followed by anything else is
265 treated as end of line. The line endings of the output file always
266 conform to conventions used on the operating system where the
267 preprocessor runs.
268 */
269
270 /*
271 Modifications in version 2.15:
272
273 \def\DevnagVersion is inserted at the beginning of the second line
274 if the first line starts with %&
275
276 Error and warning messages written to stderr instead of stdout
277 (requested by Karl Berry)
278 */
279
280 const char *version = "2.15";
281
282 #include <stdio.h>
283 #include <ctype.h>
284 #include <string.h>
285 #include <stdlib.h> /* Marc Csernel */
286
287 /* General constants */
288 #define TRUE 1
289 #define FALSE 0
290 #define VIRAAM 94
291 #define SMALLBUF 30
292 #define MEDBUF 512
293 #define MAXBUF 2048
294 #define N_NOLIGS (sizeof nolig / sizeof nolig[0])
295 #define N_MNOLIGS (sizeof modnolig / sizeof modnolig[0])
296 #define ill_char 29
297 #define dummy 30
298 #define end_of_file 30
299 #define end_of_line 31
300
301 /*
302 * Constants used in char_def structs
303 */
304 /* ch_typ constants */
305 #define illegal 0
306 #define cmr 1
307 #define control 2
308 #define dn 3
309 #define numeral 4
310 /* ch_subtyp constants */
311 #define lo_vowel 0
312 #define hi_vowel 1
313 #define consonant 2
314 #define special 3
315
316 /* Constants representing symbols: defined as indexes into out_string[] */
317 #define LBRACE 273
318 #define RBRACE 264
319 #define RE 263 /* \thinspace on switching from cmr to dn */
320 #define RDT 266 /* raised r-dot (repha + anusvara) */
321 #define RN 265 /* numeral, using cmr or dn as appropriate */
322 #define RS 256 /* \thinspace on switching from dn to cmr */
323
324 /* Default extensions */
325 #define DEFAULT_SRC_EXT ".dn"
326 #define DEFAULT_DEST_EXT ".tex"
327
328 /*
329 Some C libraries do not have strcasecmp but have either strcmpi or stricmp
330 with the same syntax. Select the one you have.
331 */
332 #ifdef HAS_STRCMPI
333 #define strcasecmp(s1,s2) strcmpi(s1,s2)
334 #elif HAS_STRICMP
335 #define strcasecmp(s1,s2) stricmp(s1,s2)
336 #endif
337
338 /* Global variable declarations */
339 FILE *f_in, *f_out;
340 char *p_in;
341 int charbuf, wasCR = FALSE, charpresent = FALSE;
342 int number;
343 char symbol;
344 char infil[MEDBUF], outfil[MEDBUF];
345 char inbuf[MAXBUF], outbuf[MAXBUF];
346 char word[MEDBUF];
347 short syll[SMALLBUF];
348 int n_halves, buf_idx;
349 short half_codes[SMALLBUF];
350 short joincode;
351 unsigned char hindi_mode, mhindi_mode, dollar_mode, d_found;
352 unsigned char tabs_mode; /* Marc Csernel */
353 unsigned char no_dn, wait_syll, do_hyphen, do_vconjuncts;
354 unsigned char cons_seen, vow_seen, front_r, cmr_mode, num_mode;
355 unsigned char lig_block; /* Kevin Carmody */
356 short chr_idx, cons_code;
357 const char *banner =
358 "Preprocessor for Devanagari for TeX package\n\
359 Copyright (C) 1991-1998 University of Groningen, The Netherlands\n\
360 Author : Frans J. Velthuis <velthuis@rc.rug.nl>\n\
361 Maintainer : Zdenek Wagner <zdenek.wagner@gmail.com>";
362
363 /* Function declarations */
364 int main(int argc, char **argv);
365 void dnproc(void);
366 void put_ch(short code);
367 void sendchar(char c);
368 void put_sym(short code);
369 void put_word(void);
370 void put_syll(void);
371 void tst_half(void);
372 void put_macro(short macro);
373 void err_ill(const char *str);
374 char inp_ch(void);
375 void expand(void);
376 char find_dn(void);
377 int sindex(int i, short t);
378 void fixconj(short *wrong, short *right);
379 char *fgetline(char *buf, int n, FILE *f);
380
381 /* --------- Addition by Marc Csernel 1998 --------- */
382
383 int citation;
384 int optchapter;
385 int linenumber;
386 int test_command(void);
387 char test_sub_com(void);
388 char comm_double_args(void);
389 char comm_special(void);
390 char comm_opt(void);
391 char comm_chapter(void);
392 char comm_cite(void);
393 char *getsubarg(void);
394 char comm_begin(void);
395 char ignore(void);
396
397 /* ------------------ End Addition ----------------- */
398
399 /*
400 * *** Struct declarations: major data types ***
401 */
402
403 /*
404 A struct of type char_def contains the following information about
405 any given character:
406
407 ch_typ: dn -- a character of the Devanagari syllabary
408 cmr -- a Roman character available within {\dn }
409 numeral -- self-evident: either Devanagari or ASCII as
410 specified
411 control -- special TeX character ("\", "{", "}", etc.)
412 illegal -- none of the above
413 ch_subtyp: consonant
414 lo_vowel (subscript)
415 hi_vowel ("regular" and superscript)
416 special -- none of the above
417 ch_code: For ch_typ dn only, gives the octal value of the
418 character's position in the dvng fonts. For vowels,
419 refers to the initial form (ch_subcode refers to
420 non-initial form); composite forms such as initial "o"
421 (= initial "a" + non-initial "o") have special values
422 greater than 257 decimal.
423 ch_subcode: Used for ch_typ dn only. For vowels, gives the octal
424 value of the non-initial form ("a" has the special value
425 257 decimal). For consonants, gives the index into
426 cons_table[] where the "half-form" of the consonant is
427 defined.
428 */
429 struct char_def {
430 short ch_typ, ch_subtyp, ch_code, ch_subcode;
431 };
432
433 /*
434 A struct of type cons_joins contains the following information about
435 any given consonant or consonant-group Ca:
436
437 n_ligs: The number of "simple" (two-member) ligatures listed in
438 lig_table[] for Ca.
439 lig_code: The index into lig_table[] of the first such ligature.
440 r_type: Has the value 0 if Ca takes the normal form of following "r"
441 (decimal 125) or if "Cra" is a predefined ligature; 1 if Ca
442 requires the "caret" form of following "r" (decimal 126);
443 2 if "Cra" is handled as "\qb{Ca}".
444 j_code: Gives the octal value of the "half-form" of Ca if one exists,
445 otherwise 0.
446 */
447 struct cons_joins {
448 short n_ligs, lig_code;
449 short r_type, j_code;
450 };
451
452 /*
453 A struct of type ligs contains the following information about any
454 given ligature:
455
456 sym_code: The index into char_table[] of the final member of the
457 ligature. May be expressed as as a character constant
458 (e.g. 't') or as a number (e.g. 6, referring to ".s").
459 sym_new: Gives either (a) the octal value of the ligature, or (b) a
460 negative number to be handled by expand(), which will reverse
461 the sign and subtract 1 (-5 becomes 4), and use the result as
462 an index into r_ligs[]. (This is done for "ktra", "gra",
463 ".dra", "dra", "dhra" and ".s.tra".)
464 join_idx: Gives the index into cons_table[] of the ligature, or 0.
465 in_use: Boolean TRUE or FALSE according to whether the ligature is
466 currently enabled (they are all initially enabled in
467 lig_table[], but may be disabled by e.g. @hindi).
468 */
469 struct ligs {
470 char sym_code;
471 short sym_new, join_idx;
472 unsigned char in_use;
473 };
474
475 /*
476 * *** Data structures used by devnag ***
477 */
478
479 /* Ligatures to be disabled by @hindi */
480 short nolig[] = {
481 2,3,6,7,16,25,27,34,35,39,40,46,47,49,56,58,59,62,65,
482 78,81,82,84,85,86,87,88,89,90,91,92,93,94,95,98,99,
483 100,101,105
484 };
485
486 /* Ligatures to be disabled by @modernhindi */
487 short modnolig[] = {
488 0,1,2,3,4,6,7,9,10,11,12,14,16,17,18,19,20,21,22,23,
489 24,25,26,27,28,29,30,31,32,33,34,35,36,39,40,41,42,43,
490 44,45,46,47,48,49,50,52,53,54,56,58,59,62,64,65,69,70,
491 71,72,73,74,75,76,77,78,80,81,82,84,85,86,87,88,89,90,91,
492 92,93,94,95,98,99,100,101,102,103,104,105,118,119
493 };
494
495 /*
496 * ligidxs[] maps the ligature-numbers that the user may specify
497 * with @lig and @nolig to the appropriate entries in lig_table[]
498 */
499 short ligidxs[] = {
500 0,1,2,3,4,6,7,9,11,12,13,14,118,16,17,18,19,20,21,22,
501 23,24,25,26,27,28,29,30,31,32,33,34,35,36,38,39,40,41,
502 42,43,44,45,46,47,48,49,50,52,53,119,54,55,56,58,59,60,
503 61,62,63,64,65,66,68,69,70,71,72,73,74,75,76,77,78,80,
504 81,82,84,85,86,87,88,89,90,91,92,93,94,95,96,98,99,100,
505 101,102,104,117,105,106,107,108,109,110,111,112,113
506 };
507
508 /*
509 * In the following character sets, final space is a dummy value
510 */
511 /* Characters that may be preceded by "." */
512 char chset1[] = {
513 'k','t','d','o','n','s','r','g',
514 'h','a','.','K','T','D','l','L','R','m',' '
515 };
516 /* Characters with a special meaning if preceded by "a" */
517 char chset2[] = {'a','i','u',' '};
518 /* Characters that may be preceded by '"' */
519 char chset3[] = {'n','s',' '};
520 /* Characters that may be followed by "h" */
521 char chset4[] = {'k','g','c','j','t','d','p','b','R',' '};
522 /* Replacements for chset2 characters when preceded by "a" */
523 char chset5[] = {'A','E','O'};
524 /* Characters that may be preceded by "~" */
525 char chset6[] = {'n','o','a','r','m',' '};
526
527 /*
528 * Private character set used internally by devnag -- basically
529 * ASCII, but with special characters allotted slots below 32:
530 * conversion from input representation done by dnproc().
531 */
532 struct char_def char_table[] = {
533 {illegal,special,0,0}, /* 1 not used */
534 {dn,consonant,'\126',34}, /* 2 .t */
535 {dn,consonant,'\130',36}, /* 3 .d */
536 {dn,special,'\72',0}, /* 4 .o */
537 {dn,consonant,'\132',1}, /* 5 .n */
538 {dn,consonant,'\161',2}, /* 6 .s */
539 {dn,lo_vowel,'\33',2}, /* 7 .r */
540 {dn,consonant,'\13',3}, /* 8 .g */
541 {dn,special,'\54',0}, /* 9 .h */
542 {dn,special,'\137',0}, /* 10 .a */
543 {dn,special,'\24',0}, /* 11 .. */
544 {dn,consonant,'\14',4}, /* 12 .K */
545 {dn,consonant,'\127',35}, /* 13 .T */
546 {dn,consonant,'\131',57}, /* 14 .D */
547 {dn,lo_vowel,'\30','\37'}, /* 15 .l */
548 {dn,lo_vowel,'\31','\174'}, /* 16 .L */
549 {dn,lo_vowel,'\21','\16'}, /* 17 .R */
550 {dn,consonant,'\122',32}, /* 18 "n */
551 {dn,consonant,'\146',5}, /* 19 "s */
552 {dn,consonant,'\170',0}, /* 20 Rh */
553 {dn,consonant,'\32',11}, /* 21 ~n */
554 {dn,hi_vowel,267,262}, /* 22 ~o */
555 {dn,hi_vowel,275,4}, /* 23 ~a */
556 {dn,consonant,'\35',31}, /* 24 ~r */
557 {illegal,special,0,0}, /* 25 not used */
558 {illegal,special,0,0}, /* 26 not used */
559 {illegal,special,0,0}, /* 27 not used */
560 {illegal,special,0,0}, /* 28 not used */
561 {illegal,special,0,0}, /* 29 not used */
562 {control,special,0,0}, /* 30 dummy */
563 {control,special,0,0}, /* 31 end_of_line */
564 {control,special,0,0}, /* 32 space */
565 {cmr,special,0,0}, /* ! */
566 {illegal,special,0,0}, /* " */
567 {dn,special,'\25',0}, /* # */
568 {illegal,special,0,0}, /* $ */
569 {control,special,0,0}, /* % */
570 {dn,special,0,0}, /* & */
571 {cmr,special,0,0}, /* ' to * */
572 {cmr,special,0,0}, /* ' to * */
573 {cmr,special,0,0}, /* ' to * */
574 {cmr,special,0,0}, /* ' to * */
575 {dn,special,0,0}, /* + */
576 /* Kevin Carmody:
577 * "+" changed
578 * from cmr
579 * to dn */
580 {cmr,special,0,0}, /* , to - */
581 {cmr,special,0,0}, /* , to - */
582 {illegal,special,0,0}, /* . */
583 {dn,special,'\40',0}, /* / */
584 {numeral,special,0,0}, /* 0 to 9 */
585 {numeral,special,0,0}, /* 0 to 9 */
586 {numeral,special,0,0}, /* 0 to 9 */
587 {numeral,special,0,0}, /* 0 to 9 */
588 {numeral,special,0,0}, /* 0 to 9 */
589 {numeral,special,0,0}, /* 0 to 9 */
590 {numeral,special,0,0}, /* 0 to 9 */
591 {numeral,special,0,0}, /* 0 to 9 */
592 {numeral,special,0,0}, /* 0 to 9 */
593 {numeral,special,0,0}, /* 0 to 9 */
594 {cmr,special,0,0}, /* : and ; */
595 {cmr,special,0,0}, /* : and ; */
596 {control,special,0,0}, /* < */
597 {cmr,special,0,0}, /* = */
598 {control,special,0,0}, /* > */
599 {cmr,special,0,0}, /* ? */
600 {dn,special,'\177',0}, /* @ */
601 {dn,hi_vowel,258,'\101'}, /* A */
602 {dn,consonant,'\102',6}, /* B */
603 {dn,consonant,'\103',33}, /* C */
604 {dn,consonant,'\104',7}, /* D */
605 {dn,hi_vowel,259,'\173'}, /* E */
606 {illegal,special,0,0}, /* F */
607 {dn,consonant,'\107',8}, /* G */
608 {dn,special,'\54',0}, /* H */
609 {dn,hi_vowel,'\111','\106'}, /* I */
610 {dn,consonant,'\112',9}, /* J */
611 {dn,consonant,'\113',10}, /* K */
612 {dn,consonant,'\17',30}, /* L */
613 {dn,special,'\134',0}, /* M */
614 {illegal,special,0,0}, /* N */
615 {dn,hi_vowel,260,'\117'}, /* O */
616 {dn,consonant,'\120',12}, /* P */
617 {illegal,special,0,0}, /* Q */
618 {dn,consonant,'\167',0}, /* R */
619 {illegal,special,0,0}, /* S */
620 {dn,consonant,'\124',13}, /* T */
621 {dn,lo_vowel,'\125',1}, /* U */
622 {illegal,special,0,0}, /* V to Z */
623 {illegal,special,0,0}, /* V to Z */
624 {illegal,special,0,0}, /* V to Z */
625 {illegal,special,0,0}, /* V to Z */
626 {illegal,special,0,0}, /* V to Z */
627 {cmr,special,0,0}, /* [ */
628 {control,special,0,0}, /* \ */
629 {cmr,special,0,0}, /* ] */
630 {illegal,special,0,0}, /* ^ */
631 {dn,special,0,0}, /* _ */
632 /* Marc Csernel:
633 * "_" changed
634 * from illegal
635 * to dn */
636 {cmr,special,0,0}, /* ` */
637 {dn,hi_vowel,'\141',257}, /* a */
638 {dn,consonant,'\142',14}, /* b */
639 {dn,consonant,'\143',15}, /* c */
640 {dn,consonant,'\144',37}, /* d */
641 {dn,hi_vowel,'\145',3}, /* e */
642 {dn,consonant,'\47',16}, /* f */
643 {dn,consonant,'\147',17}, /* g */
644 {dn,consonant,'\150',38}, /* h */
645 {dn,hi_vowel,'\151','\105'}, /* i */
646 {dn,consonant,'\152',18}, /* j */
647 {dn,consonant,'\153',19}, /* k */
648 {dn,consonant,'\154',20}, /* l */
649 {dn,consonant,'\155',21}, /* m */
650 {dn,consonant,'\156',22}, /* n */
651 {dn,hi_vowel,261,'\157'}, /* o */
652 {dn,consonant,'\160',23}, /* p */
653 {dn,consonant,'\52',24}, /* q */
654 {dn,consonant,'\162',0}, /* r */
655 {dn,consonant,'\163',25}, /* s */
656 {dn,consonant,'\164',26}, /* t */
657 {dn,lo_vowel,'\165',0}, /* u */
658 {dn,consonant,'\166',27}, /* v */
659 {illegal,special,0,0}, /* not used */
660 {illegal,special,0,0}, /* not used */
661 {dn,consonant,'\171',28}, /* y */
662 {dn,consonant,'\51',29}, /* z */
663 {control,special,0,0}, /* left brace */
664 {dn,special,'\56',0}, /* | */
665 {control,special,0,0}, /* right brace */
666 {illegal,special,0,0}, /* ~ */
667 {illegal,special,0,0} /* del */
668 };
669
670 /*
671 * Unordered table of consonants and consonant-groups giving
672 * information on the available ligatures, the form taken by a
673 * following "r", and the location in the dvng fonts of the
674 * "half-form" (if any)
675 */
676 struct cons_joins cons_table[] = {
677 {0,0,1,0}, /* 0 */
678 {1,120,0,'\27'}, /* 1 .n */
679 {2,100,0,'\11'}, /* 2 .s */
680 {0,0,0,'\34'}, /* 3 .g */
681 {0,0,1,'\7'}, /* 4 .k */
682 {6,94,0,'\133'}, /* 5 "s */
683 {1,88,0,'\74'}, /* 6 B */
684 {2,78,0,'\100'}, /* 7 D */
685 {1,16,0,'\135'}, /* 8 G */
686 {0,0,1,'\44'}, /* 9 J */
687 {0,0,1,'\110'}, /* 10 K */
688 {2,39,1,'\26'}, /* 11 ~n */
689 {1,115,0,'\45'}, /* 12 P */
690 {0,0,0,'\114'}, /* 13 T */
691 {3,85,0,'\116'}, /* 14 b */
692 {2,34,0,'\121'}, /* 15 c */
693 {1,116,0,'\10'}, /* 16 f */
694 {1,15,0,'\140'}, /* 17 g */
695 {2,37,0,'\76'}, /* 18 j */
696 {9,0,0,'\77'}, /* 19 k */
697 {1,91,0,'\123'}, /* 20 l */
698 {2,89,0,'\115'}, /* 21 m */
699 {1,80,0,'\6'}, /* 22 n */
700 {4,81,0,'\75'}, /* 23 p */
701 {0,0,1,'\12'}, /* 24 q */
702 {2,105,0,'\55'}, /* 25 s */
703 {3,55,0,'\50'}, /* 26 t */
704 {2,92,0,'\46'}, /* 27 v */
705 {0,0,1,'\5'}, /* 28 y */
706 {1,114,0,'\36'}, /* 29 z */
707 {0,0,1,'\20'}, /* 30 L */
708 {0,0,1,'\35'}, /* 31 ~r */
709 {8,17,1,0}, /* 32 "n */
710 {1,36,1,0}, /* 33 C */
711 {4,41,1,0}, /* 34 .t */
712 {1,45,1,0}, /* 35 .th */
713 {6,46,1,0}, /* 36 .d */
714 {11,58,2,0}, /* 37 d */
715 {7,107,1,0}, /* 38 h */
716 {3,9,1,0}, /* 39 k t */
717 {1,14,1,0}, /* 40 k v */
718 {3,25,1,0}, /* 41 "n k */
719 {1,28,1,0}, /* 42 "n kh */
720 {1,29,1,0}, /* 43 "n g */
721 {2,30,1,0}, /* 44 "n gh */
722 {1,32,1,0}, /* 45 "n k t */
723 {1,33,1,0}, /* 46 "n k .s */
724 {1,52,1,0}, /* 47 .d g */
725 {1,53,1,0}, /* 48 .d gh */
726 {2,71,2,0}, /* 49 d d */
727 {2,73,2,0}, /* 50 d dh */
728 {1,75,1,0}, /* 51 d bh */
729 {1,77,2,0}, /* 52 d v */
730 {3,102,1,0}, /* 53 .s .t */
731 {0,0,1,'\43'}, /* 54 k .s */
732 {0,0,1,0202}, /* 55 t t */
733 {1,117,1,0}, /* 56 .s .t r */
734 {1,54,1,0}, /* 57 .dh */
735 {1,12,1,0}, /* 58 k n */
736 {1,13,1,0}, /* 59 k r */
737 {0,0,1,0351}, /* 60 g r */
738 {0,0,1,0350}, /* 61 gh n */
739 {0,0,1,0352}, /* 62 j ~n */
740 {0,0,1,0353}, /* 63 ~n c */
741 {0,0,1,0354}, /* 64 t r */
742 {1,69,1,0}, /* 65 d g */
743 {1,70,1,0}, /* 66 d gh */
744 {0,0,1,0361}, /* 67 dh n */
745 {0,0,1,0362}, /* 68 dh r */
746 {0,0,1,0363}, /* 69 p t */
747 {0,0,1,0364}, /* 70 "s c */
748 {0,0,1,0365}, /* 71 "s r */
749 {0,0,1,0366}, /* 72 "s v */
750 {1,118,1,0}, /* 73 k t r */
751 {1,119,1,0}, /* 74 .d r */
752 {1,76,1,0}, /* 75 d r */
753 {0,0,2,0} /* 76 d b */
754 };
755
756 /*
757 * Ordered table of available ligatures giving each ligature's
758 * position in the dvng fonts (or a negative number for use by
759 * expand()) and index into cons_table[]
760 *
761 * Note that lig_table[96] is an entry for a ligature that was
762 * removed from the fonts as of release 2.1. It is therefore
763 * marked as (permanently) FALSE; it has not been removed from
764 * the table since to do so would change the index values of all
765 * succeeding entries, and these occur frequently in the code.
766 */
767 struct ligs lig_table[] = {
768 {'k',0303,0,TRUE}, /* 0 k k */
769 {'t',0304,39,TRUE}, /* 1 k t */
770 {'n',0307,58,TRUE}, /* 2 k n */
771 {'m',0311,0,TRUE}, /* 3 k m */
772 {'y',0310,0,TRUE}, /* 4 k y */
773 {'r',0207,59,TRUE}, /* 5 k r */
774 {'l',0312,0,TRUE}, /* 6 k l */
775 {'v',0313,40,TRUE}, /* 7 k v */
776 {6,042,54,TRUE}, /* 8 k .s */
777 {'y',0305,0,TRUE}, /* 9 k t y */
778 {'r',-5,73,TRUE}, /* 10 k t r */
779 {'v',0306,0,TRUE}, /* 11 k t v */
780 {'y',0346,0,TRUE}, /* 12 k n y */
781 {'y',0347,0,TRUE}, /* 13 k r y */
782 {'y',0314,0,TRUE}, /* 14 k v y */
783 {'r',-2,60,TRUE}, /* 15 g r */
784 {'n',0315,61,TRUE}, /* 16 gh n */
785 {'k',0254,41,TRUE}, /* 17 "n k */
786 {'K',0262,42,TRUE}, /* 18 "n kh */
787 {'g',0275,43,TRUE}, /* 19 "n g */
788 {'G',0277,44,TRUE}, /* 20 "n gh */
789 {18,0274,0,TRUE}, /* 21 "n "n */
790 {'n',0265,0,TRUE}, /* 22 "n n */
791 {'m',0301,0,TRUE}, /* 23 "n m */
792 {'y',0302,0,TRUE}, /* 24 "n y */
793 {'t',0255,45,TRUE}, /* 25 "n k t */
794 {'y',0257,0,TRUE}, /* 26 "n k y */
795 {6,0260,46,TRUE}, /* 27 "n k .s */
796 {'y',0272,0,TRUE}, /* 28 "n kh y */
797 {'y',0276,0,TRUE}, /* 29 "n g y */
798 {'y',0271,0,TRUE}, /* 30 "n gh y */
799 {'r',0300,0,TRUE}, /* 31 "n gh r */
800 {'y',0256,0,TRUE}, /* 32 "n k t y */
801 {'v',0261,0,TRUE}, /* 33 "n k .s v */
802 {'c',0316,0,TRUE}, /* 34 c c */
803 {21,0317,0,TRUE}, /* 35 c ~n */
804 {'y',0320,0,TRUE}, /* 36 ch y */
805 {21,0342,62,TRUE}, /* 37 j ~n */
806 {'r',0205,0,TRUE}, /* 38 j r */
807 {'c',0321,63,TRUE}, /* 39 ~n c */
808 {'j',0322,0,TRUE}, /* 40 ~n j */
809 {'k',0326,0,TRUE}, /* 41 .t k */
810 {2,0323,0,TRUE}, /* 42 .t .t */
811 {13,0341,0,TRUE}, /* 43 .t .th */
812 {'y',0324,0,TRUE}, /* 44 .t y */
813 {'y',0325,0,TRUE}, /* 45 .th y */
814 {'g',0263,47,TRUE}, /* 46 .d g */
815 {'G',0264,48,TRUE}, /* 47 .d gh */
816 {3,0345,0,TRUE}, /* 48 .d .d */
817 {'m',0273,0,TRUE}, /* 49 .d m */
818 {'y',0267,0,TRUE}, /* 50 .d y */
819 {'r',-6,74,TRUE}, /* 51 .d r */
820 {'y',0270,0,TRUE}, /* 52 .d g y */
821 {'r',0266,0,TRUE}, /* 53 .d gh r */
822 {'y',0344,0,TRUE}, /* 54 .dh y */
823 {'t',0201,55,TRUE}, /* 55 t t */
824 {'n',0327,0,TRUE}, /* 56 t n */
825 {'r',057,64,TRUE}, /* 57 t r */
826 {'g',0213,65,TRUE}, /* 58 d g */
827 {'G',0212,66,TRUE}, /* 59 d gh */
828 {'d',0214,49,TRUE}, /* 60 d d */
829 {'D',0210,50,TRUE}, /* 61 d dh */
830 {'n',0221,0,TRUE}, /* 62 d n */
831 {'b',0223,76,TRUE}, /* 63 d b */
832 {'B',0211,51,TRUE}, /* 64 d bh */
833 {'m',0224,0,TRUE}, /* 65 d m */
834 {'y',0215,0,TRUE}, /* 66 d y */
835 {'r',-3,75,TRUE}, /* 67 d r */
836 {'v',0222,52,TRUE}, /* 68 d v */
837 {'r',0355,0,TRUE}, /* 69 d g r */
838 {'r',0356,0,TRUE}, /* 70 d gh r */
839 {'y',0220,0,TRUE}, /* 71 d d y */
840 {'v',0370,76,TRUE}, /* 72 d d v */
841 {'y',0217,0,TRUE}, /* 73 d dh y */
842 {'v',0371,0,TRUE}, /* 74 d dh v */
843 {'y',0216,0,TRUE}, /* 75 d bh y */
844 {'y',0357,0,TRUE}, /* 76 d r y */
845 {'y',0225,0,TRUE}, /* 77 d v y */
846 {'n',0360,67,TRUE}, /* 78 dh n */
847 {'r',-4,68,TRUE}, /* 79 dh r */
848 {'n',0340,0,TRUE}, /* 80 n n */
849 {'t',0330,69,TRUE}, /* 81 p t */
850 {'n',0331,0,TRUE}, /* 82 p n */
851 {'r',0376,0,TRUE}, /* 83 p r */
852 {'l',0332,0,TRUE}, /* 84 p l */
853 {'n',0247,0,TRUE}, /* 85 b n */
854 {'b',0251,0,TRUE}, /* 86 b b */
855 {'v',0333,0,TRUE}, /* 87 b v */
856 {'n',0336,0,TRUE}, /* 88 bh n */
857 {'n',0337,0,TRUE}, /* 89 m n */
858 {'l',0335,0,TRUE}, /* 90 m l */
859 {'l',0245,0,TRUE}, /* 91 l l */
860 {'n',0246,0,TRUE}, /* 92 v n */
861 {'v',0250,0,TRUE}, /* 93 v v */
862 {'c',0226,70,TRUE}, /* 94 "s c */
863 {'n',0227,0,TRUE}, /* 95 "s n */
864 {'b',0233,0,FALSE}, /* 96 "s b */
865 {'r',0231,71,TRUE}, /* 97 "s r */
866 {'l',0232,0,TRUE}, /* 98 "s l */
867 {'v',0230,72,TRUE}, /* 99 "s v */
868 {2,0243,53,TRUE}, /* 100 .s .t */
869 {13,0244,0,TRUE}, /* 101 .s .th */
870 {'y',0367,0,TRUE}, /* 102 .s .t y */
871 {'r',-1,56,TRUE}, /* 103 .s .t r */
872 {'v',0253,0,TRUE}, /* 104 .s .t v */
873 {'n',0334,0,TRUE}, /* 105 s n */
874 {'r',0372,0,TRUE}, /* 106 s r */
875 {5,0242,0,TRUE}, /* 107 h .n */
876 {'n',0241,0,TRUE}, /* 108 h n */
877 {'m',0234,0,TRUE}, /* 109 h m */
878 {'y',0235,0,TRUE}, /* 110 h y */
879 {'r',0240,0,TRUE}, /* 111 h r */
880 {'l',0236,0,TRUE}, /* 112 h l */
881 {'v',0237,0,TRUE}, /* 113 h v */
882 {'r',0206,0,TRUE}, /* 114 z r */
883 {'r',0203,0,TRUE}, /* 115 ph r */
884 {'r',0204,0,TRUE}, /* 116 f r */
885 {'y',0252,0,TRUE}, /* 117 .s .t r y */
886 {'y',0374,0,TRUE}, /* 118 k t r y */
887 {'y',0373,0,TRUE}, /* 119 .d r y */
888 {5,0233,0,TRUE} /* 120 .n .n */
889 };
890
891 /*
892 * Table of the actual codes output by devnag
893 */
894 const char *out_string[] = {
895 "\\7{","\\8{","\\9{","\\?","\\<","\\305w","\\306w", /* 0-6 */
896 "\\307w","\\308w","\\309w","\\30Aw","\\30Bw","\\30Cw", /* 7-12 */
897 "\\0","\\qx{","\\30Fw","\\310w","\\311w","\\312w", /* 13-18 */
898 "\\313w","\\314w","\\315w","\\316w","\\317w","\\318w", /* 19-24 */
899 "\\319w","\\31Aw","\\31Bw","\\31Cw","\\31Dw", /* 25-29 */
900 "\\31Ew","\\qy{","\\1","!","\\322w","\\323w","\\324w", /* 30-36 */
901 "\\325w","\\326w","\\327w","(",")","\\32Aw","+",",", /* 37-44 */
902 "-",".","/","0","1","2","3","4","5","6","7","8","9", /* 45-57 */
903 ":",";","<","=",">","?","@", /* 58-64 */
904 "A","B","C","D","E","F","G","H","I","J","K","L","M", /* 65-77 */
905 "N","O","P","Q","R","S","T","U","V","W","X","Y","Z", /* 78-90 */
906 "\\35Bw","\\2","\\35Dw","\\qq{","\\35Fw","`", /* 91-96 */
907 "a","b","c","d","e","f","g","h","i","j","k","l","m", /* 97-109 */
908 "n","o","p","q","r","s","t","u","v","w","x","y","z", /* 110-122 */
909 "\\4","\\qz{","\\5","\\6{","\\37Fw", /* 123-127 */
910 "\\380w","\\381w","\\382w","\\383w","\\384w","\\385w", /* 128-133 */
911 "\\386w","\\387w","\\388w","\\389w","\\38Aw","\\38Bw", /* 134-139 */
912 "\\38Cw","\\38Dw","\\38Ew","\\38Fw","\\390w","\\391w", /* 140-145 */
913 "\\392w","\\393w","\\394w","\\395w","\\396w","\\397w", /* 146-151 */
914 "\\398w","\\399w","\\39Aw","\\39Bw","\\39Cw","\\39Dw", /* 152-157 */
915 "\\39Ew","\\39Fw","\\3A0w","\\3A1w","\\3A2w","\\3A3w", /* 158-163 */
916 "\\3A4w","\\3A5w","\\3A6w","\\3A7w","\\3A8w","\\3A9w", /* 164-169 */
917 "\\3AAw","\\3ABw","\\3ACw","\\3ADw","\\3AEw","\\3AFw", /* 170-175 */
918 "\\3B0w","\\3B1w","\\3B2w","\\3B3w","\\3B4w","\\3B5w", /* 176-181 */
919 "\\3B6w","\\3B7w","\\3B8w","\\3B9w","\\3BAw","\\3BBw", /* 182-187 */
920 "\\3BCw","\\3BDw","\\3BEw","\\3BFw","\\3C0w","\\3C1w", /* 188-193 */
921 "\\3C2w","\\3C3w","\\3C4w","\\3C5w","\\3C6w","\\3C7w", /* 194-199 */
922 "\\3C8w","\\3C9w","\\3CAw","\\3CBw","\\3CCw","\\3CDw", /* 200-205 */
923 "\\3CEw","\\3CFw","\\3D0w","\\3D1w","\\3D2w","\\3D3w", /* 206-211 */
924 "\\3D4w","\\3D5w","\\3D6w","\\3D7w","\\3D8w","\\3D9w", /* 212-217 */
925 "\\3DAw","\\3DBw","\\3DCw","\\3DDw","\\3DEw","\\3DFw", /* 218-223 */
926 "\\3E0w","\\3E1w","\\3E2w","\\3E3w","\\3E4w","\\3E5w", /* 224-229 */
927 "\\3E6w","\\3E7w","\\3E8w","\\3E9w","\\3EAw","\\3EBw", /* 230-235 */
928 "\\3ECw","\\3EDw","\\3EEw","\\3EFw","\\3F0w","\\3F1w", /* 236-241 */
929 "\\3F2w","\\3F3w","\\3F4w","\\3F5w","\\3F6w","\\3F7w", /* 242-247 */
930 "\\3F8w","\\3F9w","\\3FAw","\\3FBw","\\3FCw","\\3FDw", /* 248-253 */
931 "\\3FEw","\\3FFw", /* 254-255 */
932 "{\\rs ","","aA","e\\?","aO","ao","A\\<","\\re}","}", /* 256-264 */
933 "\\rn{","{\\rdt}","aA\\<","{\\qva}","{\\qvb}","{\\qvc}", /* 265-270 */
934 "\\qa{","\\qb{","{","\\qc{","a\\<" /* 271-275 */
935 };
936
937 /*
938 * Table specifying the form of following "r" for various consonants
939 * and consonant-groups (used by expand())
940 */
941 short r_ligs[6][2] = {
942 {0243,1}, /* .s .t */
943 {0147,0}, /* g */
944 {0144,2}, /* d */
945 {0104,0}, /* dh */
946 {0304,1}, /* k t */
947 {0130,1} /* .d */
948 };
949
950 /* --------- Addition by Marc Csernel 1998 --------- */
951
952 /* The array contains a list of LaTeX commands preceded by a code:
953
954 1 a mandatory argument follows. e.g. \end{enumerate}
955 2 the text inclosed by a preceding brace must not be translated
956 till next closing brace.
957 3 two mandatory arguments follow. e.g. \multicolumn{nb}{desc}{text}
958 4 For begin: a mandatory argument followed by zero, or one optional,
959 depending on the first one e.g. \begin{itemize} or
960 \begin{tabular}{....}
961 5 a mandatory argument and optional ones which must not be translated.
962 \raisebox{raise}[ht][prof]{text to be translated}
963 6 one or more optional argument(s) which must not be translated and
964 a mandatory one which must be translated e.g.
965 \framebox[6cm][s]{text to be translated}
966 7 The command cite: an optional argument which must be translated
967 and a mandatory one which mustn't.
968 8 Commands like chapter, section... with optional argument which
969 must be translated and a mandatory one which must also be
970 translated.
971
972 */
973
974 typedef struct {
975 int Typ_Com;
976 const char *Name_com;
977 } typcom;
978
979 typcom TabCom[] = {
980 {4,"begin"},
981 {1,"end"},
982 {1,"label"},
983 {1,"pageref"},
984 {1,"ref"},
985 {1,"index"},
986 {1,"hspace"},
987 {1,"hspace*"},
988 {1,"vspace"},
989 {1,"vspace*"},
990 {1,"addvspace"},
991 {1,"enlargethispage"},
992 {1,"enlargethispage*"},
993 {1,"include"},
994 {1,"input"},
995 {1,"parbox"},
996 {1,"stepcounter"},
997 {1,"refstepcounter"},
998 {1,"bibitem"},
999 {1,"cline"},
1000 {2,"rm"},
1001 {2,"kern"},
1002 {2,"hskip"},
1003 {2,"vskip"},
1004 {2,"vadjust"},
1005 {3,"addtolength"},
1006 {3,"setlength"},
1007 {3,"setcounter"},
1008 {3,"addtocounter"},
1009 {3,"multicolumn"},
1010 {3,"rule"},
1011 {3,"addcontentsline"},
1012 {5,"raisebox"},
1013 {6,"framebox"},
1014 {6,"makebox"},
1015 {7,"cite"},
1016 {8,"chapter"},
1017 {8,"section"},
1018 {8,"subsection"},
1019 {8,"subsubsection"},
1020 {8,"paragraph"},
1021 {8,"subparagraph"},
1022 {8,"part"},
1023 {0,""}
1024 };
1025
1026 /*
1027 For the command begin, depending on the first argument we will
1028 have zero (default), 1, 2.. other arguments following. Within
1029 the following array the first element of an item describes the
1030 number of arguments, the second one the name of the first
1031 argument related with i.e
1032
1033 \begin {tabular}
1034
1035 will have 1 argument.
1036 */
1037 typcom TabSubCom[]= {
1038 {1,"tabular"},
1039 {1,"supertabular"},
1040 {1,"longtable"},
1041 {1,"thebibliography"},
1042 {0,""}
1043 };
1044
1045 char command[100]; /* the text of a current command to test */
1046 int nbchcomm; /* the number of character of the curent command */
1047 char subcom [1000]; /* for debugging etc. */
1048
1049 /*
1050 This fuction tests if the LaTeX command is one of the TabCom[]
1051 array. In this case the code (Typ_Com) is returned.
1052 */
test_command(void)1053 int test_command(void) {
1054 int i = 0;
1055 while (TabCom[i].Name_com[0] != 0) {
1056 if (!strcmp(command,TabCom[i++].Name_com)) return TabCom[i-1].Typ_Com;
1057 }
1058 return 0;
1059 }
1060
1061 /*
1062 This routine writes down all characters it finds; it looks
1063 for a '{' followed by some text and a '}'; no nesting of braces
1064 is considered.
1065 */
test_sub_com(void)1066 char test_sub_com(void) {
1067 int nbsub = 0;
1068 while (symbol != '}') {
1069 sendchar(symbol);
1070 subcom[nbsub++] = symbol;
1071 subcom[nbsub] = 0;
1072 symbol = inp_ch();
1073 }
1074 sendchar(symbol);
1075 subcom[nbsub++] = symbol;
1076 subcom[nbsub] = 0;
1077 symbol = inp_ch();
1078 return symbol;
1079 }
1080
1081 /*
1082 This routine writes down all characters it finds; it looks
1083 twice for a '{' followed by some text and a '}'; for the
1084 second time nesting of braces is considered.
1085 */
comm_double_args(void)1086 char comm_double_args(void) {
1087 int nbsub = 0;
1088 while (symbol != '}') {
1089 sendchar(symbol);
1090 subcom[nbsub++] = symbol;
1091 subcom[nbsub] = 0;
1092 symbol = inp_ch();
1093 }
1094 /* looking for the end of the second argument */
1095 sendchar(symbol);
1096 symbol = inp_ch();
1097 while (symbol != '{') {
1098 sendchar(symbol);
1099 symbol = inp_ch();
1100 }
1101 sendchar(symbol);
1102 symbol = inp_ch();
1103 symbol = ignore();
1104 sendchar(symbol);
1105 symbol = inp_ch();
1106 return symbol;
1107 }
1108
1109 /*
1110 For LaTeX commands such as \raisebox{5pt}[10pt][25pt]{.sa.t&vidha.m}
1111 where the second argument must be translated
1112 */
comm_special(void)1113 char comm_special(void) {
1114 int nbsub = 0;
1115 while (symbol != '}') {
1116 sendchar(symbol);
1117 subcom[nbsub++] = symbol;
1118 subcom[nbsub] = 0;
1119 symbol = inp_ch();
1120 }
1121 while (symbol != '{') {
1122 sendchar(symbol);
1123 subcom[nbsub++] = symbol;
1124 subcom[nbsub] = 0;
1125 symbol = inp_ch();
1126 }
1127 return symbol;
1128 }
1129
1130 /*
1131 For LaTeX commands such as \framebox[10pt][25pt]{.sa.t&vidha.m}
1132 where optional arguments are not translated and the mandatory
1133 one must be translated
1134 */
comm_opt(void)1135 char comm_opt(void) {
1136 int nbsub = 0;
1137 while (symbol != '{') {
1138 sendchar(symbol);
1139 subcom[nbsub++] = symbol;
1140 subcom[nbsub] = 0;
1141 symbol = inp_ch();
1142 }
1143 return symbol;
1144 }
1145
comm_chapter(void)1146 char comm_chapter(void) {
1147 if (symbol == '[') {
1148 optchapter = 1;
1149 sendchar(symbol);
1150 symbol=inp_ch();
1151 }
1152 if (symbol == '*') {
1153 sendchar(symbol);
1154 symbol=inp_ch();
1155 }
1156 return symbol;
1157 }
1158
comm_cite(void)1159 char comm_cite(void) {
1160 if (symbol == '[') {
1161 citation = 1;
1162 sendchar(symbol);
1163 symbol = inp_ch();
1164 }
1165 else test_sub_com();
1166 return symbol;
1167 }
1168
getsubarg(void)1169 char *getsubarg(void) {
1170 char com[20], *result;
1171 int i = 0, j = 0;
1172 while (subcom[i] != '{') i++;
1173 i++;
1174 while (subcom[i] == ' ') i++;
1175 while (isalpha((unsigned char)subcom[i])) com[j++]= subcom[i++];
1176 com[j] = 0;
1177 i = 0;
1178 result = (char*) malloc (strlen(com)+1);
1179 strcpy (result,com);
1180 return result;
1181 }
1182
1183 /*
1184 The LaTeX command BEGIN treatment
1185 */
comm_begin(void)1186 char comm_begin(void) {
1187 int i = 0, nbargs = 0;
1188 char *com;
1189 int nbsub = 0;
1190 while (symbol != '}') {
1191 sendchar(symbol);
1192 subcom[nbsub++] = symbol;
1193 subcom[nbsub] = 0;
1194 symbol = inp_ch();
1195 }
1196 sendchar(symbol);
1197 symbol = inp_ch();
1198 com = getsubarg();
1199 while (TabSubCom[i].Name_com[0] != 0) {
1200 if (!strcmp(com,TabSubCom[i++].Name_com))
1201 nbargs = TabSubCom[i-1].Typ_Com;
1202 }
1203 if (!nbargs) { /* argument not found within the table */
1204 free(com);
1205 return symbol;
1206 }
1207 while (nbargs--) {
1208 while (symbol != '{') {
1209 sendchar(symbol);
1210 subcom[nbsub++] = symbol;
1211 subcom[nbsub] = 0;
1212 symbol = inp_ch();
1213 }
1214 sendchar(symbol);
1215 symbol = inp_ch();
1216 symbol = ignore ();
1217 }
1218 sendchar(symbol);
1219 symbol = inp_ch();
1220 free(com);
1221 return symbol;
1222 }
1223
1224 /*
1225 This routine assumes that a '{' has already been read; it
1226 looks for the corresponding closing brace '}'; nesting of
1227 braces is considered.
1228 */
ignore(void)1229 char ignore(void) {
1230 int nbsub = 0;
1231 int nbbraces = 1;
1232 while (nbbraces ) {
1233 subcom[nbsub++] = symbol;
1234 subcom[nbsub] = 0;
1235 switch (symbol) {
1236 case '{':
1237 nbbraces++;
1238 sendchar(symbol);
1239 break;
1240 case '}':
1241 nbbraces--;
1242 if (!nbbraces) return symbol;
1243 sendchar(symbol);
1244 break;
1245 case ' ':
1246 case '\n':
1247 sendchar(symbol);
1248 put_word();
1249 break;
1250 default :
1251 sendchar(symbol);
1252 break;
1253 }
1254 symbol = inp_ch();
1255 }
1256 return symbol ;
1257 }
1258
1259 /* ------------------ End Addition ----------------- */
1260
1261 /*
1262 * *** Devnag function definitions ***
1263 */
1264
main(int argc,char ** argv)1265 int main(int argc, char **argv) {
1266 char *s_ptr;
1267 int i;
1268 unsigned char dn_yes, start_file;
1269
1270 /* if invoked with "-v", print banner and exit */
1271
1272 if ((argc == 2) && (strcmp(argv[1], "-v") == 0)) {
1273 printf("devnag v%s\n", version);
1274 puts(banner);
1275 exit(0);
1276 }
1277
1278 /* get file specifications */
1279
1280 if (argc == 3) {
1281 strcpy(infil, argv[1]);
1282 strcpy(outfil, argv[2]);
1283 }
1284 else {
1285 if (argc == 2) {
1286 strcpy(infil, argv[1]);
1287 *outfil = '\0';
1288 }
1289 else {
1290 do {
1291 printf("input file: ");
1292 fgets(infil, MEDBUF, stdin);
1293 infil[strlen(infil)-1] = '\0';
1294 } while (strlen(infil) == 0);
1295 printf("output file: ");
1296 fgets(outfil, MEDBUF, stdin);
1297 outfil[strlen(outfil)-1] = '\0';
1298 }
1299 }
1300 /* Check the source file extension */
1301 if (strcasecmp(infil+strlen(infil)-strlen(DEFAULT_DEST_EXT), DEFAULT_DEST_EXT) == 0) {
1302 fprintf(stderr, "source file extension %s is forbidden\n", DEFAULT_DEST_EXT);
1303 exit(1);
1304 }
1305 s_ptr = infil+strlen(infil)-strlen(DEFAULT_SRC_EXT);
1306 if (strcasecmp(s_ptr, DEFAULT_SRC_EXT) != 0) s_ptr = NULL;
1307 if (!s_ptr) strcat(infil, DEFAULT_SRC_EXT);
1308
1309 /* Try to open the source file */
1310 f_in = fopen(infil, "rb");
1311 if (!f_in && !s_ptr) {
1312 /* strip extension which has not been supplied and try again */
1313 infil[strlen(infil)-strlen(DEFAULT_SRC_EXT)] = '\0';
1314 f_in = fopen(infil, "rb");
1315 }
1316 if (!f_in) {
1317 if (s_ptr) fprintf(stderr, "cannot open file %s\n", infil);
1318 else fprintf(stderr, "cannot open either %s or %s%s\n", infil, infil, DEFAULT_SRC_EXT);
1319 exit(1);
1320 }
1321
1322 /* Destination file name */
1323 if (strlen(outfil) == 0) {
1324 strcpy(outfil, infil);
1325 if (strcasecmp(outfil+strlen(outfil)-strlen(DEFAULT_SRC_EXT), DEFAULT_SRC_EXT) == 0) {
1326 outfil[strlen(outfil)-strlen(DEFAULT_SRC_EXT)] = '\0';
1327 }
1328 strcat(outfil, DEFAULT_DEST_EXT);
1329 } else {
1330 if (strcasecmp(outfil+strlen(outfil)-strlen(DEFAULT_SRC_EXT), DEFAULT_SRC_EXT) == 0) {
1331 fclose(f_in);
1332 fprintf(stderr, "destination file extension %s is forbidden\n", DEFAULT_SRC_EXT);
1333 exit(1);
1334 }
1335 if (strcasecmp(infil, outfil) == 0) strcat(outfil, DEFAULT_DEST_EXT);
1336 }
1337 #ifdef TEXLIVE
1338 /* In TeX Live we want to share files between Unix and Windows systems. */
1339 #define FOPEN_W_MODE "wb"
1340 #else
1341 #define FOPEN_W_MODE "w"
1342 #endif
1343 if ((f_out = fopen(outfil, FOPEN_W_MODE)) == NULL) {
1344 fclose(f_in);
1345 fprintf(stderr, "cannot open %s for output\n", outfil);
1346 exit(1);
1347 }
1348
1349 /* initialization */
1350
1351 cons_seen = FALSE;
1352 vow_seen = FALSE;
1353 front_r = FALSE;
1354 wait_syll = FALSE;
1355 cmr_mode = FALSE;
1356 num_mode = FALSE;
1357 hindi_mode = FALSE;
1358 mhindi_mode = FALSE;
1359 dollar_mode = 0;
1360 do_hyphen = FALSE;
1361 do_vconjuncts = FALSE;
1362 tabs_mode = FALSE; /* Marc Csernel */
1363 lig_block = FALSE; /* Kevin Carmody */
1364 start_file = TRUE;
1365
1366 chr_idx = 0;
1367 n_halves = 0; /* Kevin Carmody */
1368 *word = '\0';
1369 *inbuf = '\0';
1370 *outbuf = '\0';
1371 linenumber = 1;
1372
1373
1374 /* main loop */
1375
1376 do {
1377 p_in = fgetline(inbuf, MAXBUF, f_in);
1378 if (start_file) {
1379 if (inbuf[0] != '%' || inbuf[1] != '&') {
1380 fprintf(f_out, "\\def\\DevnagVersion{%s}", version);
1381 start_file = FALSE;
1382 }
1383 }
1384
1385 /* read preprocessor commands */
1386
1387 if (*inbuf == '@') {
1388 while (TRUE) {
1389 if (strstr(inbuf, "dollars\n") == inbuf+1) {
1390 dollar_mode = 1;
1391 fprintf(f_out, "%%%s", inbuf);
1392 linenumber++;
1393 break;
1394 }
1395 if (strstr(inbuf, "nodollars\n") == inbuf+1) {
1396 dollar_mode = 0;
1397 fprintf(f_out, "%%%s", inbuf);
1398 linenumber++;
1399 break;
1400 }
1401 if (strstr(inbuf, "dolmode0\n") == inbuf+1) {
1402 dollar_mode = 0;
1403 fprintf(f_out, "%%%s", inbuf);
1404 linenumber++;
1405 break;
1406 }
1407 if (strstr(inbuf, "dolmode1\n") == inbuf+1) {
1408 dollar_mode = 1;
1409 fprintf(f_out, "%%%s", inbuf);
1410 linenumber++;
1411 break;
1412 }
1413 if (strstr(inbuf, "dolmode2\n") == inbuf+1) {
1414 dollar_mode = 2;
1415 fprintf(f_out, "%%%s", inbuf);
1416 linenumber++;
1417 break;
1418 }
1419 if (strstr(inbuf, "dolmode3\n") == inbuf+1) {
1420 dollar_mode = 3;
1421 fprintf(f_out, "%%%s", inbuf);
1422 linenumber++;
1423 break;
1424 }
1425 if (strstr(inbuf, "hindi\n") == inbuf+1) {
1426 hindi_mode = TRUE;
1427 if (mhindi_mode) {
1428 for (i = 0; i < N_MNOLIGS; i++)
1429 lig_table[modnolig[i]].in_use = TRUE;
1430 mhindi_mode = FALSE;
1431 }
1432 for (i = 0; i < N_NOLIGS; i++)
1433 lig_table[nolig[i]].in_use = FALSE;
1434 fprintf(f_out, "%%%s", inbuf);
1435 linenumber++;
1436 break;
1437 }
1438 if (strstr(inbuf, "modernhindi\n") == inbuf+1) {
1439 hindi_mode = TRUE;
1440 mhindi_mode = TRUE;
1441 for (i = 0; i < N_MNOLIGS; i++)
1442 lig_table[modnolig[i]].in_use = FALSE;
1443 fprintf(f_out, "%%%s", inbuf);
1444 linenumber++;
1445 break;
1446 }
1447 if (strstr(inbuf, "sanskrit\n") == inbuf+1) {
1448 hindi_mode = FALSE;
1449 mhindi_mode = FALSE;
1450 for (i = 0; i < N_MNOLIGS; i++)
1451 lig_table[modnolig[i]].in_use = TRUE;
1452 fprintf(f_out, "%%%s", inbuf);
1453 linenumber++;
1454 break;
1455 }
1456 if (strstr(inbuf, "lig") == inbuf+1) {
1457 s_ptr = inbuf;
1458 while (TRUE) {
1459 if ((s_ptr = strchr(s_ptr, ' ')) == NULL) break;
1460 s_ptr++;
1461 if (sscanf(s_ptr, "%d", &number) != 0)
1462 lig_table[ligidxs[number-1]].in_use = TRUE;
1463 }
1464 fprintf(f_out, "%%%s", inbuf);
1465 linenumber++;
1466 break;
1467 }
1468 if (strstr(inbuf, "nolig") == inbuf+1) {
1469 s_ptr = inbuf;
1470 while (TRUE) {
1471 if ((s_ptr = strchr(s_ptr, ' ')) == NULL) break;
1472 s_ptr++;
1473 if (sscanf(s_ptr, "%d", &number) != 0)
1474 lig_table[ligidxs[number-1]].in_use = FALSE;
1475 }
1476 fprintf(f_out, "%%%s", inbuf);
1477 linenumber++;
1478 break;
1479 }
1480 if (strstr(inbuf, "hyphen\n") == inbuf+1) {
1481 do_hyphen = TRUE;
1482 fprintf(f_out, "%%%s", inbuf);
1483 linenumber++;
1484 break;
1485 }
1486 if (strstr(inbuf, "nohyphen\n") == inbuf+1) {
1487 do_hyphen = FALSE;
1488 fprintf(f_out, "%%%s", inbuf);
1489 linenumber++;
1490 break;
1491 }
1492 if (strstr(inbuf, "vconjuncts\n") == inbuf+1) {
1493 do_vconjuncts = TRUE;
1494 fprintf(f_out, "%%%s", inbuf);
1495 linenumber++;
1496 break;
1497 }
1498 if (strstr(inbuf, "novconjuncts\n") == inbuf+1) {
1499 do_vconjuncts = FALSE;
1500 fprintf(f_out, "%%%s", inbuf);
1501 linenumber++;
1502 break;
1503 }
1504
1505 /* --------- Addition by Marc Csernel 1998 --------- */
1506
1507 if (strstr(inbuf, "tabs\n") == inbuf+1) {
1508 tabs_mode = TRUE;
1509 fprintf(f_out, "%%%s", inbuf);
1510 linenumber++;
1511 break;
1512 }
1513
1514 /* ------------------ End Addition ----------------- */
1515
1516 if (strstr(inbuf, "notabs\n") == inbuf+1) {
1517 tabs_mode = FALSE;
1518 fprintf(f_out, "%%%s", inbuf);
1519 linenumber++;
1520 break;
1521 }
1522
1523 fprintf(stderr, "Warning: possible illegal preprocessor command at line ");
1524 fprintf(stderr, "%d:\n%s", linenumber, inbuf);
1525 fprintf(f_out, "%s", inbuf);
1526 linenumber++;
1527 break;
1528 }
1529 *inbuf = '\0';
1530 }
1531 else {
1532 if (!find_dn()) fputs(inbuf, f_out);
1533
1534 /* process DN text */
1535
1536 else do {
1537 buf_idx = 0;
1538 symbol = inp_ch();
1539 dnproc();
1540 dn_yes = find_dn();
1541 if (!dn_yes) {
1542 strcat(outbuf, inbuf);
1543 fputs(outbuf, f_out);
1544 }
1545 }
1546 while (dn_yes);
1547 *inbuf = '\0';
1548 linenumber++;
1549 *outbuf = '\0';;
1550 }
1551 }
1552 while (p_in != NULL);
1553 fclose(f_in);
1554 fclose(f_out);
1555 exit(0);
1556 }
1557
1558
1559 /*
1560 * Read and parse DN input, and convert it into the character set
1561 * defined in char_table[]
1562 */
dnproc(void)1563 void dnproc(void) {
1564 short i;
1565 unsigned char saved, dnready;
1566 short brace_lev;
1567 int test_val; /* Marc Csernel */
1568 char savchr = 0;
1569 char wrong[10];
1570 brace_lev = 1;
1571 saved = FALSE;
1572 dnready = FALSE;
1573 do {
1574 switch(symbol) {
1575 case '.':
1576 savchr = inp_ch();
1577 i = 0;
1578 do { i++; } while ((i != 19) && (chset1[i-1] != savchr));
1579 if (i == 19) {
1580 wrong[0] = '.';
1581 wrong[1] = savchr;
1582 wrong[2] = '\0';
1583 err_ill(wrong);
1584 }
1585 else {
1586 if (i < 4) {
1587 savchr = inp_ch();
1588 if (savchr == 'h') i += 11;
1589 else saved = TRUE;
1590 if (i == 1) err_ill(".k");
1591 }
1592 }
1593 if (i == 18) put_ch('M');
1594 else put_ch(i);
1595 break;
1596
1597 /* --------- Addition by Marc Csernel 1998 --------- */
1598
1599 /* cite and chapter command */
1600 case ']':
1601 if (citation) {
1602 citation = 0;
1603 if (num_mode) put_ch(dummy);
1604 put_syll();
1605 test_sub_com();
1606 }
1607 if (optchapter) {
1608 optchapter = 0;
1609 if (num_mode) put_ch(dummy);
1610 put_syll();
1611 sendchar(symbol);
1612 break;
1613 }
1614
1615 /* ------------------ End Addition ----------------- */
1616
1617 case 'i':
1618 savchr = inp_ch();
1619 if (savchr == 'i') put_ch('I');
1620 else {
1621 put_ch(symbol);
1622 saved = TRUE;
1623 }
1624 break;
1625 case 'u':
1626 savchr = inp_ch();
1627 if (savchr == 'u') put_ch('U');
1628 else {
1629 put_ch(symbol);
1630 saved = TRUE;
1631 }
1632 break;
1633 case 'a':
1634 savchr = inp_ch();
1635 i = 0;
1636 do { i++; } while ((i != 4) && (chset2[i-1] != savchr));
1637 if (i == 4) {
1638 put_ch(symbol);
1639 saved = TRUE;
1640 }
1641 else put_ch(chset5[i-1]);
1642 break;
1643 case '\"':
1644 savchr = inp_ch();
1645 i = 0;
1646 do { i++; } while ((i != 3) && (chset3[i-1] != savchr));
1647 if (i == 3) {
1648 wrong[0] = '\"';
1649 wrong[1] = savchr;
1650 wrong[2] = '\0';
1651 err_ill(wrong);
1652 }
1653 else put_ch((short)(i+17));
1654 break;
1655 case '~':
1656 savchr = inp_ch();
1657 i = 0;
1658 do { i++; } while ((i != 5) && (chset6[i-1] != savchr));
1659 if (i == 6) {
1660 wrong[0] = '~';
1661 wrong[1] = savchr;
1662 wrong[2] = '\0';
1663 err_ill(wrong);
1664 }
1665 else if (i == 5) put_ch(47);
1666 else put_ch((short)(i+20));
1667 break;
1668 case end_of_line:
1669 put_ch(end_of_line);
1670 break;
1671 case '$':
1672 if (!dollar_mode) put_ch(symbol);
1673 else {
1674 if (no_dn) put_ch(dummy);
1675 else put_ch('}');
1676 dnready = TRUE;
1677 put_word();
1678 memmove(inbuf, inbuf+buf_idx, strlen(inbuf+buf_idx)+1);
1679 }
1680 break;
1681 case '}':
1682 brace_lev -= 1;
1683 if ((brace_lev == 0) && (!d_found)) {
1684 if (no_dn) put_ch(dummy);
1685 else put_ch(symbol);
1686 dnready = TRUE;
1687 put_word();
1688 memmove(inbuf, inbuf+buf_idx, strlen(inbuf+buf_idx)+1);
1689 }
1690 else put_ch(symbol);
1691 break;
1692 case '{':
1693 put_ch(symbol);
1694 brace_lev += 1;
1695 break;
1696 case '%':
1697 put_ch(symbol);
1698 do {
1699 symbol = inp_ch();
1700 if (symbol != end_of_line) sendchar(symbol);
1701 }
1702 while (symbol != end_of_line);
1703 sendchar('\n');
1704 break;
1705 case '<':
1706 put_syll();
1707 do {
1708 symbol = inp_ch();
1709 if (symbol == end_of_line) symbol = '\n';
1710 if (symbol != '>') sendchar(symbol);
1711 }
1712 while (symbol != '>');
1713 break;
1714 case '\\':
1715 put_ch(symbol);
1716 symbol = inp_ch();
1717 if (symbol == end_of_line) {
1718 put_word();
1719 strcat(outbuf, "\n");
1720 fputs(outbuf, f_out);
1721 *outbuf = '\0';
1722 }
1723 else {
1724
1725 /* --------- Addition by Marc Csernel 1998 --------- */
1726
1727 /* Modified MC May 98 to take \\[5pt] into account */
1728 if (symbol == '\\') {
1729 sendchar(symbol);
1730 symbol = inp_ch();
1731 if (symbol == '[') {
1732 while (symbol != ']') {
1733 sendchar(symbol);
1734 symbol = inp_ch();
1735 }
1736 sendchar(symbol);
1737 symbol = inp_ch();
1738 }
1739 savchr = symbol;
1740 saved = TRUE;
1741 break;
1742 }
1743
1744 /* ------------------ End Addition ----------------- */
1745
1746 if (!isalpha((unsigned char)symbol)) sendchar(symbol);
1747 else {
1748 nbchcomm = 0; /* Marc Csernel */
1749 do {
1750 command[nbchcomm++] = symbol; /* Marc Csernel */
1751 sendchar(symbol);
1752 symbol = inp_ch();
1753 }
1754 while (isalpha((unsigned char)symbol));
1755
1756 /* --------- Addition by Marc Csernel 1998 --------- */
1757
1758 command[nbchcomm++] = 0;
1759 test_val = test_command();
1760 switch (test_val) {
1761 case 1:
1762 savchr = test_sub_com();
1763 break;
1764 case 2:
1765 savchr = ignore();
1766 break;
1767 case 3:
1768 savchr = comm_double_args();
1769 break;
1770 case 4:
1771 savchr = comm_begin();
1772 break;
1773 case 5:
1774 savchr = comm_special();
1775 break;
1776 case 6:
1777 savchr = comm_opt();
1778 break;
1779 case 7:
1780 savchr = comm_cite();
1781 break;
1782 case 8:
1783 savchr = comm_chapter();
1784 break;
1785 default:
1786 savchr = symbol;
1787 }
1788
1789 /* ------------------ End Addition ----------------- */
1790
1791 saved = TRUE;
1792 }
1793 }
1794 break;
1795 case ill_char:
1796 err_ill('\0');
1797 break;
1798 case end_of_file:
1799 fputs("Error: missing }", stderr);
1800 exit(1);
1801 default:
1802 if (symbol < 0) err_ill('\0'); /* accented character inside dn mode */
1803 i = 0;
1804 do { i++; } while ((i != 10) && (chset4[i-1] != symbol));
1805 if (i == 10) put_ch(symbol);
1806 else {
1807 savchr = inp_ch();
1808 if (savchr == 'h') {
1809 if (i == 9) put_ch(20);
1810 else put_ch((short)(symbol-32));
1811 }
1812 else {
1813 put_ch(symbol);
1814 saved = TRUE;
1815 }
1816 }
1817 }
1818 if (saved) {
1819 symbol = savchr;
1820 saved = FALSE;
1821 }
1822 else {
1823 if (!dnready) symbol = inp_ch(); }
1824 }
1825 while (!dnready);
1826 }
1827
1828 /*
1829 * Read and parse input in the character set defined by char_table[],
1830 * and convert it into TeX text and macros for the dvng fonts.
1831 */
put_ch(short code)1832 void put_ch(short code) {
1833 short cons_idx = 0;
1834 char cstr[2];
1835 struct char_def *c_ptr;
1836 struct cons_joins *q_ptr;
1837 short i, j;
1838 /* --------- Addition by Kevin Carmody 2005 --------- */
1839 /*
1840 * Conjunct fixes used by fixconj()
1841 */
1842 short wrong_1[] = {63, 63, 113};
1843 short right_1[] = {63, 34, 0}; /* kk.sa */
1844 short wrong_2[] = {94, 214, 264, 113};
1845 short right_2[] = {94, 86, 264, 34, 0}; /* .tk.sa */
1846 short wrong_3[] = {22, 62, 26};
1847 short right_3[] = {22, 226, 0}; /* ~nj~na */
1848 short wrong_4[] = {274, 88, 264, 273, 57, 52, 264, 121};
1849 short right_4[] = {126, 88, 264, 43, 0}; /* .drya */
1850 short wrong_5[] = {94, 140, 264, 118};
1851 short right_5[] = {94, 100, 264, 146, 0}; /* ddva */
1852 short wrong_6[] = {94, 136, 264, 118};
1853 short right_6[] = {94, 100, 264, 64, 118, 0}; /* ddhva */
1854 short wrong_7[] = {271, 100, 264, 273, 57, 52, 264, 121};
1855 short right_7[] = {272, 100, 264, 43, 0}; /* drya */
1856 short wrong_8[] = {9, 274, 86, 264, 273, 57, 52, 264, 121};
1857 short right_8[] = {9, 126, 86, 264, 43, 0}; /* .s.trya */
1858 /* ------------------ End Addition ----------------- */
1859
1860 c_ptr = &char_table[code-1];
1861 switch(c_ptr->ch_typ) {
1862 case dn:
1863 if (cmr_mode) {
1864 cmr_mode = FALSE;
1865 put_sym(RE);
1866 }
1867 else {
1868 if (num_mode) {
1869 num_mode = FALSE;
1870 put_sym(RBRACE);
1871 }
1872 }
1873 switch(c_ptr->ch_subtyp) {
1874 case hi_vowel:
1875 if (wait_syll) {
1876 put_syll();
1877 if (do_hyphen) strcat(word, "\\-");
1878 }
1879 if (lig_block) err_ill("+"); /* Kevin Carmody */
1880 if (cons_seen) {
1881 if (syll[chr_idx-1] < 0) expand();
1882 if (code == 'i') {
1883 for (i = chr_idx; i>= (cons_idx+1); i--)
1884 syll[i] = syll[i-1];
1885 syll[cons_idx] = c_ptr->ch_subcode;
1886 }
1887 else {
1888 syll[chr_idx] = c_ptr->ch_subcode;
1889 if ((code != 'A') && (code != 'a')) vow_seen = TRUE;
1890 }
1891 }
1892 else syll[chr_idx] = c_ptr->ch_code;
1893 chr_idx += 1;
1894 wait_syll = TRUE;
1895 cons_seen = FALSE;
1896 break;
1897 case lo_vowel:
1898 if (wait_syll) {
1899 put_syll();
1900 if (do_hyphen) strcat(word, "\\-");
1901 }
1902 if (lig_block) err_ill("+"); /* Kevin Carmody */
1903 if (cons_seen) {
1904 if (syll[chr_idx-1] < 0) expand();
1905 if ((syll[chr_idx-1] == 'r') && (code == 'u'))
1906 syll[--chr_idx] = 'z';
1907 else {
1908 if ((syll[chr_idx-1] == 'r') && (code == 'U'))
1909 syll[--chr_idx] = '!';
1910 else {
1911 if ((syll[chr_idx-1] == 'h') && (code == 7))
1912 syll[--chr_idx] = 0343;
1913 else {
1914 if ((syll[chr_idx-1] == 'r') && ((code == 7)
1915 || (code == 15) || (code == 16) || (code == 17))) {
1916 syll[--chr_idx] = c_ptr->ch_code;
1917 front_r = TRUE;
1918 }
1919 else {
1920 put_macro(c_ptr->ch_subcode);
1921 chr_idx -= 1;
1922 }
1923 }
1924 }
1925 }
1926 }
1927 else syll[chr_idx] = c_ptr->ch_code;
1928 chr_idx += 1;
1929 wait_syll = TRUE;
1930 cons_seen = FALSE;
1931 break;
1932 case consonant:
1933 if (wait_syll) {
1934 put_syll();
1935 if (do_hyphen) strcat(word, "\\-");
1936 }
1937 if (!cons_seen) {
1938
1939 /* Is this the first consonant? */
1940
1941 cons_seen = TRUE;
1942 cons_idx = chr_idx;
1943 cons_code = c_ptr->ch_subcode;
1944 syll[chr_idx] = c_ptr->ch_code;
1945 chr_idx += 1;
1946 tst_half();
1947 }
1948 else {
1949 q_ptr = &cons_table[cons_code];
1950 if (syll[cons_idx] == 'r') {
1951
1952 /* Was there an initial "r"? */
1953
1954 front_r = TRUE;
1955 syll[chr_idx-1] = c_ptr->ch_code;
1956 cons_code = c_ptr->ch_subcode;
1957 tst_half();
1958 }
1959 else {
1960 i = q_ptr->lig_code;
1961 for (j = i+(q_ptr->n_ligs); i != j; i++)
1962 if (lig_table[i].sym_code == code) break;
1963 if ((i != j) && (lig_table[i].in_use)
1964 && (!lig_block)) { /* lig_block added Kevin Carmody */
1965
1966 /* Is there a ligature? */
1967
1968 syll[chr_idx-1] = lig_table[i].sym_new;
1969 cons_code = lig_table[i].join_idx;
1970 joincode = cons_table[cons_code].j_code;
1971 if (joincode != 0) {
1972 half_codes[0] = joincode;
1973 n_halves = 1;
1974 }
1975 else {
1976
1977 /* ... or a half-form? */
1978
1979 joincode = cons_table[c_ptr->ch_subcode].j_code;
1980 if ((joincode != 0) && (n_halves != 0)) {
1981 half_codes[n_halves] = joincode;
1982 n_halves += 1;
1983 }
1984 else n_halves = 0;
1985 }
1986 }
1987 else {
1988 if ((code == 'r') && (!lig_block)) {
1989 /* lig_block added Kevin Carmody */
1990 if (q_ptr->r_type != 0) {
1991
1992 /* "Special" non-initial "r"? */
1993
1994 syll[chr_idx] = syll[chr_idx-1];
1995 syll[chr_idx-1] = (q_ptr->r_type == 1) ? '\176' : 272;
1996 syll[chr_idx+1] = RBRACE;
1997 chr_idx += 2;
1998 }
1999 else {
2000
2001 /* "Normal" non-initial "r"? */
2002
2003 syll[chr_idx] = '\175';
2004 chr_idx += 1;
2005 n_halves = 0;
2006 }
2007 cons_code = 0;
2008 }
2009 else {
2010 if ((q_ptr->j_code != 0) && (!lig_block)) {
2011 /* lig_block added by Kevin Carmody */
2012
2013 /* Can we build a conjunct using a ligature? */
2014
2015 syll[chr_idx-1] = q_ptr->j_code;
2016 syll[chr_idx] = c_ptr->ch_code;
2017 cons_code = c_ptr->ch_subcode;
2018 chr_idx += 1;
2019 tst_half();
2020 }
2021 else {
2022 if (n_halves != 0) {
2023
2024 /* ... or a half-form? */
2025
2026 if (syll[chr_idx-1] != RBRACE) {
2027 /*
2028 * There might already have been a
2029 * subscript "-r" in the conjunct!
2030 * (E.g. khrya, ttrya)
2031 * -- John Smith
2032 */
2033 for (i = 0; i < n_halves; i++)
2034 syll[chr_idx-1+i] = half_codes[i];
2035 chr_idx += n_halves;
2036 syll[chr_idx-1] = c_ptr->ch_code;
2037 cons_code = c_ptr->ch_subcode;
2038 tst_half();
2039 }
2040 else {
2041 for (i = 0; i < n_halves; i++)
2042 syll[chr_idx-2+i] = half_codes[i];
2043 chr_idx += n_halves;
2044 syll[chr_idx-1] = c_ptr->ch_code;
2045 syll[chr_idx-2] = RBRACE;
2046 cons_code = c_ptr->ch_subcode;
2047 tst_half();
2048 }
2049 }
2050 else {
2051
2052 /* Fall back on viraama */
2053
2054 if (syll[chr_idx-1] < 0) expand();
2055 put_macro(VIRAAM);
2056 cons_code = c_ptr->ch_subcode;
2057 syll[chr_idx] = c_ptr->ch_code;
2058 chr_idx += 1;
2059 tst_half();
2060 }
2061 }
2062 }
2063 /*
2064 * This hack is to secure the correct representation
2065 * for various conjuncts that may assume undesirable
2066 * forms.
2067 */
2068 /* --------- Modification by Kevin Carmody 2005 --------- */
2069 fixconj(wrong_1, right_1);
2070 fixconj(wrong_2, right_2);
2071 fixconj(wrong_3, right_3);
2072 fixconj(wrong_4, right_4);
2073 fixconj(wrong_5, right_5);
2074 fixconj(wrong_6, right_6);
2075 fixconj(wrong_7, right_7);
2076 fixconj(wrong_8, right_8);
2077 /* ------------------ End Modification ----------------- */
2078 /*
2079 * Now replace the sequence consonant + viraama + ya
2080 * by consonant + open ya (glyph became available only
2081 * Devnag 2.1).
2082 */
2083 for (i = 0; i < chr_idx-3; i++) {
2084 if ((syll[i] == 94) && (syll[i+2] == 264)
2085 && (syll[i+3] == 121)) {
2086 syll[i] = syll[i+1];
2087 syll[i+1] = 43;
2088 chr_idx = i + 2;
2089 }
2090 }
2091 }
2092 }
2093 }
2094 lig_block = FALSE; /* Kevin Carmody */
2095 break;
2096 case special:
2097 if (lig_block) err_ill("+"); /* Kevin Carmody */
2098 if (cons_seen) { if (syll[chr_idx-1] < 0) expand(); }
2099 if ((code == 'M') && (front_r)) {
2100 front_r = FALSE;
2101 if (vow_seen) syll[chr_idx] = 270;
2102 else syll[chr_idx] = RDT;
2103 chr_idx += 1;
2104 put_syll();
2105 }
2106 else {
2107 if ((code == 'M') && (syll[chr_idx-1] == 'I')) {
2108 syll[chr_idx-1] = 18;
2109 put_syll();
2110 }
2111 else {
2112 if ((code == 'M') && (vow_seen)) {
2113 syll[chr_idx] = 268;
2114 chr_idx += 1;
2115 put_syll();
2116 }
2117
2118 /* --------- Addition by Marc Csernel 1998 --------- */
2119
2120 else {
2121 if (code == '_') {
2122 if(!cons_seen) err_ill("_");
2123 else {
2124 put_macro(VIRAAM);
2125 put_syll();
2126 }
2127 }
2128 else {
2129 if (code == '&') {
2130 if(!tabs_mode) {
2131 if (!cons_seen) {
2132 fprintf(stderr, "Error: tabs_mode not selected\n");
2133 err_ill("&");
2134 }
2135 else {
2136 put_macro(VIRAAM);
2137 put_syll();
2138 }
2139 }
2140 else {
2141 if(!cons_seen) sendchar((char)code);
2142 else {
2143 put_macro(VIRAAM);
2144 put_syll();
2145 }
2146 }
2147 }
2148
2149 /* ------------------ End Addition ----------------- */
2150
2151 else {
2152
2153 /* --------- Addition by Kevin Carmody 2005 --------- */
2154
2155 if (code == '+') { /* half letter or viraama */
2156 if (!cons_seen) err_ill("+");
2157 lig_block = TRUE;
2158 }
2159 /* ------------------ End Addition ------------------ */
2160
2161 else {
2162 if ((!hindi_mode) && (cons_seen)) put_macro(VIRAAM);
2163 put_syll();
2164 put_sym(c_ptr->ch_code);
2165 }
2166 }
2167 }
2168 }
2169 }
2170 }
2171 }
2172 break;
2173 case illegal:
2174 cstr[0] = code;
2175 cstr[1] = '\0';
2176 err_ill(cstr);
2177 break;
2178 case control:
2179 if (cmr_mode) {
2180 cmr_mode = FALSE;
2181 put_sym(RE);
2182 }
2183 else {
2184 if (lig_block) err_ill("+"); /* Kevin Carmody */
2185 if (num_mode) {
2186 num_mode = FALSE;
2187 put_sym(RBRACE);
2188 }
2189 else {
2190 if (cons_seen) {
2191 if (syll[chr_idx-1] < 0) expand();
2192 }
2193 if ((!hindi_mode) && (cons_seen)) put_macro(VIRAAM);
2194 put_syll();
2195 }
2196 }
2197 if (code == end_of_line) {
2198 put_word();
2199 strcat(outbuf, "\n");
2200 fputs(outbuf, f_out);
2201 *outbuf = '\0';
2202 }
2203 else if (code != dummy) sendchar((char)code);
2204 break;
2205 case cmr:
2206 if (cmr_mode) sendchar((char)code);
2207 else {
2208 cmr_mode = TRUE;
2209 if (num_mode) {
2210 num_mode = FALSE;
2211 put_sym(RBRACE);
2212 }
2213 else {
2214 if (lig_block) err_ill("+"); /* Kevin Carmody */
2215 if (cons_seen) { if (syll[chr_idx-1] < 0) expand(); }
2216 if ((!hindi_mode) && (cons_seen)) put_macro(VIRAAM);
2217 put_syll();
2218 }
2219 put_sym(RS);
2220 sendchar((char)code);
2221 }
2222 break;
2223 case numeral:
2224 if (num_mode) sendchar((char)code);
2225 else {
2226 num_mode = TRUE;
2227 if (cmr_mode) {
2228 cmr_mode = FALSE;
2229 put_sym(RE);
2230 }
2231 else {
2232 if (lig_block) err_ill("+"); /* Kevin Carmody */
2233 if (cons_seen) { if (syll[chr_idx-1] < 0) expand(); }
2234 if ((!hindi_mode) && (cons_seen)) put_macro(VIRAAM);
2235 put_syll();
2236 }
2237 put_sym(RN);
2238 sendchar((char)code);
2239 }
2240 }
2241 }
2242
2243 /*
2244 * Append a character to word[]; if character is whitespace,
2245 * call put_word().
2246 */
sendchar(char c)2247 void sendchar(char c) {
2248 int i = strlen(word);
2249 word[i] = c == end_of_line ? '\n' : c;
2250 word[i+1] = '\0';
2251 if (isspace((unsigned char)c)) put_word();
2252 }
2253
2254 /*
2255 * Use the current chacter value as an index into out_string[], and
2256 * append the code found there to the end of word[].
2257 */
put_sym(short code)2258 void put_sym(short code) {
2259 strcat(word, out_string[code]);
2260 }
2261
2262 /*
2263 * Append word[] to outbuf[].
2264 */
put_word(void)2265 void put_word(void) {
2266 /*
2267 * The hack is to avoid hyphenation before any consonant stopped
2268 * with viraama. -- John Smith
2269 */
2270 char *w_ptr;
2271 if (do_hyphen) { /* hack */
2272 do {
2273 w_ptr = strstr(word, "\\-\\qq{");
2274 if (w_ptr != NULL) memmove(w_ptr, w_ptr+2, strlen(w_ptr+2)+1);
2275 }
2276 while (w_ptr != NULL);
2277 }
2278 strcat(outbuf, word);
2279 *word = '\0';
2280 }
2281
2282 /*
2283 * Append syll[] to word[], using the codes defined in out_string[]
2284 */
put_syll(void)2285 void put_syll(void) {
2286 /*
2287 * put_syll() now checks to see whether "old-style" treatment of
2288 * consonant sequences containing viraama has been requested with
2289 * the @vconjuncts preprocessor command. If not, it re-orders the
2290 * characters in any such sequence containing "i" so that the
2291 * i-matra vowel is placed after the viraama rather than before
2292 * the entire sequence. -- John Smith
2293 */
2294 short i;
2295 int ipos, vpos, bpos;
2296 if (do_vconjuncts == FALSE) {
2297 ipos = sindex(0, '\105'); /* 'i' */
2298 if (ipos != -1) {
2299 vpos = sindex(ipos, '\136'); /* viraama */
2300 if (vpos == -1) {
2301 vpos = sindex(ipos, 271);
2302 if (vpos == -1) vpos = sindex(ipos, 274);
2303 if (vpos != -1) {
2304 vpos = sindex(vpos, 273); /* alternative viraama */
2305 if ((syll[vpos+1] != '9') || (syll[vpos+2] != '4')) vpos = -1;
2306 }
2307 }
2308 if (vpos != -1) {
2309 bpos = sindex(vpos, 264); /* right brace after viraama */
2310 if (bpos != -1) {
2311 for (i = ipos+1; i <= bpos; i++)
2312 syll[i-1] = syll[i];
2313 syll[bpos] = '\105';
2314 }
2315 }
2316 }
2317 }
2318 for (i = 0; i < chr_idx; i++)
2319 strcat(word, out_string[syll[i]]);
2320 if (front_r) {
2321 if (vow_seen) strcat(word, out_string[269]);
2322 else strcat(word, out_string[13]);
2323 front_r = FALSE;
2324 }
2325 chr_idx = 0;
2326 cons_seen = FALSE;
2327 vow_seen = FALSE;
2328 wait_syll = FALSE;
2329 lig_block = FALSE; /* Kevin Carmody */
2330 }
2331
2332 /*
2333 * Check whether a "half-form" exists for current consonant, and
2334 * store the result.
2335 */
tst_half(void)2336 void tst_half(void) {
2337 joincode = cons_table[cons_code].j_code;
2338 if (joincode != 0) {
2339 half_codes[0] = joincode;
2340 n_halves = 1;
2341 }
2342 else n_halves = 0;
2343 }
2344
2345 /*
2346 * Manipulate contents of syll[] to incorporate a macro call,
2347 * using values that are indices into out_string[] (so that
2348 * put_syll() will produce the correct output).
2349 */
put_macro(short macro)2350 void put_macro(short macro) {
2351 char tmp[5];
2352 int lt, i;
2353 if (syll[chr_idx-1] == '\175') {
2354 syll[chr_idx+1] = '\175';
2355 syll[chr_idx] = RBRACE;
2356 syll[chr_idx-1] = syll[chr_idx-2];
2357 syll[chr_idx-2] = macro;
2358 chr_idx += 2;
2359 }
2360 else {
2361 if (syll[chr_idx-1] == RBRACE) {
2362 /*
2363 * This is a bit of a hack on Velthuis's part! What it
2364 * really means is: if syll[] currently consists of "dr"
2365 * OR a consonant(-group) with the subscript "caret" form
2366 * of "-r" already attached, AND if a subscript vowel
2367 * (or viraama) is to be added to it. In pre-2.0 releases
2368 * of devnag this always produced "\qa{consonant}{vowel}",
2369 * i.e. it used the simple, non-"caret" form of "-r",
2370 * whatever the consonant to which it was to be attached.
2371 * I have fixed this bug (feature?), but at the cost of
2372 * invoking a new macro, \qc, which will have to be
2373 * defined in dnmacs.tex etc. for the new code to work.
2374 * -- John Smith
2375 */
2376 if (syll[chr_idx-3] == 126) syll[chr_idx-3] = 274;
2377 else syll[chr_idx-3] = 271;
2378 syll[chr_idx] = LBRACE;
2379 sprintf(tmp, "%d", macro);
2380 lt = strlen(tmp);
2381 chr_idx += 1;
2382 for (i = 0; i < lt; i++)
2383 syll[chr_idx+i] = tmp[i];
2384 chr_idx += lt;
2385 syll[chr_idx] = RBRACE;
2386 chr_idx += 1;
2387 }
2388 else {
2389 syll[chr_idx] = syll[chr_idx-1];
2390 syll[chr_idx-1] = macro;
2391 syll[chr_idx+1] = RBRACE;
2392 chr_idx += 2;
2393 }
2394 }
2395 }
2396
2397 /*
2398 * Exit with error message in the case of illegal input.
2399 */
err_ill(const char * str)2400 void err_ill(const char *str) {
2401 fprintf(stderr, "Error: illegal character(s) \"%s\" detected at line %d:\n",
2402 str, linenumber);
2403 fprintf(stderr, inbuf);
2404 exit(1);
2405 }
2406
2407 /*
2408 * Read and return the next character from inbuf[], taking appropriate
2409 * action in the case of EOL, EOF or an illegal character.
2410 */
inp_ch(void)2411 char inp_ch(void) {
2412 char ch, ch_out;
2413 ch = inbuf[buf_idx++];
2414 if (ch == '\n') {
2415 if (p_in == 0) ch_out = end_of_file;
2416 else {
2417 p_in = fgetline(inbuf, MAXBUF, f_in);
2418 linenumber++;
2419 buf_idx = 0;
2420 ch_out = end_of_line;
2421 }
2422 }
2423 else {
2424 if (ch == '\t') ch_out = ' '; /* Change TABs to spaces */
2425 else {
2426 if ((unsigned)ch < 32) ch_out = ill_char; /* Allow accented characters */
2427 else ch_out = ch;
2428 }
2429 }
2430 return(ch_out);
2431 }
2432
2433 /*
2434 * Invoked if syll[chr_idx-1] is negative (instead of containing
2435 * an octal character value). Fixes appropriate representation
2436 * for "r".
2437 */
expand(void)2438 void expand(void) {
2439 short indx;
2440 indx = -1-syll[chr_idx-1];
2441 if (r_ligs[indx][1] != 0) {
2442 syll[chr_idx] = r_ligs[indx][0];
2443 syll[chr_idx-1] = (r_ligs[indx][1] == 1) ? '\176' : 272;
2444 syll[chr_idx+1] = RBRACE;
2445 chr_idx += 2;
2446 }
2447 else {
2448 syll[chr_idx-1] = r_ligs[indx][0];
2449 syll[chr_idx] = '\175';
2450 chr_idx += 1;
2451 }
2452 cons_code = 0;
2453 }
2454
2455 /*
2456 * Search inbuf[] for "{\dn" followed by non-letter or, in dollar
2457 * mode only, for "$". Return TRUE or FALSE as appropriate. If
2458 * TRUE, send inbuf[] text prior to mode-switch to outbuf[], followed
2459 * by mode-switch indicator, and make inbuf[] start at beginning of
2460 * Devanagari text.
2461 */
find_dn(void)2462 char find_dn(void) {
2463 char *d_ptr;
2464 char *dn_ptr;
2465 char *svbuf;
2466 int again;
2467 d_found = FALSE;
2468 svbuf = inbuf;
2469 do {
2470 again = FALSE;
2471 dn_ptr = strstr(svbuf, "{\\dn");
2472 if (dn_ptr != NULL) {
2473 again = isalpha((unsigned char)dn_ptr[4]);
2474 svbuf = dn_ptr+4;
2475 }
2476 }
2477 while (again);
2478 if (dollar_mode) {
2479 d_ptr = strchr(inbuf, '$');
2480 if ((d_ptr != NULL) && ((dn_ptr == NULL) || (d_ptr < dn_ptr))) {
2481 d_found = TRUE;
2482 dn_ptr = d_ptr;
2483 }
2484 }
2485 if (dn_ptr == NULL) return(FALSE);
2486 strncat(outbuf, inbuf, dn_ptr-inbuf);
2487 no_dn = FALSE;
2488 if (!d_found) {
2489 if (dn_ptr[4] == '#') { /* equivalent to @dolmode3 */
2490 no_dn = TRUE;
2491 dn_ptr += 1;
2492 }
2493 else strcat(outbuf, "{\\dn");
2494 dn_ptr += 4;
2495 }
2496 else {
2497 switch(dollar_mode) {
2498 case 1:
2499 strcat(outbuf, "{\\dn ");
2500 break;
2501 case 2:
2502 strcat(outbuf, "\\pdn ");
2503 case 3:
2504 no_dn = TRUE;
2505 }
2506 dn_ptr += 1;
2507 }
2508 memmove(inbuf, dn_ptr, strlen(dn_ptr)+1);
2509 return(TRUE);
2510 }
2511
2512 /*
2513 * Return index of character value in syll[] starting at syll[i],
2514 * -1 if none
2515 */
sindex(int i,short t)2516 int sindex(int i, short t) {
2517 int j;
2518 for (j = i; j < chr_idx; j++) {
2519 if (syll[j] == t) return j;
2520 }
2521 return -1;
2522 }
2523
2524 /*
2525 * Replace infelicitous conjuncts
2526 */
fixconj(short * wrong,short * right)2527 void fixconj(short *wrong, short *right) {
2528 int i;
2529 for (i = 0; i < chr_idx; i++) {
2530 if (syll[i] != wrong[i]) return;
2531 }
2532 for (i = 0; right[i] != 0; i++) {
2533 syll[i] = right[i];
2534 }
2535 chr_idx = i;
2536 }
2537
2538 /*
2539 * Read a line with either line ending (UNIX = LF, DOS = CR LF, Mac = CR)
2540 * return the pointer to the buffer of NULL at end of file or I/O Error
2541 * (replacement of fgets, requires global variables)
2542 */
fgetline(char * buf,int n,FILE * f)2543 char *fgetline(char *buf, int n, FILE *f) {
2544 int k;
2545 buf[0] = '\0';
2546 for (k = 0; k < n-1 && (k == 0 || buf[k-1] != '\n'); ) {
2547 if (charpresent) charpresent = FALSE;
2548 else charbuf = fgetc(f);
2549 if (wasCR) {
2550 wasCR = FALSE;
2551 buf[k++] = '\n';
2552 if (charbuf != '\n') charpresent = TRUE;
2553 } else {
2554 if (charbuf == EOF) {
2555 if (k) {
2556 charpresent = TRUE; break;
2557 }
2558 else return NULL;
2559 }
2560 if (charbuf == '\r') wasCR = TRUE;
2561 else buf[k++] = charbuf;
2562 }
2563 }
2564 buf[k] = '\0';
2565 return buf;
2566 }
2567