/*  devnag.c
    Preprocessor for TeX for texts containing Devanagari characters.
    Copyright (C) 1991  University of Groningen, The Netherlands

    Author:   Frans J. Velthuis
    Internet: velthuis@rc.rug.nl
    Bitnet:   velthuis@hgrrug5

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 1, or (at your option)
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdio.h>
#include <ctype.h>
#define TRUE 1
#define FALSE 0
#define ill_char  29
#define dummy 30
#define end_of_file 30
#define end_of_line 31
#define n_noligs 40
/* ch_class values */
#define illegal 0
#define cmr 1
#define control 2
#define dn 3
#define numeral 4
/* ch_subclass values */
#define lo_vowel 0
#define hi_vowel 1
#define consonant 2
#define special 3

#define LBRACE 273
#define RBRACE 264
#define RE 263
#define RDT 266
#define RN 265
#define RS 256
#define VIRAAM 94

short ch_class;
short ch_subclass ;
short join_type;
struct  char_def {
       short ch_typ, ch_subtyp, ch_code, ch_subcode;
     };
struct cons_joins {
       short n_ligs, lig_code;
       short r_type, j_code;
     };
struct ligs {
       char sym_code;
       short sym_new, join_ptr;
       unsigned char in_use;
     };
struct char_def *c_ptr;
struct cons_joins *q_ptr;
char tmp[4];
char string[10];
char wrong[10];
char cstr[2];
FILE *f_in,*f_out,*fopen();
char *p_in,*p_out,*s_ptr,*o_ptr;
char **p_match;
char *strchr();
short i, j, buf_length;
int number;
char symbol;
char com_str[80], prompt[80];
char infil[80], outfil[80];
char inbuf[133], outbuf[133], tmpbuf[133];
char word[500];
char *p;
short syll[30];
int n_halves;
short half_codes[30];
short joincode;
unsigned char dn_yes, hindi_mode, dollar_mode, d_found;
unsigned char no_dn, result, buf_ptr, wait_syl, lin_obey;
unsigned char error, cons_seen, vow_seen, front_r, cmr_mode, num_mode;
short cons_ptr, chr_ptr, cons_code;
short nolig[n_noligs] = {2,3,6,7,16,25,27,34,35,39,40,46,47,49,
    56,58,59,62,65,78,81,82,84,85,86,87,88,89,90,91,92,93,94,95,
    96,98,99,100,101,105};
short ligptrs[105] = {0,1,2,3,4,6,7,9,11,12,13,14,118,16,17,18,
    19,20,21,22,23,24,25,26,27,28,29,
    30,31,32,33,34,35,36,38,39,40,41,
    42,43,44,45,46,47,48,49,50,52,53,119,54,
    55,56,58,59,60,61,62,63,64,65,66,
    68,69,70,71,72,73,74,75,76,77,78,80,
    81,82,84,85,86,87,88,89,90,91,92,93,
    94,95,96,98,99,100,101,102,104,117,105,
    106,107,108,109,110,111,112,113};
