w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

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