/***************************************************************************/
/* */
/* GRMK.C */
/* */
/* Source code for "Gurmukhi for LaTeX" preprocessor. */
/* */
/* Based on Revision 1.1 1996/03/05 of skt.c preprocessor developed by */
/* Charles Wikner <
[email protected]> */
/* */
/* Modifications to original source for Gurmukhi preprocessor made by */
/* Anshuman Pandey <
[email protected]>, 1999/02/24 */
/* */
/***************************************************************************/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
/* DECLARE FUNCTIONS */
void exit (int);
void search (void);
void write_outbuf(void);
void write_line (char *);
char * str_find (char *, char *);
void getline (void);
char * command (char *);
void error (char *, int);
void process (void);
void chrcat (char *, char);
void sktcont (void);
void sktword (void);
void single (char);
void frontac (void);
void sam_warning (void);
void backac (void);
void samyoga (void);
FILE *infile, *outfile, *fopen();
char infilename[80];
char outfilename[80];
#define TRUE 1
#define FALSE 0
unsigned char sktline; /* flag TRUE if there is any sanskrit on this line */
unsigned char sktmode; /* flag TRUE while within {\gm } */
unsigned char eof_flag; /* flag True when end of file detected */
unsigned char ac_flag; /* flag TRUE while processing skt vowels */
unsigned char roman_flag; /* flag TRUE if previous output was Roman string */
int nest_cnt; /* '{' increments, '}' decrements, while in \gm */
int err_cnt; /* incremented by any error while in \gm */
#define err_max 10 /* after err_max errors, program aborts */
int line_cnt; /* line number of current input line */
char inbuf[133]; /* input file line buffer of text being processed */
char *i_ptr; /* general pointer to input buffer */
char outbuf[512]; /* output file line buffer of text processed */
char *o_ptr; /* general pointer to output buffer */
unsigned char cont_end; /* flag TRUE when line ends with %-continuation */
unsigned char cont_begin; /* flag TRUE when line begins after %-continuation */
unsigned char hal_flag; /* flag TRUE when hal_type detected in syllable */
unsigned char accent; /* storage for working accent character */
unsigned char ac_char; /* storage for working vowel character */
char sktbuf[255]; /* storage for sanskrit in internal code */
char *s_ptr; /* general pointer to sanskrit buffer */
char *old_sptr; /* points to samyoga start; used by warning message */
char work[80]; /* general scratchpad */
char *w_ptr; /* general pointer to work buffer */
char tmp[80]; /* temporary buffer for previous syllable */
int virama; /* flag to add viraama to samyoga (i.e. no vowel) */
int hr_flag; /* flag indicates vowel picked up in samyoga (h.r) */
/***************************************************************************/
/* Function: main() */
/***************************************************************************/
main(argc,argv)
int argc;
char *argv[];
{ char *p; int k;
/* Initialization */
sktmode = eof_flag = FALSE;
nest_cnt = err_cnt = 0;
line_cnt = 0;
i_ptr = inbuf; *i_ptr = '\0';
s_ptr = sktbuf; *s_ptr = '\0';
o_ptr = outbuf; *o_ptr = '\0';
/* handle command-line options */
k=0;
if (argc>1) strcpy(infilename,argv[1]);
if (strcmp(infilename,"-h")==0)
{ k=1;
strcpy(infilename,"");
printf("Gurmukhi for TeX, v1.0, 1999.03.02\n");
printf("Anshuman Pandey <
[email protected]>\n");
printf("Syntax: grmk infile[.gm] [outfile.tex]\n");
exit(0);
}
/* then get file names */
switch(argc-k)
{ case 3: strcpy(infilename,argv[1+k]);
strcpy(outfilename,argv[2+k]);
break;
case 2: strcpy(infilename,argv[1+k]);
strcpy(outfilename,"");
break;
default: strcpy(infilename,"");
while(strlen(infilename) == 0)
{ printf("Input file: "); gets(infilename); }
printf("Output file: ");
gets(outfilename);
}
if (strlen(outfilename) == 0)
{ strcpy (outfilename,infilename); /* default output file name */
p = strchr(outfilename,'.');
if (p != 0) *p = '\0'; /* delete out file name extension */
}
p = strchr(infilename,'.');
if (p == 0) strcat(infilename,".gm"); /* default input file extension */
if ((infile=fopen(infilename,"r")) == NULL)
{ printf("Cannot open file %s\n",infilename); exit(1); }
getline(); if (eof_flag)
{ printf("Input file %s is empty.\n",infilename); exit(1); }
p = strchr(outfilename,'.');
if (p == 0)
{ if (inbuf[0] == '@') strcat(outfilename,".dn");
else strcat(outfilename,".tex"); /* set default output file extension */
}
if ((outfile=fopen(outfilename,"w")) == NULL)
{ printf("Cannot open output file %s\n",outfilename); exit(1); }
/* Normal main loop */
while(eof_flag == 0)
{ while(!sktmode && !eof_flag) search(); /* search for \gm command */
while( sktmode && !eof_flag) process(); /* process bengali text */
if (err_cnt >= err_max)
{ printf("Too many (%d) errors, aborting program\n",err_cnt); break; }
}
if ((err_cnt < err_max) && (nest_cnt != 0))
printf("Brace mismatch within \\gm = %d\n",nest_cnt);
fclose(infile);
fclose(outfile);
exit(1);
}
/***************************************************************************/
/* Function: search() */
/* */
/* Search inbuf for '{\gm', getting more input lines as necessary */
/* until string found or end of file, copying input to output; if */
/* the string is found but command not recognised, it is treated as */
/* ordinary text; if valid command i_ptr points to first sanskrit */
/* char after command, and sets sktmode TRUE. */
/***************************************************************************/
void search(void)
{
unsigned char c;
char *p,*q;
while (eof_flag == 0)
{ p = str_find(i_ptr,"{\\gm");
if (p == 0)
{ if (sktline == TRUE) { strcat(outbuf,i_ptr); write_outbuf(); }
else { write_line(inbuf); o_ptr = outbuf; *o_ptr = '\0'; }
getline();
continue;
}
q = i_ptr; i_ptr = p;
if ((p = command(p)) == 0) /* test command string \gm */
{ p = i_ptr; i_ptr = q; /* if bad \gm command */
c = *++p; *p = '\0'; /* copy partial line, and search more */
strcat(outbuf,i_ptr); *p = c; i_ptr = p; continue;
}
i_ptr = q;
nest_cnt++; c = *p; *p = '\0'; /* skip over '{\gm' */
strcat(outbuf,i_ptr); /* append partial line to outbuf */
*p = c; i_ptr = p;
sktmode = TRUE; sktline = TRUE; /* now comes the fun! */
break;
}
}
/***************************************************************************/
/* Function: write_outbuf() */
/* */
/* Write outbuf in 80 character lines */
/***************************************************************************/
void write_outbuf(void)
{
char c, d, e;
while(1)
{ c = '\0';
if (strlen(outbuf) < 81) { write_line(outbuf); break; }
for (o_ptr = outbuf + 78; o_ptr > outbuf + 50; o_ptr--)
{ if (*o_ptr == ' ') break; }
if (*o_ptr != ' ') { for (o_ptr = outbuf+78; o_ptr > outbuf + 50; o_ptr--)
if ((*o_ptr=='\\') && (*(o_ptr-1)!='\\')) break;
if (o_ptr == outbuf+50) o_ptr = outbuf+78;
c = *o_ptr; *o_ptr++ = '%'; d = *o_ptr;
}
*o_ptr++ = '\n'; e = *o_ptr; *o_ptr = '\0';
write_line(outbuf);
*o_ptr = e;
if (c!='\0') { *--o_ptr = d; *--o_ptr = c; } /* restore displaced chars */
strcpy(outbuf,o_ptr);
}
o_ptr = outbuf;
*o_ptr = '\0';
}
/***************************************************************************/
/* Function: write_line() */
/* */
/* Write p-string to output device */
/***************************************************************************/
void write_line(char *p)
{
if (err_cnt == 0) fputs(p,outfile);
}
/***************************************************************************/
/* Function: str_find() */
/* */
/* Find first occasion of string *str within *buf before '%' char; */
/* return pointer first char of str within buf, else 0. */
/***************************************************************************/
char * str_find(char *buf, char *str)
{ char *p, *x;
p = strstr(buf,str);
if (p == 0) return(0);
x = strchr(buf,'%');
if ((x != 0) && (p > x)) return(0);
return(p);
}
/***************************************************************************/
/* Function: getline() */
/* */
/* Get another line from input file; reset i_ptr, increments */
/* line_cnt, and sets eof_flag if EOF. */
/***************************************************************************/
void getline(void)
{
char *p;
i_ptr = inbuf;
*i_ptr = '\0';
line_cnt++;
if (fgets(inbuf,133,infile) == NULL) eof_flag = TRUE;
if (sktmode == FALSE) sktline = FALSE;
}
/***************************************************************************/
/* Function: command() */
/* */
/* Check for valid \gm command; if invalid command, print error message */
/***************************************************************************/
char * command(char *p)
{ p += 4; /* skip over '{\gm' */
if (*p++ != ' ') p = 0;
if (p == 0) error("Unrecognised command string",7);
return(p);
}
/***************************************************************************/
/* Function: error() */
/* */
/* Print out error message, including string *s and 'n' characters */
/* of inbuf. */
/***************************************************************************/
void error(char *s, int n)
{ char err_str[80]; int j;
if (++err_cnt <= err_max)
{ if (n > 0) { for (j=0; j<n; j++) err_str[j] = *(i_ptr+j);
err_str[j] = '\0';
}
if (n == 0) { strcpy(err_str,"oct(");
chrcat(err_str,'0' + (*i_ptr/64));
chrcat(err_str,'0' + (*i_ptr/8));
chrcat(err_str,'0' + (*i_ptr & 7));
strcat(err_str,")");
}
if (n < 0) { err_str[0] = '\0'; }
}
printf("Line %4d Error: %s %s\n",line_cnt,s,err_str);
}
/***************************************************************************/
/* Function: process() */
/* */
/* Process input text within {\gm, converting to internal format in sktbuf */
/***************************************************************************/
#define ISAC(c) (((strchr("aAiIuUeEoO",c) != 0) && c) ? TRUE : FALSE)
/* wWX removed from the definition of ISAC above (.R .l .L) */
void process(void)
{ int cap_flag, underscore;
unsigned char *i, c, d;
#define CF ac_flag=underscore=cap_flag=roman_flag=FALSE
#define CC CF; continue
#define CR ac_flag=underscore=cap_flag=FALSE;
#define CI i_ptr++; CC
CF;
while(1)
{ if (eof_flag) return;
if (err_cnt >= err_max)
{ sktmode = FALSE; return; }
c = *i_ptr; d = *(i_ptr+1);
/* END OF LINE */
if ((c == '\0') || (c == '\n'))
{ sktword(); strcat (outbuf,i_ptr); write_outbuf(); getline(); CC; }
/* IMBEDDED ROMAN */
/* if (strchr("!'()*+,-/:;=?[]`",c) || ((c == '.') && (*(i_ptr+1) == '.')))
{ if (c == '.') i_ptr++;
if (sktbuf[0]) { sktword(); }
while(1) */
if (strchr("!'()*+,-/:;=?[]`",c))
{ if (sktbuf[0]) { sktword(); }
while(1)
{ chrcat(outbuf,c); c = *++i_ptr;
if (c == '.')
{ if (*(i_ptr+1) != '.') break;
i_ptr++; continue;
}
if ((strchr("!'()*+,-/:;=?[]`",c) && c) == 0) break;
}
CR; continue;
}
/* ILLEGAL CHARS */
if (strchr("_$qwxBCDEFJLNOPQSVWXYZ\177",c))
{ error("Illegal Gurmukhi character: ",1); CI; }
if (c>127) { error("Invalid character >80H: ",1); CI; }
/*?? Since we are now case sensitive (unlike skt), the list of */
/*?? illegal chars has been increased (_ added, and & removed) */
/* CONTROL CHARACTERS */
if (c < ' ')
{ error("Illegal control character: ",0); CI; }
/* IMBEDDED LATEX COMMAND STRINGS */
if (c == '\\')
{ if (d == '-') /* imbedded discretionary hyphen */
{ strcat(sktbuf,"!"); i_ptr++; CI; }
sktword();
if (isalpha(d) == 0)
{ chrcat(outbuf,c); chrcat(outbuf,*++i_ptr); CI; }
else
{ while (1)
{ chrcat(outbuf,c); c = *++i_ptr; if (isalpha(c) == 0) break; }
}
CC;
}
/* SPACE CHAR */
if (c == ' ')
{ sktword(); while(*++i_ptr == ' '); chrcat(outbuf,c); CC;
}
/*?? slight change here, since underscore is now an illegal character */
/* COMMENT DELIMITER */
if (c == '%')
{ if (*(i_ptr+1) == '\n') sktcont();
else sktword();
strcat(outbuf,i_ptr); write_outbuf(); getline(); CC;
}
/* BRACES */
if (c == '{') { if (d == '}') { i_ptr++; CI; } /* for words like pra{}uga */
else { nest_cnt++; sktcont(); chrcat(outbuf,c); CI; }
}
if (c == '}')
{ sktword(); chrcat(outbuf,c);
if (--nest_cnt == 0)
{ sktmode = FALSE;
i_ptr++; return;
}
else CI;
}
/* UPPER CASE */
if (isupper(c))
{ switch (c)
{ case 'A':
case 'I':
case 'U':
case 'H': break;
case 'M': c = '\\'; break;
case 'K': c = 'L'; break;
case 'R': c = 'w'; break;
case 'G': c = 'W'; break;
default: c = '*'; break;
}
if (c=='*') { error("Invalid upper case: ",1); CI; }
}
/*?? big change with that code: the upper case has a different *meaning* than */
/*?? the lower case: fortunately, AIUMH are the same as the internal code :-) */
/* DOT_CHAR */
if (c == '.') { switch(d)
{ case 'd': c = 'q'; break;
case 'h': c = 'H'; break;
case 'm': c = 'M'; break;
case 'n': c = 'N'; break;
case 'o': c = '%'; break;
case 't': c = 'x'; break;
case '.': c = '@'; break;
case ' ': c = '|'; break; /* following space */
case '\\': c = '|'; break; /* following LaTeX command */
case '}': c = '|'; break; /* following brace */
case '\0': c = '|'; break; /* end of line */
case '\n': c = '|'; break; /* end of line */
}
if (c=='.') { error("Invalid dot_character: ",2); CI; }
if (c!='|') { i_ptr++; d = *(i_ptr+1);}
}
/* NEXT CHAR IS H */
if (d=='h')
{ if (strchr("bcdgjkptqx",c)) { c=toupper(c); i_ptr++; d=*(i_ptr+1); }
}
/* The upper/lowercase stuff removed: a following 'h' converts a consonant */
/* to its upper case internal code, e.g th --> T. Note that 'w' is added */
/* to the list for R Rh */
/* QUOTE CHAR */
if (c == '\"') { switch(d)
{ case 'n': c = 'Y'; break;
case 's': c = 'Z'; break;
}
if (c=='\"') { error("Invalid quote_character",2); CI; }
i_ptr++; d = *(i_ptr+1);
}
/*?? "d and "h removed */
/* TILDE CHAR */
if (c == '~') { switch (d)
{ case 'n': c = 'V'; break;
default : c = '*'; break;
}
if (c=='*')
{ error("Invalid use of tilde character: ",2); CI; }
i_ptr++; d = *(i_ptr+1);
}
/* TWO CHAR VOWELS */
if ( strchr("aiu",c) && strchr("aiu",d) )
{ switch(c)
{ case 'a': switch(d)
{ case 'a': c = 'A'; break;
case 'i': c = 'E'; break;
case 'u': c = 'O'; break;
} break;
case 'i': if (d=='i') c = 'I'; break;
case 'u': if (d=='u') c = 'U'; break;
}
if (isupper(c)) { i_ptr++; d = *(i_ptr+1); }
}
/*?? all the upper/lowercase stuff removed */
/* NOW CHAR SHOULD BE INTERNAL REPRESENTATION OF SANSKRIT CHAR */
if ( ((c=='\\' || c=='M') && !(ac_flag)) ) {
i_ptr -=2; error("No vowel before nasal: ",3); i_ptr +=2; CF;
}
if (c=='H' && !(ac_flag)) {
i_ptr -=2; error("No vowel before visarga: ",3); i_ptr +=2; CF;
}
chrcat(sktbuf,c);
CR;
if (ISAC(c)) ac_flag = TRUE;
i_ptr++;
}
}
/*?? all the tests for (semi-)vowel nasalization and accents removed */
#undef CI;
#undef CC;
#undef CR;
#undef CF;
/***************************************************************************/
/* Function: chrcat() */
/* */
/* Append character c to end of buffer s */
/***************************************************************************/
void chrcat(char *s, char c)
{ char temp[] = " "; temp[0] = c; strcat(s,temp);
}
/***************************************************************************/
/* Function: sktcont() */
/* */
/* Similar to sktword() but used where input text line ends in '%' to */
/* cotinue on next line. */
/***************************************************************************/
void sktcont(void)
{
cont_end = TRUE; sktword();
cont_end = FALSE; cont_begin = TRUE;
}
/***************************************************************************/
/* Function: sktword() */
/* */
/* Convert contents of sktbuf to output string in outbuf */
/***************************************************************************/
/* internal code for consonants */
static char hal_chars[] = "BCDGJKLNPQRTVWXYZbcdfghjklmnpqrstvwxyz";
#define ISHAL(c) (((strchr(hal_chars,c) != 0) && c) ? TRUE : FALSE)
#define CLRFLAGS virama=hal_flag=0
#define CAT(w,x,z) \
strcat(w,x); strcat(w,z)
void sktword(void)
{ char c;
if (roman_flag && sktbuf[0]) { strcat(outbuf,"\\,"); roman_flag = FALSE; }
/* A word is built up one syllable at a time: a syllable typically comprises */
/* a consonant (or samyoga) followed by a vowel (with its nasalisation and */
/* accents). If there is no consonant, then a front-vowel is output; if there */
/* is no vowel, then a viraama is appended to the consonant/samyoga. */
/* One effect of this is that, if a consonant cluster is not fully resolved */
/* into a single samyoga, it will be treated as two syllable: in particular, */
/* the hook of the short-i will span one samyoga only. */
/* */
/* The `work' buffer is used as a scratchpad while building a syllable; on */
/* completion it is stored in the `tmp' buffer before shipping to the output */
/* buffer. This temporary storage while working on the next syllable, allows */
/* changes to the back spacing of the previous syllable for more effiecient */
/* output. */
CLRFLAGS;
s_ptr = sktbuf; c = *s_ptr;
if (c == '\0') return;
*tmp = '\0'; *work = '\0';
while (1)
{ CLRFLAGS; /* in particular, need to clear hal_flag for the likes of kara */
c= *s_ptr++;
if (c == '\0')
{ if (*tmp) { if (outbuf[0]=='\0' && tmp[0]=='[') strcat(outbuf,"{}");
strcat(outbuf,tmp);
}
break;
}
if (ISAC(c))
{ ac_char = c;
frontac();
if (*tmp) { if (outbuf[0]=='\0' && tmp[0]=='[') strcat(outbuf,"{}");
strcat(outbuf,tmp);
}
strcpy(tmp,work);
*work = '\0'; cont_begin = 0;
continue;
}
if (strchr("0123456789\"!%|\\@~HM",c))
{ single(c);
if (*tmp) { if (outbuf[0]=='\0' && tmp[0]=='[') strcat(outbuf,"{}");
strcat(outbuf,tmp);
}
strcpy(tmp,work);
*work = '\0'; cont_begin = 0;
continue;
}
s_ptr--;
old_sptr = s_ptr; /* save pointer to start of samyoga */
if (ISHAL(c)) { hal_flag = TRUE; samyoga(); c = *s_ptr; }
ac_char = virama = 0;
if (!hr_flag) { if (ISAC(c)) { ac_char = *s_ptr++; }
else virama = TRUE; /* hr_flag = h.r parsed by samyoga */
}
backac(); hr_flag = FALSE;
if (*tmp) { if (outbuf[0]=='\0' && tmp[0]=='[') strcat(outbuf,"{}");
strcat(outbuf,tmp);
}
strcpy(tmp,work);
*work = '\0'; cont_begin = FALSE;
}
strcat(outbuf,work);
s_ptr = sktbuf; *s_ptr = '\0';
cont_begin = 0;
}
/***************************************************************************/
/* Function: single() */
/* */
/* Output single (stand-alone) character to work buffer */
/***************************************************************************/
void single(char c)
{
switch(c)
{ case '0': strcat(work,"0"); break; /* numerals */
case '1': strcat(work,"1"); break;
case '2': strcat(work,"2"); break;
case '3': strcat(work,"3"); break;
case '4': strcat(work,"4"); break;
case '5': strcat(work,"5"); break;
case '6': strcat(work,"6"); break;
case '7': strcat(work,"7"); break;
case '8': strcat(work,"8"); break;
case '9': strcat(work,"9"); break;
case '!': strcat(tmp,"\\-"); break; /* discretionary hyphen */
case '%': strcat(work,"{\\char35}"); break; /* pra.nava */
case '|': strcat(work,"."); break; /* single danda */
case '@': strcat(work,"|"); break; /* double danda */
case '\\': strcat(work,"{\\kern-1.8pt:}"); break; /* candrabindu */
case 'H': strcat(work,"{\\char92}"); break; /* visarga */
case 'M': strcat(work,"{\\tpp}"); break; /* anusvara */
}
}
/***************************************************************************/
/* Function: frontac() */
/* */
/* Process a front-vowel to workbuf */
/***************************************************************************/
void frontac(void)
{
CLRFLAGS;
switch(ac_char)
{ case 'a': strcat(work,"a"); break;
case 'A': strcat(work,"aA"); break;
case 'i': strcat(work,"ie"); break;
case 'I': strcat(work,"eI"); break;
case 'u': strcat(work,"uU"); break;
case 'U': strcat(work,"u<"); break;
case 'e': strcat(work,"eE"); break;
case 'E': strcat(work,"a>"); break;
case 'o': strcat(work,"o"); break;
case 'O': strcat(work,"aO"); break;
default : error("Lost in frontac()",-1);
}
}
/***************************************************************************/
/* Function: sam_warning() */
/* */
/* Print a warning message that a virama will be used within a */
/* samyoga. Also print input file line number, together with an */
/* indication of the samyoga and where the viraama will be placed. */
/***************************************************************************/
void sam_warning(void)
{
char *p, msg[80]="";
p = old_sptr;
while (ISHAL(*p))
{ switch (*p)
{ case 'B': strcat(msg,"bh"); break;
case 'C': strcat(msg,"ch"); break;
case 'D': strcat(msg,"dh"); break;
case 'G': strcat(msg,"gh"); break;
case 'H': strcat(msg,".h"); break;
case 'J': strcat(msg,"jh"); break;
case 'K': strcat(msg,"kh"); break;
case 'L': strcat(msg,"K"); break;
case 'P': strcat(msg,"ph"); break;
case 'T': strcat(msg,"th"); break;
case 'x': strcat(msg,".t"); break;
case 'X': strcat(msg,".th"); break;
case 'N': strcat(msg,".n"); break;
case 'q': strcat(msg,".d"); break;
case 'Q': strcat(msg,".dh"); break;
case 'f': strcat(msg,"f"); break;
case 'V': strcat(msg,"~n"); break;
case 'w': strcat(msg,"R"); break;
case 'W': strcat(msg,"G"); break;
case 'z': strcat(msg,"z"); break;
case 'Y': strcat(msg,"\"n"); break;
case 'Z': strcat(msg,"\"s"); break;
case 'r': strcat(msg,"r"); break;
default: chrcat(msg,*p); break;
}
if (++p == s_ptr) strcat(msg,"-");
}
if (ISAC(*p))
{ switch (*p)
{ /* case 'w': strcat(msg,".l"); break; */
default: chrcat(msg,*p); break;
}
}
printf("Line %4d Warning: samyoga viraama: %s\n",line_cnt,msg);
}
/***************************************************************************/
/* Function: backac() */
/* */
/* Process vowel diacritics */
/***************************************************************************/
void backac(void)
{ int j,k; char c, *p;
c = ac_char;
if (ac_char == 'A') { strcat(work,"A");} /* add aa-dia */
if (ac_char == 'i') { CAT(tmp,"i",""); } /* add i-dia */
if (ac_char == 'I') { strcat(work,"I"); } /* add ii-dia */
if (ac_char == 'u') { strcat(work,"U");} /* add u-dia */
if (ac_char == 'U') { strcat(work,"<");} /* add uu-dia */
if (ac_char == 'e') { strcat(work,"E"); } /* add e-dia */
if (ac_char == 'E') { strcat(work,">"); } /* add ai-dia */
if (ac_char == 'o') { strcat(work,"{\\char126}");} /* add o-dia */
if (ac_char == 'O') { strcat(work,"O");} /* add au-dia */
/* if (virama) { strcat(work,"\\30Cz"); } /* add virama */
}
/***************************************************************************/
/* Function: samyoga() */
/* */
/* Work along sktbuf sequentially to build up a samyoga print */
/* string in the work buffer and update the samyoga parameters. */
/* */
/* The method is quite unsophisticated, but its simplicity lends */
/* clarity for later additions or changes, and for this reason */
/* is done in Devanagari alphabetical order, but with longer */
/* strings before shorter. */
/* */
/* Macros are used to simplify reading the program --- believe it or not! */
/* */
/* Switch/case is used on the first letter, then the main LS macro tests: */
/* (1) if the test string matches the input exactly, then */
/* (2) bump input pointer to the character after string match */
/* (3) use NX macro to break out of switch instruction */
/***************************************************************************/
#define LS(a,c,z) n=strlen(a); \
if(strncmp(p,a,n)==0) { strcat(work,z); p+=n; c;}
#define NX sam_flag = 'X'; break;
/******************************************************************************/
void samyoga(void)
{
char *p, sam_flag; int n;
sam_flag = 0;
p = s_ptr;
while (1)
{ if (!ISHAL(*p)) { NX; }
switch (*p++)
{
/* k */
case 'k': LS("k", NX, "{\\adk}c");
LS("K", NX, "{\\adk}K");
LS("r", NX, "cq");
strcat(work,"c"); break;
/* kh */
case 'K': LS("y", NX, "kw");
strcat(work,"k"); break;
/* g */
case 'g': LS("g", NX, "{\\adk}g");
LS("G", NX, "{\\adk}G");
LS("r", NX, "gq");
strcat(work,"g"); break;
/* gh */
case 'G': strcat(work,"G"); break;
/* "n */
case 'Y': if(*p=='g' && *(p+1)=='i')
{p+=2; strcat(work,"{\\tpp}ig");NX;}
LS("k", NX, "{\\tpp}c");
LS("K", NX, "{\\tpp}k");
LS("g", NX, "{\\tpp}g");
LS("G", NX, "{\\tpp}G");
strcat(work,"L"); break;
/* c */
case 'c': LS("c", NX, "{\\adk}C");
LS("C", NX, "{\\adk}x");
strcat(work,"C"); break;
/* ch */
case 'C': strcat(work,"x"); break;
/* j */
case 'j': LS("j", NX, "{\\adk}j");
LS("J", NX, "{\\adk}J");
strcat(work,"j"); break;
/* jh */
case 'J': strcat(work,"J"); break;
/* ~n */
case 'V': LS("c", NX, "{\\tpp}C");
LS("C", NX, "{\\tpp}x");
LS("j", NX, "{\\tpp}j");
LS("J", NX, "{\\tpp}J");
strcat(work,"M"); break;
/* .t */
case 'x': LS("x", NX, "{\\adk}t");
LS("X", NX, "{\\adk}T");
strcat(work,"t"); break;
/* .th */
case 'X': strcat(work,"T"); break;
/* .da */
case 'q': LS("q", NX, "{\\adk}D");
LS("Q", NX, "{\\adk}Q");
strcat(work,"D"); break;
/* .dh */
case 'Q': strcat(work,"Q"); break;
/* .n */
case 'N': LS("x", NX, "{\\tpp}t");
LS("X", NX, "{\\tpp}T");
LS("q", NX, "{\\tpp}D");
LS("Q", NX, "{\\tpp}Q");
strcat(work,"N"); break;
/* t */
case 't': LS("t", NX, "{\\adk}V");
LS("T", NX, "{\\adk}W");
LS("r", NX, "Vq");
strcat(work,"V"); break;
/* th */
case 'T': strcat(work,"W"); break;
/* d */
case 'd': LS("d", NX, "{\\adk}d");
LS("D", NX, "{\\adk}Y");
LS("y", NX, "dw");
LS("r", NX, "dq");
LS("v", NX, "dX");
strcat(work,"d"); break;
/* dh */
case 'D': strcat(work,"Y"); break;
/* n */
case 'n': if(*p=='n' && *(p+1)=='i')
{p+=2; strcat(work,"i{\\tpt}n");NX;}
LS("t", NX, "{\\tpp}V");
LS("T", NX, "{\\tpp}W");
LS("d", NX, "{\\tpp}d");
LS("D", NX, "{\\tpp}Y");
LS("n", NX, "{\\tpp}n");
LS("h", NX, "nH");
strcat(work,"n"); break;
/* p */
case 'p': LS("p", NX, "{\\adk}p");
LS("P", NX, "{\\adk}f");
LS("r", NX, "pq");
strcat(work,"p"); break;
/* ph */
case 'P': strcat(work,"f"); break;
/* b */
case 'b': LS("b", NX, "{\\adk}b");
LS("B", NX, "{\\adk}B");
LS("r", NX, "bq");
strcat(work,"b"); break;
/* bh */
case 'B': strcat(work,"B"); break;
/* m */
case 'm': if(*p=='m' && *(p+1)=='i')
{p+=2; strcat(work,"i{\\tpt}m");NX;}
LS("p", NX, "{\\tpp}p");
LS("P", NX, "{\\tpp}f");
LS("b", NX, "{\\tpp}b");
LS("B", NX, "{\\tpp}B");
LS("m", NX, "{\\tpp}m");
LS("r", NX, "mq");
strcat(work,"m"); break;
/* y */
case 'y': strcat(work,"y"); break;
/* r */
case 'r': LS("h", NX, "rH");
strcat(work,"r"); break;
/* l */
case 'l': LS("l", NX, "{\\adk}l");
LS("h", NX, "lH");
strcat(work,"l"); break;
/* v */
case 'v': LS("h", NX, "vH");
strcat(work,"v"); break;
/* "s */
case 'Z': strcat(work,"S"); break;
/* s */
case 's': LS("s", NX, "{\\adk}s");
LS("v", NX, "sX");
strcat(work,"s"); break;
/* h */
case 'h': strcat(work,"h"); break;
/* K */
case 'L': strcat(work,"K"); break;
/* G */
case 'W': strcat(work,"Z"); break;
/* z */
case 'z': strcat(work,"z"); break;
/* R */
case 'w': LS("h", NX, "RH");
strcat(work,"R"); break;
/* f */
case 'f': strcat(work,"F"); break;
default: error("Lost in samyoga()",-1); NX;
}
if (sam_flag == 'X') { s_ptr = p; break; }
if (!ISHAL(*p)) { s_ptr = p; break; }
}
}
/***************************************************************************/
/* samapta */
/***************************************************************************/