struct char_def table[127] = {
    {illegal,special,0,0},                        /* 1 not used */
    {dn,consonant,'\126',34},                     /* 2 .t */
    {dn,consonant,'\130',36},                     /* 3 .d */
    {dn,special,'\72',0},                         /* 4 .o */
    {dn,consonant,'\132',1},                      /* 5 .n */
    {dn,consonant,'\161',2},                      /* 6 .s */
    {dn,lo_vowel,'\33',2},                        /* 7 .r */
    {dn,consonant,'\13',3},                       /* 8 .g */
    {dn,special,'\54',0},                         /* 9 .h */
    {dn,special,'\137',0},                        /* 10 .a */
    {dn,special,'\24',0},                         /* 11 .. */
    {dn,consonant,'\14',4},                       /* 12 .K */
    {dn,consonant,'\127',35},                     /* 13 .T */
    {dn,consonant,'\131',57},                     /* 14 .D */
    {dn,lo_vowel,'\30','\37'},                    /* 15 .l */
    {dn,lo_vowel,'\31','\174'},                   /* 16 .L */
    {dn,lo_vowel,'\21','\16'},                    /* 17 .R */
    {dn,consonant,'\122',32},                     /* 18 "n */
    {dn,consonant,'\146',5},                      /* 19 "s */
    {dn,consonant,'\170',0},                      /* 20 Rh */
    {dn,consonant,'\32',11},                      /* 21 ~n */
    {dn,hi_vowel,267,262},                        /* 22 ~o */
    {dn,hi_vowel,259,4},                          /* 23 ~a */
    {dn,consonant,'\35',31},                      /* 24 ~r */
    {illegal,special,0,0},                        /* 25 not used */
    {illegal,special,0,0},                        /* 26 not used */
    {illegal,special,0,0},                        /* 27 not used */
    {illegal,special,0,0},                        /* 28 not used */
    {illegal,special,0,0},                        /* 29 not used */
    {control,special,0,0},                        /* 30 dummy */
    {control,special,0,0},                        /* 31 end_of_line */
    {control,special,0,0},                        /* 32 space */
    {cmr,special,0,0},                            /* ! */
    {illegal,special,0,0},                        /* " */
    {dn,special,'\25',0},                         /* # */
    {illegal,special,0,0},                        /* $ */
    {illegal,special,0,0},                        /* % */
    {dn,special,0,0},                             /* & */
    {cmr,special,0,0},                            /* ' to - */
    {cmr,special,0,0},                            /* ' to - */
    {cmr,special,0,0},                            /* ' to - */
    {cmr,special,0,0},                            /* ' to - */
    {cmr,special,0,0},                            /* ' to - */
    {cmr,special,0,0},                            /* ' to - */
    {cmr,special,0,0},                            /* ' to - */
    {illegal,special,0,0},                        /* . */
    {dn,special,'\40',0},                         /* / */
    {numeral,special,0,0},                        /* 0 to 9 */
    {numeral,special,0,0},                        /* 0 to 9 */
    {numeral,special,0,0},                        /* 0 to 9 */
    {numeral,special,0,0},                        /* 0 to 9 */
    {numeral,special,0,0},                        /* 0 to 9 */
    {numeral,special,0,0},                        /* 0 to 9 */
    {numeral,special,0,0},                        /* 0 to 9 */
    {numeral,special,0,0},                        /* 0 to 9 */
    {numeral,special,0,0},                        /* 0 to 9 */
    {numeral,special,0,0},                        /* 0 to 9 */
    {cmr,special,0,0},                            /* : and ; */
    {cmr,special,0,0},                            /* : and ; */
    {illegal,special,0,0},                        /* < */
    {cmr,special,0,0},                            /* = */
    {illegal,special,0,0},                        /* > */
    {cmr,special,0,0},                            /* ? */
    {dn,special,'\177',0},                        /* @ */
    {dn,hi_vowel,258,'\101'},                     /* A */
    {dn,consonant,'\102',6},                      /* B */
    {dn,consonant,'\103',33},                     /* C */
    {dn,consonant,'\104',7},                      /* D */
    {dn,hi_vowel,259,'\173'},                     /* E */
    {illegal,special,0,0},                        /* F */
    {dn,consonant,'\107',8},                      /* G */
    {dn,special,'\54',0},                         /* H */
    {dn,hi_vowel,'\111','\106'},                  /* I */
    {dn,consonant,'\112',9},                      /* J */
    {dn,consonant,'\113',10},                     /* K */
    {dn,consonant,'\17',30},                      /* L */
    {dn,special,'\134',0},                        /* M */
    {illegal,special,0,0},                        /* N */
    {dn,hi_vowel,260,'\117'},                     /* O */
    {dn,consonant,'\120',12},                     /* P */
    {illegal,special,0,0},                        /* Q */
    {dn,consonant,'\167',0},                      /* R */
    {illegal,special,0,0},                        /* S */
    {dn,consonant,'\124',13},                     /* T */
    {dn,lo_vowel,'\125',1},                       /* U */
    {illegal,special,0,0},                        /* V to Z */
    {illegal,special,0,0},                        /* V to Z */
    {illegal,special,0,0},                        /* V to Z */
    {illegal,special,0,0},                        /* V to Z */
    {illegal,special,0,0},                        /* V to Z */
    {cmr,special,0,0},                            /* [ */
    {control,special,0,0},                        /* \ */
    {cmr,special,0,0},                            /* ] */
    {illegal,special,0,0},                        /* ^ */
    {illegal,special,0,0},                        /* _ */
    {cmr,special,0,0},                            /* ` */
    {dn,hi_vowel,'\141',257},                     /* a */
    {dn,consonant,'\142',14},                     /* b */
    {dn,consonant,'\143',15},                     /* c */
    {dn,consonant,'\144',37},                     /* d */
    {dn,hi_vowel,'\145',3},                       /* e */
    {dn,consonant,'\47',16},                      /* f */
    {dn,consonant,'\147',17},                     /* g */
    {dn,consonant,'\150',38},                     /* h */
    {dn,hi_vowel,'\151','\105'},                  /* i */
    {dn,consonant,'\152',18},                     /* j */
    {dn,consonant,'\153',19},                     /* k */
    {dn,consonant,'\154',20},                     /* l */
    {dn,consonant,'\155',21},                     /* m */
    {dn,consonant,'\156',22},                     /* n */
    {dn,hi_vowel,261,'\157'},                     /* o */
    {dn,consonant,'\160',23},                     /* p */
    {dn,consonant,'\52',24},                      /* q */
    {dn,consonant,'\162',0},                      /* r */
    {dn,consonant,'\163',25},                     /* s */
    {dn,consonant,'\164',26},                     /* t */
    {dn,lo_vowel,'\165',0},                       /* u */
    {dn,consonant,'\166',27},                     /* v */
    {illegal,special,0,0},                        /* not used */
    {illegal,special,0,0},                        /* not used */
    {dn,consonant,'\171',28},                     /* y */
    {dn,consonant,'\51',29},                      /* z */
    {control,special,0,0},                        /* left brace */
    {dn,special,'\56',0},                         /* | */
    {control,special,0,0},                        /* right brace */
    {illegal,special,0,0},                        /* ~ */
    {illegal,special,0,0}};                       /* del */

char chset1[19] = {'k','t','d','o','n','s','r','g',
    'h','a','.','K','T','D','l','L','R','m',' '};
char chset2[4] = {'a','i','u',' '};
char chset3[3] = {'n','s',' '};
char chset4[10] = {'k','g','c','j','t','d','p','b','R',' '};
char chset5[3] = {'A','E','O'};
char chset6[5] = {'n','o','a','r',' '};
struct cons_joins cons_table[77] = {
      {0,0,1,0},			/* 0  */
      {0,0,0,'\27'},                    /* 1 .n */
      {2,100,0,'\11'},                   /* 2 .s */
      {0,0,0,'\34'},                    /* 3 .g */
      {0,0,1,'\7'},                     /* 4 .k */
      {6,94,0,'\133'},                  /* 5 "s */
      {1,88,0,'\74'},                   /* 6 B */
      {2,78,0,'\100'},                  /* 7 D */
      {1,16,0,'\135'},                  /* 8 G */
      {0,0,1,'\44'},                    /* 9 J */
      {0,0,1,'\110'},                   /* 10 K */
      {2,39,1,'\26'},                   /* 11 N */
      {1,115,0,'\45'},                  /* 12 P */
      {0,0,0,'\114'},                   /* 13 T */
      {3,85,0,'\116'},                  /* 14 b */
      {2,34,0,'\121'},                  /* 15 c */
      {1,116,0,'\10'},                  /* 16 f */
      {1,15,0,'\140'},                  /* 17 g */
      {2,37,0,'\76'},                   /* 18 j */
      {9,0,0,'\77'},                    /* 19 k */
      {1,91,0,'\123'},                  /* 20 l */
      {2,89,0,'\115'},                  /* 21 m */
      {1,80,0,'\6'},                    /* 22 n */
      {4,81,0,'\75'},                   /* 23 p */
      {0,0,1,'\12'},                    /* 24 q */
      {2,105,0,'\55'},                  /* 25 s */
      {3,55,0,'\50'},                   /* 26 t */
      {2,92,0,'\46'},                   /* 27 v */
      {0,0,1,'\5'},                     /* 28 y */
      {1,114,0,'\36'},                  /* 29 z */
      {0,0,1,'\20'},			/* 30 L */
      {0,0,1,'\35'},			/* 31 ~r */
      {8,17,1,0},			/* 32 "n */
      {1,36,1,0},			/* 33 C */
      {4,41,1,0},			/* 34 .t */
      {1,45,1,0},			/* 35 .th */
      {6,46,1,0},			/* 36 .d */
      {11,58,2,0},			/* 37 d */
      {7,107,1,0},			/* 38 h */
      {3,9,1,0},			/* 39 k t */
      {1,14,1,0},			/* 40 k v */
      {3,25,1,0},			/* 41 "n k */
      {1,28,1,0},			/* 42 "n kh */
      {1,29,1,0},			/* 43 "n g */
      {2,30,1,0},			/* 44 "n gh */
      {1,32,1,0},			/* 45 "n k t */
      {1,33,1,0},			/* 46 "n k .s */
      {1,52,1,0},			/* 47 .d g */
      {1,53,1,0},			/* 48 .d gh */
      {2,71,2,0},			/* 49 d d */
      {2,73,2,0},			/* 50 d dh */
      {1,75,1,0},			/* 51 d bh */
      {1,77,2,0},			/* 52 d v */
      {3,102,1,0},			/* 53 .s .t */
      {0,0,1,'\43'},			/* 54 k .s */
      {0,0,1,0202},			/* 55 t t */
      {1,117,1,0},			/* 56 .s t r */
      {1,54,1,0},			/* 57 .dh */
      {1,12,1,0},			/* 58 k n */
      {1,13,1,0},			/* 59 k r */
      {0,0,1,0351},			/* 60 g r */
      {0,0,1,0350},			/* 61 gh n */
      {0,0,1,0352},			/* 62 j ~n */
      {0,0,1,0353},			/* 63 ~n c */
      {0,0,1,0354},			/* 64 t r */
      {1,69,1,0},			/* 65 d g */
      {1,70,1,0},			/* 66 d gh */
      {0,0,1,0361},			/* 67 dh n */
      {0,0,1,0362},			/* 68 dh r */
      {0,0,1,0363},			/* 69 p t */
      {0,0,1,0364},			/* 70 "s c */
      {0,0,1,0365},			/* 71 "s r */
      {0,0,1,0366},			/* 72 "s v */
      {1,118,1,0},			/* 73 k t r */
      {1,119,1,0},			/* 74 .d r */
      {1,76,1,0},			/* 75 d r  */
      {0,0,2,0}};			/* 76 d b  */

struct ligs ligtable[120] = {
      {'k',0303,0,TRUE},		/* 0   k k       */
      {'t',0304,39,TRUE},		/* 1   k t       */
      {'n',0307,58,TRUE},	        /* 2   k n       */
      {'m',0311,0,TRUE},		/* 3   k m       */
      {'y',0310,0,TRUE},		/* 4   k y       */
      {'r',0207,59,TRUE},		/* 5   k r       */
      {'l',0312,0,TRUE},		/* 6   k l       */
      {'v',0313,40,TRUE},		/* 7   k v       */
      {6,042,54,TRUE},			/* 8   k .s      */
      {'y',0305,0,TRUE},		/* 9   k t y     */
      {'r',-5,73,TRUE},			/* 10  k t r     */
      {'v',0306,0,TRUE},		/* 11  k t v     */
      {'y',0346,0,TRUE},                /* 12  k n y     */
      {'y',0347,0,TRUE},                /* 13  k r y     */
      {'y',0314,0,TRUE},		/* 14  k v y     */
      {'r',-2,60,TRUE},                 /* 15  g r       */
      {'n',0315,61,TRUE},		/* 16  gh n      */
      {'k',0254,41,TRUE},		/* 17  "n k      */
      {'K',0262,42,TRUE},		/* 18  "n kh     */
      {'g',0275,43,TRUE},		/* 19  "n g      */
      {'G',0277,44,TRUE},		/* 20  "n gh     */
      {18,0274,0,TRUE},			/* 21  "n "n     */
      {'n',0265,0,TRUE},		/* 22  "n n      */
      {'m',0301,0,TRUE},		/* 23  "n m      */
      {'y',0302,0,TRUE},		/* 24  "n y      */
      {'t',0255,45,TRUE},		/* 25  "n k t    */
      {'y',0257,0,TRUE},		/* 26  "n k y    */
      {6,0260,46,TRUE},			/* 27  "n k .s   */
      {'y',0272,0,TRUE},		/* 28  "n kh y   */
      {'y',0276,0,TRUE},		/* 29  "n g y    */
      {'y',0271,0,TRUE},		/* 30  "n gh y   */
      {'r',0300,0,TRUE},		/* 31  "n gh r   */
      {'y',0256,0,TRUE},		/* 32  "n k t y  */
      {'v',0261,0,TRUE},		/* 33  "n k .s v */
      {'c',0316,0,TRUE},		/* 34  c c       */
      {21,0317,0,TRUE},			/* 35  c ~n      */
      {'y',0320,0,TRUE},		/* 36  ch y      */
      {21,0342,62,TRUE},		/* 37  j ~n      */
      {'r',0205,0,TRUE},		/* 38  j r       */
      {'c',0321,63,TRUE},		/* 39  ~n c      */
      {'j',0322,0,TRUE},		/* 40  ~n j      */
      {'k',0326,0,TRUE},		/* 41  .t k      */
      {2,0323,0,TRUE},			/* 42  .t .t     */
      {13,0341,0,TRUE},			/* 43  .t .th    */
      {'y',0324,0,TRUE},		/* 44  .t y      */
      {'y',0325,0,TRUE},		/* 45  .th y     */
      {'g',0263,47,TRUE},		/* 46  .d g      */
      {'G',0264,48,TRUE},		/* 47  .d gh     */
      {3,0345,0,TRUE},			/* 48  .d .d     */
      {'m',0273,0,TRUE},		/* 49  .d m      */
      {'y',0267,0,TRUE},		/* 50  .d y      */
      {'r',-6,74,TRUE},         	/* 51  .d r      */
      {'y',0270,0,TRUE},		/* 52  .d g y    */
      {'r',0266,0,TRUE},		/* 53  .d gh r   */
      {'y',0344,0,TRUE},		/* 54  .dh y     */
      {'t',0201,55,TRUE},		/* 55  t t       */
      {'n',0327,0,TRUE},		/* 56  t n       */
      {'r',057,64,TRUE}, 		/* 57  t r       */
      {'g',0213,65,TRUE},		/* 58  d g       */
      {'G',0212,66,TRUE},		/* 59  d gh      */
      {'d',0214,49,TRUE},		/* 60  d d       */
      {'D',0210,50,TRUE},		/* 61  d dh      */
      {'n',0221,0,TRUE},		/* 62  d n       */
      {'b',0223,76,TRUE},		/* 63  d b       */
      {'B',0211,51,TRUE},		/* 64  d bh      */
      {'m',0224,0,TRUE},		/* 65  d m       */
      {'y',0215,0,TRUE},		/* 66  d y       */
      {'r',-3,75,TRUE},			/* 67  d r       */
      {'v',0222,52,TRUE},		/* 68  d v       */
      {'r',0355,0,TRUE},                /* 69  d g r     */
      {'r',0356,0,TRUE},		/* 70  d gh r    */
      {'y',0220,0,TRUE},		/* 71  d d y     */
      {'v',0370,76,TRUE},               /* 72  d d v     */
      {'y',0217,0,TRUE},		/* 73  d dh y    */
      {'v',0371,0,TRUE},		/* 74  d dh v    */
      {'y',0216,0,TRUE},		/* 75  d bh y    */
      {'y',0357,0,TRUE},		/* 76  d r y     */
      {'y',0225,0,TRUE},		/* 77  d v y     */
      {'n',0360,67,TRUE},               /* 78  dh n      */
      {'r',-4,68,TRUE},                 /* 79  dh r      */
      {'n',0340,0,TRUE},		/* 80  n n       */
      {'t',0330,69,TRUE},		/* 81  p t       */
      {'n',0331,0,TRUE},		/* 82  p n       */
      {'r',0376,0,TRUE},		/* 83  p r       */
      {'l',0332,0,TRUE},		/* 84  p l       */
      {'n',0247,0,TRUE},		/* 85  b n       */
      {'b',0251,0,TRUE},		/* 86  b b       */
      {'v',0333,0,TRUE},		/* 87  b v       */
      {'n',0336,0,TRUE},		/* 88  bh n      */
      {'n',0337,0,TRUE},		/* 89  m n       */
      {'l',0335,0,TRUE},		/* 90  m l       */
      {'l',0245,0,TRUE},		/* 91  l l       */
      {'n',0246,0,TRUE},		/* 92  v n       */
      {'v',0250,0,TRUE},        	/* 93  v v       */
      {'c',0226,70,TRUE},      		/* 94  "s c      */
      {'n',0227,0,TRUE},		/* 95  "s n      */
      {'b',0233,0,TRUE},		/* 96  "s b      */
      {'r',0231,71,TRUE},		/* 97  "s r      */
      {'l',0232,0,TRUE},		/* 98  "s l      */
      {'v',0230,72,TRUE},		/* 99  "s v      */
      {2,0243,53,TRUE},			/* 100  .s .t    */
      {13,0244,0,TRUE},			/* 101 .s .th    */
      {'y',0367,0,TRUE},		/* 102 .s .t y   */
      {'r',-1,56,TRUE},  		/* 103 .s .t r   */
      {'v',0253,0,TRUE},		/* 104 .s .t v   */
      {'n',0334,0,TRUE},		/* 105  s n      */
      {'r',0372,0,TRUE},		/* 106  s r      */
      {5,0242,0,TRUE},			/* 107  h .n     */
      {'n',0241,0,TRUE},		/* 108  h n      */
      {'m',0234,0,TRUE},		/* 109  h m      */
      {'y',0235,0,TRUE},		/* 110  h y      */
      {'r',0240,0,TRUE},		/* 111  h r      */ 
      {'l',0236,0,TRUE},		/* 112  h l      */
      {'v',0237,0,TRUE},		/* 113  h v      */
      {'r',0206,0,TRUE},		/* 114  z r      */
      {'r',0203,0,TRUE},		/* 115  ph r     */
      {'r',0204,0,TRUE},		/* 116  f r      */         
      {'y',0252,0,TRUE}, 		/* 117  .s .t r y */
      {'y',0374,0,TRUE},		/* 118  k t r y  */
      {'y',0373,0,TRUE}};		/* 119  .d r y   */

char out_string[274][7] = {
      "\\7{","\\8{","\\9{","\\?","\\<","^^E","^^F",
       "^^G","^^H","^^I","^^J","^^K","^^L","\\0",
       "\\qx{","^^O","^^P","^^Q","^^R",
       "^^S","^^T","^^U","^^V","^^W","^^X",
       "^^Y","^^Z","^^[","^^\\","^^]",
       "^^^","\\qy{","\\1","!","\"","\\#","\\$",
       "\\%","\\&","\'","(",")","*","+",",","-",".","/","0","1","2",
       "3","4","5","6","7","8","9",":",";","<","=",">","?","@",
       "A","B","C","D","E","F","G","H","I","J","K","L","M","N",
       "O","P","Q","R","S","T","U","V","W","X","Y","Z","[","\\2",
       "]","\\qq{","\\35Fw","`","a","b","c","d","e","f","g","h","i","j",
       "k","l","m","n","o","p","q","r","s","t","u","v","w","x",
       "y","z","\\4","\\qz{","\\5","\\6{","^^?",
       "\\380w","\\381w","\\382w","\\383w","\\384w","\\385w",
       "\\386w","\\387w","\\388w","\\389w","\\38Aw","\\38Bw",
       "\\38Cw","\\38Dw","\\38Ew","\\38Fw","\\390w","\\391w",
       "\\392w","\\393w","\\394w","\\395w","\\396w","\\397w",
       "\\398w","\\399w","\\39Aw","\\39Bw","\\39Cw","\\39Dw",
       "\\39Ew","\\39Fw","\\3A0w","\\3A1w","\\3A2w","\\3A3w",
       "\\3A4w","\\3A5w","\\3A6w","\\3A7w","\\3A8w","\\3A9w",
       "\\3AAw","\\3ABw","\\3ACw","\\3ADw","\\3AEw","\\3AFw",
       "\\3B0w","\\3B1w","\\3B2w","\\3B3w","\\3B4w","\\3B5w",
       "\\3B6w","\\3B7w","\\3B8w","\\3B9w","\\3BAw","\\3BBw",
       "\\3BCw","\\3BDw","\\3BEw","\\3BFw","\\3C0w","\\3C1w",
       "\\3C2w","\\3C3w","\\3C4w","\\3C5w","\\3C6w","\\3C7w",
       "\\3C8w","\\3C9w","\\3CAw","\\3CBw","\\3CCw","\\3CDw",
       "\\3CEw","\\3CFw","\\3D0w","\\3D1w","\\3D2w","\\3D3w",
       "\\3D4w","\\3D5w","\\3D6w","\\3D7w","\\3D8w","\\3D9w",
       "\\3DAw","\\3DBw","\\3DCw","\\3DDw","\\3DEw","\\3DFw",
       "\\3E0w","\\3E1w","\\3E2w","\\3E3w","\\3E4w","\\3E5w",
       "\\3E6w","\\3E7w","\\3E8w","\\3E9w","\\3EAw","\\3EBw",
       "\\3ECw","\\3EDw","\\3EEw","\\3EFw","\\3F0w","\\3F1w",
       "\\3F2w","\\3F3w","\\3F4w","\\3F5w","\\3F6w","\\3F7w",
       "\\3F8w","\\3F9w","\\3FAw","\\3FBw","\\3FCw","\\3FDw",
       "\\3FEw","\\3FFw","{\\rs ","","aA","e\\?",
       "aO","ao","A\\<","\\re}","}","\\rn{",
       "{\\rdt}","aA\\<","{\\qva}","{\\qvb}","{\\qvc}",
       "\\qa{","\\qb{","{"};

short r_ligs[6][2] = {
	{0243,1},		/* .s .t */
	{0147,0},		/* g     */
	{0144,2},		/* d     */
	{0104,0},		/* dh    */
	{0304,1},		/* k t   */
	{0130,1}};		/* .d    */

char *st_find(s,q)
char *s, *q;
{
short i,j,k,l;
    j = strlen(s);
    k = strlen(q);
    for (i=0; i <= j-k; i++) {
      if (s[i]==q[0]) {
        for (l = 1; (s[i + l] == q[l]) && (q[l] != '\0'); l++) ;
        if (q[l] == '\0') return(&s[i]);
      }
    }
    return(NULL);
}

char *ch_find(s,q)
char *s;
char q;
{
short i,j;
    j = strlen(s);
    for (i=0; i < j; i++) 
      if (s[i]==q) return(&s[i]);
    return(NULL);
}

char find_dn()
{
char *d_ptr;
char *dn_ptr;
char *svbuf;
char again;
    d_found = FALSE;
    svbuf = inbuf;
    do {
      again = FALSE;
      dn_ptr = st_find(svbuf,"{\\dn");
      if (dn_ptr != NULL) {
        again = isalpha(dn_ptr[4]);
        svbuf = dn_ptr + 4;
      } 
    } while(again);
    if (dollar_mode) {
      d_ptr = ch_find(inbuf,'$');
      if ((d_ptr != NULL) && ((dn_ptr == NULL) || (d_ptr < dn_ptr))) {
        d_found = TRUE;
        dn_ptr = d_ptr;
      }
    }
    if (dn_ptr == NULL) return(FALSE);
    strncat(outbuf,inbuf,dn_ptr-inbuf);
    no_dn = FALSE;
    if (!d_found) {
      if (dn_ptr[4] == '#') {
        no_dn = TRUE;
        dn_ptr += 1;
      } else strcat(outbuf,"{\\dn");
      dn_ptr += 4;  
    } else {
      switch(dollar_mode) {
        case 1: strcat(outbuf,"{\\dn ");
                break;
        case 2: strcat(outbuf,"\\pdn ");
        case 3: no_dn = TRUE;
      }
      dn_ptr += 1;
    }
    strcpy(inbuf,dn_ptr);
    return(TRUE);
}        
        
expand()
{
short indx;
    indx = -1-syll[chr_ptr-1];
    if (r_ligs[indx][1] != 0) {
      syll[chr_ptr] = r_ligs[indx][0];
      syll[chr_ptr-1] = (r_ligs[indx][1] == 1) ? '\176' : 272;
      syll[chr_ptr+1] = RBRACE;
      chr_ptr = chr_ptr + 2;
    } else {
      syll[chr_ptr-1] = r_ligs[indx][0];
      syll[chr_ptr] = '\175';
      chr_ptr = chr_ptr + 1;
    }
    cons_code = 0;
}

char inp_ch()
{
char ch, ch_out;
    ch = inbuf[buf_ptr++];
    if (ch == '\n') {
      if (p_in == 0) ch_out = end_of_file; else {
        p_in = fgets(inbuf,133,f_in);
        buf_ptr = 0;
        buf_length = strlen(inbuf);
        ch_out = end_of_line;
      }} else {
      if (ch < 32) ch_out = ill_char; else ch_out = ch;
    }
    return(ch_out);
}

err_ill(str)
char *str;
{
    printf("Error: illegal character(s): %s\n",str);
    puts(inbuf);
    getchar();
    error = TRUE;
}

put_macro(macro)
short macro;
{
char tmp[5];
int l,i;
    if (syll[chr_ptr-1] == '\175')
    {
       syll[chr_ptr+1] = '\175';
       syll[chr_ptr] = RBRACE;
       syll[chr_ptr-1] = syll[chr_ptr-2];
       syll[chr_ptr-2] = macro;
       chr_ptr += 2;
     }
     else {
     if (syll[chr_ptr-1]==RBRACE) {
       syll[chr_ptr-3] = 271;
       syll[chr_ptr] = LBRACE;
       sprintf(tmp,"%d",macro);
       l = strlen(tmp);
       chr_ptr += 1;
       for (i = 0; i < l; i++) syll[chr_ptr+i] = tmp[i];
       chr_ptr += l;       
       syll[chr_ptr] = RBRACE;
       chr_ptr += 1;
     }
     else {
       syll[chr_ptr] = syll[chr_ptr-1];
       syll[chr_ptr-1] = macro;
       syll[chr_ptr+1] = RBRACE;
       chr_ptr = chr_ptr +2;
     }}
}

tst_half()
{
    joincode = cons_table[cons_code].j_code;
    if (joincode != 0) {
      half_codes[0] = joincode;
      n_halves = 1;
    } else
    n_halves = 0;
}

put_syll()
{
    for (i = 0; i <= (chr_ptr-1); i++) 
    strcat(word,&out_string[syll[i]][0]);
    if (front_r) {
      if (vow_seen) strcat(word,&out_string[269][0]); else
      strcat(word,&out_string[13][0]);
      front_r = FALSE;
      }
    chr_ptr = 0;
    cons_seen =FALSE;
    vow_seen =FALSE;
    wait_syl = FALSE;
}

put_word()
{
short lw,lb;
    lw = strlen(word);
    lb = strlen(outbuf);
    if (((lb + lw) > 80) && !lin_obey)
    {
    if (lb > 1)
      {
      if (outbuf[lb-1] != ' ') strcat(outbuf,"%\n");
      else
      outbuf[lb-1] = '\n'; 
      fputs(outbuf,f_out);
      }
    while (lw > 80)
      {
      strncpy(outbuf,word,79);
      outbuf[79] = '\0';
      strcat(outbuf,"%\n");
      fputs(outbuf,f_out);
      strcpy(word,&word[79]);
      lw = strlen(word);
      }
    strcpy(outbuf,word);
    }
    else strcat(outbuf,word);
    strcpy(word,"");
}

put_sym(code)
short code;
{
    strcat(word,&out_string[code][0]);
}

sendchar(c)
char c;
{
    cstr[0] = c; cstr[1] = '\0';
    strcat(word,cstr);
    if (isspace(c)) put_word();
}

put_ch(code)
short code;
{
    c_ptr = &table[code-1];
    switch(c_ptr->ch_typ) {
case dn:
      if (cmr_mode)
        {
        cmr_mode = FALSE;
        put_sym(RE);
        } else {
      if (num_mode)
        {
        num_mode = FALSE;
        put_sym(RBRACE);
        }}
      switch(c_ptr->ch_subtyp) {
case hi_vowel:
        if (wait_syl) put_syll();
        if (cons_seen) 
          {
	  if (syll[chr_ptr-1] < 0) expand();
          if (code == 'i')
            {
            for (i = chr_ptr; i>= (cons_ptr+1); i--)
            syll[i] = syll[i-1];
            syll[cons_ptr] = c_ptr->ch_subcode;
            }
          else {
            syll[chr_ptr] = c_ptr->ch_subcode;
            if ((code != 'A') && (code != 'a')) vow_seen = TRUE;
            }
          }
        else syll[chr_ptr] = c_ptr->ch_code;
        chr_ptr = chr_ptr + 1;
        wait_syl = TRUE;
	cons_seen = FALSE;
        break;
case lo_vowel:
        if (wait_syl) put_syll();
        if (cons_seen) 
          {
          if (syll[chr_ptr-1] < 0) expand();
          if ((syll[chr_ptr-1] == 'r') && (code == 'u'))
          syll[--chr_ptr] = 'z';
            else {if ((syll[chr_ptr-1] == 'r') && (code == 'U'))
            syll[--chr_ptr] = '!';
	      else {if ((syll[chr_ptr-1] == 'h') && (code == 7))
              syll[--chr_ptr] = 0343;
                else {if ((syll[chr_ptr-1] == 'r') && ((code == 7) 
                  || (code == 17))) {
                    syll[--chr_ptr] = c_ptr->ch_code;
                    front_r = TRUE;
		  }
                  else {
                  put_macro(c_ptr->ch_subcode);
                  chr_ptr = chr_ptr - 1;
                  }
               } 
	     }
           }
         }
        else syll[chr_ptr] = c_ptr->ch_code;
        chr_ptr = chr_ptr + 1;
        wait_syl = TRUE;
	cons_seen = FALSE;
	break;
case consonant:
        if (wait_syl) put_syll();
        if (!cons_seen)
          {
          cons_seen = TRUE;
          cons_ptr = chr_ptr;
          cons_code = c_ptr->ch_subcode;
          syll[chr_ptr] = c_ptr->ch_code;
          chr_ptr += 1;
	  tst_half();
          }
        else {q_ptr = &cons_table[cons_code];
          if (syll[cons_ptr] == 'r')
            {
            front_r = TRUE;
            syll[chr_ptr-1] = c_ptr->ch_code;
            cons_code = c_ptr->ch_subcode;
	    tst_half();
            }
          else {i = q_ptr->lig_code;
            for (j = i + (q_ptr->n_ligs); i != j; i++) {
              if (ligtable[i].sym_code == code) break;
            }
            if ((i != j) && (ligtable[i].in_use)) 
            {
            syll[chr_ptr-1] = ligtable[i].sym_new;
            cons_code = ligtable[i].join_ptr;
	    joincode = cons_table[cons_code].j_code;
	    if (joincode != 0) {
              half_codes[0] = joincode;
	      n_halves = 1;
            } else {
              joincode = cons_table[c_ptr->ch_subcode].j_code;
	      if ((joincode != 0) && (n_halves != 0)) {
                half_codes[n_halves] = joincode;
                n_halves += 1;
              } else n_halves = 0;
            }
            }
          else {if (code == 'r') {
            if (q_ptr->r_type != 0) {
              syll[chr_ptr] = syll[chr_ptr-1];
              syll[chr_ptr-1] = (q_ptr->r_type == 1) ? '\176' : 272;
              syll[chr_ptr+1] = RBRACE;
              chr_ptr = chr_ptr+2;
              }
            else
              {
              syll[chr_ptr] = '\175';
              chr_ptr = chr_ptr + 1;
              n_halves = 0;
              }
            cons_code = 0;
            }
          else {
            if (q_ptr->j_code != 0) {
            syll[chr_ptr-1] = q_ptr->j_code;
            syll[chr_ptr] = c_ptr->ch_code;
            cons_code = c_ptr->ch_subcode;
            chr_ptr += 1;
	    tst_half();
            } else {
	     if (n_halves != 0) {
	       for (i=0; i<n_halves; i++)
	       syll[chr_ptr-1+i] = half_codes[i];
	       chr_ptr = chr_ptr + n_halves;
	       syll[chr_ptr-1] = c_ptr->ch_code;
	       cons_code = c_ptr->ch_subcode;
	       tst_half();
             } else
            {
	    if (syll[chr_ptr-1] < 0) expand();
            put_macro(VIRAAM);
            cons_code = c_ptr->ch_subcode;
            syll[chr_ptr] = c_ptr->ch_code;
            chr_ptr += 1;
            tst_half();
            }}}}}}
            break;

case special:
	  if (cons_seen) { if (syll[chr_ptr-1] < 0) expand();}
          if ((code == 'M') && front_r) {
            front_r = FALSE;
            if (vow_seen) syll[chr_ptr] = 270;
            else syll[chr_ptr] = RDT;
            chr_ptr = chr_ptr +1;
            put_syll();} else {
          if ((code =='M') && (syll[chr_ptr-1] == 'I')) {
            syll[chr_ptr-1] = 18;
            put_syll();
          } else {
          if ((code == 'M') && vow_seen) {
            syll[chr_ptr] = 268;
            chr_ptr = chr_ptr +1;
            put_syll();} else {
          if (code == '&') {
            if(!cons_seen) err_ill("&"); else {
	    put_macro(VIRAAM);
            put_syll();
          }} else {
	  if (!hindi_mode && cons_seen) put_macro(VIRAAM);
          put_syll();
          put_sym(c_ptr->ch_code);
          }}}}}
          break;

case illegal:
          cstr[0] = code; cstr[1] = '\0';
          err_ill(cstr);
          break;

case control:
        if (cmr_mode) {
          cmr_mode = FALSE;
          put_sym(RE);
          } else {
        if (num_mode) {
          num_mode = FALSE;
          put_sym(RBRACE);
          } else {
	if (cons_seen) {if (syll[chr_ptr-1] < 0) expand();}
	if (!hindi_mode && cons_seen) put_macro(VIRAAM);
        put_syll();
	}}
        if (code == end_of_line) {
          put_word();
          strcat(outbuf,"\n");
          fputs(outbuf,f_out);
          strcpy(outbuf,"");
          if (!lin_obey) fputs("\n",f_out);
          }
        else if (code != dummy) sendchar(code);
        break;

case cmr:    if (cmr_mode) sendchar(code); else {
        cmr_mode = TRUE;
        if (num_mode) {
        num_mode = FALSE;
        put_sym(RBRACE);
        } else {
	if (cons_seen) {if (syll[chr_ptr-1] < 0) expand();}
	if (!hindi_mode && cons_seen) put_macro(VIRAAM);
	put_syll();
	}
        put_sym(RS);
        sendchar(code);
        }
        break;

case numeral: if (num_mode) sendchar(code); else {
        num_mode = TRUE;
        if (cmr_mode) {
        cmr_mode = FALSE;
        put_sym(RE);
        } else {
	if (cons_seen) {if (syll[chr_ptr-1] < 0) expand();}
	if (!hindi_mode && cons_seen) put_macro(VIRAAM);
	put_syll();
	}
        put_sym(RN);
        sendchar(code);
        }
      }
}

dnproc()
{
unsigned char saved,dnready;
short brace_lev;
char savchr;
    brace_lev = 1;
    saved = FALSE;
    dnready = FALSE;
    do {
    switch(symbol) {
case '.':
      savchr = inp_ch();
      i = 0;
      do {i++;}
      while ((i != 19) && (chset1[i-1] != savchr));
      if (i == 19) {wrong[0] = '.'; wrong[1] = savchr;
      wrong[2] = '\0'; err_ill(wrong);} else {
      if (i < 4) {
        savchr = inp_ch();
        if (savchr == 'h')  i = i+11; else saved = TRUE;
        if (i == 1)  err_ill(".k");
      }}
      if (!error){
        if (i == 18) put_ch('M'); else put_ch(i);
      }
      break;
case 'i':
      savchr = inp_ch();
      if (savchr == 'i')  put_ch('I'); else {
        put_ch(symbol);
        saved = TRUE;
      }
      break;
case 'u':
      savchr = inp_ch();
      if (savchr == 'u') put_ch('U'); else {
        put_ch(symbol);
        saved = TRUE;
      }
      break;
case 'a':
      savchr = inp_ch();
      i = 0;
      do {i++;}
      while ((i != 4) && (chset2[i-1] != savchr));
      if (i == 4)
      {
      put_ch(symbol);
      saved = TRUE;
      } else put_ch(chset5[i-1]);
      break;

case '\"':
      savchr = inp_ch();
      i = 0;
      do {i++;}
      while ((i != 3) && (chset3[i-1] != savchr));
      if (i == 3) {wrong[0] = '\"'; wrong[1] = savchr; wrong[2] = '\0';
      err_ill(wrong);} else put_ch(i+17);
      break;

case '~':
      savchr = inp_ch();
      i = 0;
      do {i++;}
      while ((i != 5) && (chset6[i-1] != savchr));
      if (i == 5) {wrong[0] = '~'; wrong[1] = savchr; wrong[2] = '\0';
      err_ill(wrong);} else put_ch(i+20);
      break;

case end_of_line:
      if (lin_obey) put_ch(end_of_line);
      else {
        do {savchr = inp_ch();}
	while (savchr == ' ');
        if (savchr == end_of_line)
        put_ch(end_of_line); else {
          put_ch(' ');
          saved = TRUE;
        }
      }
      break;

case '$':
      if (!dollar_mode) put_ch(symbol); else {
        if (no_dn) put_ch(dummy); else put_ch('}');
        dnready= TRUE;
        put_word();
        strcpy(inbuf,&inbuf[buf_ptr]);
      }
      break;

case '}':
      brace_lev = brace_lev-1;
      if ((brace_lev == 0) && !d_found) {
        if (no_dn) put_ch(dummy); else put_ch(symbol);
        dnready= TRUE;
        put_word();
        strcpy(inbuf,&inbuf[buf_ptr]);
      } else put_ch(symbol);
      break;

case '{':
      put_ch(symbol);
      brace_lev = brace_lev+1;
      break;

case '%':  do
      symbol = inp_ch();
      while(symbol != end_of_line);
      break;

case '\\':
      put_ch(symbol);
      symbol = inp_ch();
      if (symbol == end_of_line) {
          put_word();
          strcat(outbuf,"\n");
          fputs(outbuf,f_out);
          strcpy(outbuf,"");
      }
      else {
        if (!isalpha(symbol)) sendchar(symbol); else {
          do {
            sendchar(symbol);
            symbol = inp_ch();
          } while (isalpha(symbol));
          savchr = symbol;
          saved = TRUE;
        }
      }
      break;

case ill_char: err_ill('\0');
      break;

case end_of_file:
       puts("error: missing }");
       error = TRUE;
       break;

default:
       i = 0;
       do {i++;}
       while ((i != 10) && (chset4[i-1] != symbol));
       if (i == 10) put_ch(symbol); else {
       savchr = inp_ch();
       if (savchr == 'h') {
         if (i == 9)  put_ch(20); else put_ch(symbol-32);
         }
       else {
         put_ch(symbol);
         saved = TRUE;
         }
       }}
     if (saved) {
       symbol = savchr;
       saved = FALSE;
       } else {
     if ((!error) && (!dnready)) symbol = inp_ch(); }
     } while (!error && !dnready);
}

main(argc,argv)
int argc;
char *argv[];
{
/* get file specifications */

    if (argc == 3) {
    strcpy(infil,argv[1]);
    strcpy(outfil,argv[2]);
    } else {
    if (argc == 2) {
    strcpy(infil,argv[1]);
    strcpy(outfil,"");
    } else {
    do {
    printf("input file: ");
    gets(infil);
    }
    while (strlen(infil) == 0);
    printf("output file: ");
    gets(outfil);
    }}
    s_ptr = strchr(infil,'.');
    if (strlen(outfil) == 0) {strcpy(outfil,infil);
    o_ptr = strchr(outfil,'.');
    if (o_ptr != 0) *o_ptr = '\0';
    }
    if (s_ptr == 0) strcat(infil,".dn");
    o_ptr = strchr(outfil,'.');
    if (o_ptr == 0) strcat(outfil,".tex");

/* open files */

    if ((f_in = fopen(infil,"r")) == NULL) {
      printf("cannot open file %s\n",infil);
      exit(1);
    }
    f_out = fopen(outfil,"w");

/* initialization */

    error = FALSE;
    cons_seen = FALSE;
    vow_seen = FALSE;
    front_r = FALSE;
    wait_syl = FALSE;
    cmr_mode = FALSE;
    num_mode = FALSE;
    hindi_mode = FALSE;
    lin_obey = FALSE;
    dollar_mode = 0;
    chr_ptr = 0;
    strcpy(word,"");
    strcpy(outbuf,"");

/* read preprocessor commands */

    while (TRUE) {
    strcpy(inbuf,"");
    p_in = fgets(inbuf,133,f_in);
    if (inbuf[0] != '@') break;
      while (TRUE) {
      if (st_find(inbuf,"dollars") == &inbuf[1]) {
        dollar_mode = 1; break;}
      if (st_find(inbuf,"hindi") == &inbuf[1]) {
        hindi_mode = TRUE;
        ligtable[37].sym_new = 053;
        ligtable[37].join_ptr = 0;
        ligtable[96].sym_new = 0200;
        ligtable[96].join_ptr = 0;
        for (i=0; i < n_noligs; i++) 
        ligtable[nolig[i]].in_use = FALSE;
        break;}
      if (st_find(inbuf,"nolig") == &inbuf[1]) { 
        s_ptr = inbuf;
        while (TRUE) {
          if ((s_ptr = ch_find(s_ptr,' ')) == NULL) break;
          s_ptr++;
          if (sscanf(s_ptr,"%d",&number) != 0) 
          ligtable[ligptrs[number-1]].in_use = FALSE;
        }
        break;}
      if (st_find(inbuf,"lig") == &inbuf[1]) {
        s_ptr = inbuf;
        while (TRUE) {
          if ((s_ptr = ch_find(s_ptr,' ')) == NULL) break;
          s_ptr++;
          if (sscanf(s_ptr,"%d",&number) != 0) 
          ligtable[ligptrs[number-1]].in_use = TRUE;
          }
        break;}
      if (st_find(inbuf,"obeylines") == &inbuf[1]) {
        lin_obey = TRUE; break;}
      if (st_find(inbuf,"dolmode1") == &inbuf[1]) {
        dollar_mode = 1; break;}  
      if (st_find(inbuf,"dolmode2") == &inbuf[1]) {
        dollar_mode = 2; break;}  
      if (st_find(inbuf,"dolmode3") == &inbuf[1]) {
        dollar_mode = 3; break;}  
      printf("Error: illegal preprocessor command\n");
      puts(inbuf);
      getchar();
      break;
      }
    }
 
/* main loop */

     do {
       if (!find_dn()) fputs(inbuf,f_out);
       else do {
         buf_length = strlen(inbuf);
         buf_ptr = 0;
         symbol = inp_ch();
         dnproc();
         if (!error) dn_yes = find_dn();
         if (!dn_yes) {
           strcat(outbuf,inbuf);
           fputs(outbuf,f_out);
         }
       } while (dn_yes && !error);
     strcpy(inbuf,"");
     p_in = fgets(inbuf,133,f_in);
     strcpy(outbuf,"");
     } while ((p_in != NULL) && !error);
     fclose(f_in);
     fclose(f_out);
}
