summaryrefslogtreecommitdiff
path: root/support/translit/translit.c
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/translit/translit.c
Initial commit
Diffstat (limited to 'support/translit/translit.c')
-rw-r--r--support/translit/translit.c1752
1 files changed, 1752 insertions, 0 deletions
diff --git a/support/translit/translit.c b/support/translit/translit.c
new file mode 100644
index 0000000000..bebf3b941a
--- /dev/null
+++ b/support/translit/translit.c
@@ -0,0 +1,1752 @@
+
+/* This is a program fom transliterating files from one character set to
+ another.
+ TRANSLIT --- Version 1.02, April 4, 1993.
+ Copyright (c) by Jan Labanowski, 1993 and JKL Enterprises, Inc.
+ Permission is given to disribute this program freely in accordance with
+ the rules and conditions spelled out in the program documentation. If you
+ got this program without the documentation, or if some files were missing,
+ somebody must have violated the rules. In this case, please delete the the
+ program and obtain the information on how to get the complete distribution
+ from the author. The rules require that the whole package is distributed
+ (i.e., the source code, the transliteration tables, and the documentation).
+
+ 3/29/93 Jan Labanowski. Thanks to Leonid A. Broukhis (leo@ipmce.su)
+ I noticed that translit will not work correctly if SHIFT-IN and SHIFT-OUT
+ is the same sequence. The modification was made in which code detecting
+ SHIFT-IN and SHIFT-OUT exchanged places (i.e., program looks for SHIFT-IN
+ before it looks for SHIFT-OUT)
+
+ Author: Jan Labanowski, P.O.Box 21821, Columbus, OH 43221-0821, USA
+ E-mail: jkl@osc.edu, JKL@OHSTPY.BITNET
+ */
+
+#include "paths.h" /* for local definitions */
+#include "reg_exp.h" /* for regexp package */
+
+
+#define OPTIONS "i:o:t:d" /* allowed options on command line */
+#define MAXPAIRS 1000 /* maximum number of conversion pairs */
+#define MAXSETS 10 /* maximum number of shift in/out sets */
+#define MAXLEVEL 10 /* maximum set nesting level */
+#define MAXBUFF 1000 /* maximum size of the buffer */
+#define MAXMATCH 100 /* maximum length of match to regular exp. */
+
+
+/* define all local functions as static if compiler likes it */
+#if STATICFUN
+#define STATIC static
+#else
+#define STATIC
+#endif
+
+/* types to hold the translation maps for single chars. If inp_maps is of
+ * type IMAPP, then character of code c in set k will correspond to
+ * a string pointed by (*inp_maps[k])[c];
+ */
+
+/* ========== now include definitions for paths and regexp */
+
+
+typedef char* IMAP[256]; /* type IMAP is a 256 element array
+ of pointers to string */
+typedef IMAP* IMAPP[MAXSETS]; /* array of pointers to IMAP */
+
+/* types to hold output set number for a single char. if out_sets is of type
+ * OSETP and c is a code, and k is the set of input character, then output
+ * set number is (*out_sets[k])[c]; */
+typedef int OSET[256];
+typedef OSET* OSETP[MAXSETS];
+
+
+typedef union {
+ char *seq; /* pointer to a string */
+ reg_exp *re; /* pointer to a regular expression "program */
+ } ADDR;
+
+
+typedef struct {
+ int typ; /* type of pointer in ADDR union:
+ 0-string (seq), 1-input regexp (re),
+ 2-output regexp (seq) (output regexp
+ is a string !)*/
+ int len; /* length of a string if present */
+ int set; /* character set number for the string */
+ ADDR ad; /* string or regexp program */
+ } SDATA;
+
+
+/* Some compiler represent character codes > 127 as negative numbers, i.e.,
+ * character 255 is -1, char 254 is -2, etc.
+ * The flag SIGNED_CHAR_TYPE is set by the program, (program checks which
+ * convention is used. It is set to 1, if characters have sign (i.e., 255=-1)
+ * and is set to 0 if characters are unsigned (i.e., 255=255). Do not touch
+ * this declaration, unless you know what you are doing.
+ */
+int SIGNED_CHAR_TYPE;
+
+ char tabline[MAXBUFF]; /* line of text from conversion table file */
+ char last_tab_line[MAXBUFF];
+ char *lineptr; /* pointer to the first unread character of tabline */
+ int n_line_chars; /* number of characters in tabline buffer */
+ int chars_left; /* no. of chars left in input buffer */
+
+ int memleft; /* tells how much memory is left in allocated area */
+ char *memptr; /* pointer for memory allocation area */
+ char regerrstr[100]; /* string to hold error message from regular exp */
+ reg_exp *regauxptr; /* aux pointer for regular expresion structure */
+ int debug_flg=0; /* if 1, then additional info sent to stderr */
+
+ FILE *inpf; /* input file pointer */
+ FILE *outf; /* output file pointer */
+ FILE *tabl; /* file with translation table */
+
+ int n_conv_seq; /* number of conversion sequences */
+ SDATA inp_data[MAXPAIRS]; /* structure to hold types, lengths and pointers
+ for input sequences */
+ SDATA out_data[MAXPAIRS]; /* structure to hold types lengths and pointers
+ for output sequences */
+ SDATA inp_SO_data[MAXSETS]; /* structure with types, lens, ptrs for inp_SO*/
+ SDATA inp_SO_subs[MAXSETS]; /* holds substitution string/regexp for inp_SO*/
+ SDATA inp_SI_data[MAXSETS]; /* structure with types, lens, ptrs for inp_SI*/
+ SDATA inp_SI_subs[MAXSETS]; /* holds substitution string/regexp for inp SI*/
+ SDATA inp_nest_open[MAXSETS]; /* for sick transliteration cases, like TeX */
+ SDATA inp_nest_close[MAXSETS]; /* where you need to count {} pairs */
+
+ SDATA *junky;
+
+ IMAPP inp_maps; /* maps for single character sequences,
+ array of pointers. Element of the array is a pointer
+ to the array of pointers which point at strings */
+ OSETP out_sets; /* output set numbers corresponding to inp_maps
+ array of pointers to integer pointers */
+ int n_inp_sets; /* number of input sets */
+ int n_out_sets; /* number of output sets */
+ char *out_SI[MAXSETS]; /* pointer to output shift in sequences */
+ char *out_SO[MAXSETS]; /* pointer to output shift out sequences */
+ int out_SI_len[MAXSETS]; /* out SI sequence length */
+ int out_SO_len[MAXSETS]; /* out SO sequence length */
+
+ char *begseq, /* sequence to be written at the beginning of output*/
+ *endseq; /* sequence to be written at the end of output file */
+
+ int file_version; /* conversion table version number */
+ int strstart, strend, /* codes delimiting strings */
+ liststart, listend, /* codes delimiting lists */
+ regexstart, regexend, /* codes delimiting expressions */
+ curst1, curend1,
+ curst2, curend2; /* auxiliary */
+
+ char scr1[MAXBUFF], scr2[MAXBUFF], /* scratch space */
+ scr1a[MAXBUFF], scr2a[MAXBUFF]; /* scratch space */
+ char *scr1ptr, *scr2ptr, *scr1pt, *scr2pt,
+ *scrauxptr, *scrcurptr; /* aux string pointers */
+
+ int inp_seq_length; /* length of input sequence */
+ int out_seq_length; /* length of output sequence */
+ int out_set_number; /* number of output set */
+ char *out_seq_ptr; /* pointer to output sequence */
+
+ reg_exp *reg_comp();
+ int reg_try();
+ void reg_sub();
+ void reg_error();
+
+/* fix if no strchr routine in the libarry */
+#if STRCHR
+#else
+#define strchr indexfun
+#endif
+
+/* this is index which is equivalent to strchr */
+char *indexfun (s, c)
+char *s;
+int c;
+ {
+ while (*s)
+ if (c == *s) return (s);
+ else s++;
+ return (NULL);
+ }
+
+
+/* ============================================================ */
+
+/* include code for getopt() if not known to compiler */
+
+#if GETOPT
+#else
+
+/*
+ This is a some getopt I took from the net and do not remember
+ who actually wrote this
+*/
+
+#define ARGCH (int)':'
+#define BADCH (int)'?'
+#define EMSG ""
+#define ENDARGS "--"
+
+/*
+ * get option letter from argument vector
+ */
+int opterr = 1, /* useless, never set or used */
+ optind = 1, /* index into parent argv vector */
+ optopt; /* character checked for validity */
+char *optarg; /* argument associated with option */
+
+#define tell(s) fputs(*nargv,stderr);fputs(s,stderr); \
+ fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
+
+
+STATIC int getopt(nargc,nargv,ostr)
+int nargc;
+char **nargv,
+ *ostr;
+{
+ static char *place = EMSG; /* option letter processing */
+ register char *oli; /* option letter list index */
+
+ if(!*place) { /* update scanning pointer */
+ if(optind >= nargc || *(place = nargv[optind]) != '-' ||
+ !*++place) return(EOF);
+ if (*place == '-') { /* found "--" */
+ ++optind;
+ return(EOF);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == ARGCH || !(oli = strchr(ostr,optopt))) {
+ if(!*place) ++optind;
+ tell(": illegal option -- ");
+ }
+ if (*++oli != ARGCH) { /* don't need argument */
+ optarg = NULL;
+ if (!*place) ++optind;
+ }
+ else { /* need an argument */
+ if (*place) optarg = place; /* no white space */
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ tell(": option requires an argument -- ");
+ }
+ else optarg = nargv[optind]; /* white space */
+ place = EMSG;
+ ++optind;
+ }
+ return(optopt); /* dump back option letter */
+}
+
+#endif
+
+
+/* ================= charcode ======================
+ * returns the code of the character given its integer code. If global
+ * variable SIGNED_CHAR_TYPE flag is 1, then character code is negative
+ * for chars >= 128, otherwise they are passed through.
+ * ================================================== */
+STATIC char charcode (intcde)
+int intcde;
+{
+ if(SIGNED_CHAR_TYPE == 1) { /* if signed chars used */
+ if(intcde >= 128) { /* if integer code is larger than 128 */
+ return((char)(intcde - 256)); /* make it negative complement */
+ }
+ else { /* return the original code */
+ return((char)intcde);
+ }
+ }
+ else {
+ return((char)intcde);
+ }
+}
+/* ================= intcode =====================
+ * returns integer code of a character depending on the value of
+ * SIGNED_CHAR_TYPE flag
+ * =============================================== */
+int intcode(charcde)
+char charcde;
+{
+ if(SIGNED_CHAR_TYPE == 1) { /* if signed chars used */
+ if((int)charcde < (int)0) { /* if negative code */
+ return((int)((int)charcde + 256)); /* convert to positive */
+ }
+ else { /* return the original code */
+ return((int)charcde);
+ }
+ }
+ else {
+ return((int)charcde);
+ }
+}
+
+/* ================= tablerr ======================
+ * terminates the program with a message to stderr and contents of
+ * the buffer. num - exit status, errmsg - message
+ * ================================================ */
+STATIC int tablerr(num, errmsg)
+int num;
+char *errmsg;
+{
+ fprintf(stderr,"%s\n", errmsg);
+ fprintf(stderr,
+ "Current contents of the input buffer for conversion table file:\n");
+ fprintf(stderr,"%s\n", last_tab_line);
+ exit(num);
+ return(0); /* to keep compiler happy that there is return from function */
+}
+
+/* ================= getnblkline ====================
+ * gets a nonblank line from tabl file and resets pointers if clearflg == 1,
+ * otherwise, appends the line to the current buffer.
+ * Line is stored in the global variable tabline. The global *lineptr
+ * is reset to line beginning.
+ * If EOF reached, or line too long, returns -1, else a number of chars in
+ * the line. If line starts with # or ! in first column, it is skipped.
+ * ================================================== */
+STATIC int getnblkline(fileptr, clearflg)
+FILE *fileptr;
+int clearflg;
+{
+ int l, maxc;
+ char *auxptr;
+ if(clearflg == 1) {
+ n_line_chars = 0;
+ lineptr = tabline;
+ }
+ maxc = MAXBUFF - n_line_chars -2; /* how much space in the buffer */
+ while (fgets (lineptr, maxc, fileptr) != NULL) {
+ strcpy(last_tab_line, lineptr); /* save current line for error messages */
+ if((*lineptr == '#') || (*lineptr == '!')) { /* skip comment lines */
+ continue;
+ }
+ l = strlen(lineptr); /* how many chars we read ? */
+ n_line_chars += l; /* how many chars in the buffer */
+
+ if(n_line_chars > MAXBUFF-5) { /* if line too long */
+ return(-1);
+ }
+ if(clearflg == 1) { /* do it only if first line is fetched */
+ auxptr = lineptr;
+ while ((isspace(*auxptr) != 0) && (*auxptr != '\0')) {
+ auxptr++; /* skip front spaces */
+ }
+
+ if(*auxptr == '\0') { /* if blank line */
+ continue;
+ }
+ }
+ return(l); /* return length of line just read */
+ } /* end while */
+ return(-1); /* end of file found */
+}
+/* ================= chknblk ==========================
+ * returns a code of the first nonblank character at the current position
+ * of tabline buffer. The lineptr is left at this char (NOT AT THE NEXT CHAR !
+ * If no nonblank * character, returns -1.
+ * ==================================================== */
+STATIC int chknblk(fileptr)
+FILE *fileptr;
+{
+ int ch;
+
+ Fetch_next:
+ while (*lineptr != '\0') {
+ if(isspace(*lineptr) == 0) {
+ ch = intcode(*lineptr);
+ return(ch);
+ }
+ lineptr++;
+ }
+ if(getnblkline(fileptr, 0) > 0) {
+ goto Fetch_next;
+ }
+ else {
+ return(-1);
+ }
+}
+
+/* ================= getnumber ===========================
+ * retrieves integer nonnegative decimal number from a the current
+ * line (tabline).
+ * Returns the number, or -9999 if no good number in the line
+ * only number < 1000 allowed
+ * ========================================================== */
+STATIC int getnumber(fileptr)
+FILE *fileptr;
+{
+ int num, flg, sign;
+ num = 0;
+ flg = 0;
+ sign = 0;
+
+Next_line:
+ while (*lineptr != '\0') {
+ if(flg == 0) { /* only spaces found till now */
+ if(isspace(*lineptr) != 0) {
+ lineptr++;
+ continue;
+ }
+ else {
+ flg = 1; /* the nonblank char found */
+ }
+ }
+
+ if(flg == 1) { /* the nonblank char was found */
+ if(sign == 0) { /* sign may only be located before the number */
+ if(*lineptr == '-') {
+ sign = -1;
+ lineptr++;
+ }
+ else if(*lineptr == '+') {
+ sign = 1;
+ lineptr++;
+ }
+ else { /* set it to +1, so it is checked only once */
+ sign = 1;
+ }
+ }
+ if(isdigit(*lineptr) != 0) {
+ num = 10*num + *lineptr - '0';
+ if(num > 1000) {
+ return(-9999); /* number too large */
+ }
+ }
+ else if(isspace(*lineptr) != 0) { /* end of number */
+ return(num*sign);
+ }
+ else {
+ return(-9999); /* some strange character */
+ }
+ }
+ lineptr++; /* to next character */
+ }
+ if(flg == 1) { /* if valid number collected before '\0' */
+ return(num*sign);
+ }
+ else {
+ if(getnblkline(fileptr, 0) > 0) {
+ goto Next_line;
+ }
+ else {
+ return(-9999); /* if no number before end of file, error */
+ }
+ }
+}
+
+
+/* ================= getstring ==========================
+ * returns the pointer to the string from the tabline. The pointer is
+ * volatile, and will point to garbage after next getnblkline call, so
+ * you need to copy it (or use it) immedaitely after the call.
+ * Returns a pointer to string if successful, and NULL pointer if not.
+ * startcode --- character code which starts the string (it is not
+ * included in the string. If startcode = '\0', the
+ * string is collected from the curent pointer to a buffer.
+ * endcode --- character which ends the string. It is not included in
+ * the string. If endcode = '\0', then string is collected
+ * until first blank or end of string found.
+ * If no startcode found or no endcode found, the NULL string is returned.
+ * ========================================================= */
+
+STATIC char *getstring(startcode, endcode, fileptr)
+int startcode, endcode;
+FILE *fileptr;
+{
+ int flg;
+ char *startptr;
+
+ flg = 0;
+Read_next_line:
+ while (*lineptr != '\0') {
+ if(flg == 0) { /* if startcode not found yet */
+ if(startcode != 0) {
+ if(charcode(startcode) == *lineptr) {
+ flg = 1; /* the startcode found */
+ lineptr++;
+ startptr = lineptr; /* skip startcode */
+ continue;
+ }
+ else {
+ lineptr++;
+ continue;
+ }
+ }
+ else { /* startcode is 0 */
+ flg = 1;
+ startptr = lineptr;
+ lineptr++;
+ continue;
+ }
+ } /* end flg == 0 */
+
+ if(flg == 1) { /* the 1st char was found */
+ if(endcode == 0) { /* if stop on blank requested */
+ if(isspace(*lineptr) != 0) { /* if space found */
+ *lineptr = '\0'; /* mark string end */
+ lineptr++; /* advance pointer */
+ return(startptr);
+ }
+ else { /* collect chars */
+ lineptr++;
+ continue;
+ }
+ }
+ else if(charcode(*lineptr) == endcode) { /* if stop at endcode */
+ *lineptr = '\0';
+ lineptr++;
+ return(startptr);
+ }
+ else { /* if not endcode , collect next characters */
+ lineptr++;
+ continue;
+ }
+ } /* end flg == 1 */
+ } /* end while */
+
+ /* the buffer was exhausted */
+ if(endcode == 0) {
+ return(startptr);
+ }
+ else {
+ if(getnblkline(fileptr, 0) > 0) {
+ goto Read_next_line;
+ }
+ else {
+ return((char *)NULL);
+ }
+ }
+}
+
+/* ============================ convnum ===================
+ * returns a nonegative number based on str. Scans the string
+ * from position posbeg, and returns first invalid character position
+ * in posend. If error, returns -1 (less than 2 characters, num > 255).
+ * str - scanned string
+ * digits string of allowed ordered digits in lowercase
+ * posbeg - start
+ * ======================================================== */
+
+STATIC int convnum(buff, digits, posbeg)
+char *buff, *digits;
+int posbeg;
+{
+ int num, i, l, d, base;
+
+ base = strlen(digits);
+ num = 0;
+ i = posbeg;
+
+ while (buff[i] != '\0') {
+ d = -1;
+ for(l = 0; l < base; l++) {
+ if(buff[i] == digits[l]) {
+ d = l;
+ break;
+ }
+ }
+ if(d >= 0) {
+ num = d + num*base;
+ if(num > 255) { /* if code too large */
+ return(-1);
+ }
+ i++;
+ }
+ else {
+ break;
+ }
+ }
+ if((i - posbeg) < 2) { /* if less than two characters in a number */
+ return(-1);
+ }
+ buff[i] = '\0';
+ return(num);
+}
+
+
+/* ============================ str2code ==================
+ * str2code returns a code specified in buff. The valid numbers must have at
+ * least 2 digits. Here is a format of the code string
+ * (n represents valid digit for a given base).
+ * nnn (up to 3 decimal digits, first is not zero)
+ * 0nnn (up to 3 octal digits)
+ * 0xnn (up to 3 hex digits)
+ * 0onnn (up to 3 octal digits)
+ * 0dnnn (up to 3 decimal digits)
+ * The buff string will have '\0' put at the position after a valid number
+ * If no valid number can be parsed, or number is greater than 255, -1
+ * is returned.
+ * ======================================================== */
+STATIC int str2code(buff)
+char *buff;
+{
+ int i, l, num;
+ static char decdig[]="0123456789",
+ octdig[]="01234567",
+ hexdig[]="0123456789abcdef";
+
+ l = strlen(buff); /* get length */
+ if(l < 2) { /* string too short */
+ return(-1);
+ }
+
+ for(i = 0; i < l; i++) { /* convert to lowercase */
+ if(isalpha(buff[i]) != 0) { /* if letter */
+ buff[i] = tolower(buff[i]);
+ }
+ }
+
+ if(isdigit(buff[0]) == 0) { /* if first char not a digit */
+ return(-1);
+ }
+
+ if(buff[0] == '0') { /*if starting char is 0, then octal */
+ if((num = convnum(buff, octdig, 0)) != -1) { /* check if no base */
+ return(num);
+ }
+ }
+ else { /* this has to be a decimal number */
+ if((num = convnum(buff, decdig, 0)) != -1) {
+ return(num);
+ }
+ else { /* error in decimal number */
+ return(-1);
+ }
+ }
+ /* the base is specified at buff[1] */
+ if(buff[1] == 'o') {
+ num = convnum(buff, octdig, 2);
+ }
+ else if(buff[1] == 'd') {
+ num = convnum(buff, decdig, 2);
+ }
+ else if(buff[1] == 'x') {
+ num = convnum(buff, hexdig, 2);
+ }
+ else { /* no base found */
+ return(-1);
+ }
+ return(num);
+}
+
+/* ================= convstr ========================
+ * copies inp_string to out_strings, and when codes are given as \xxx
+ * converts them to characters.
+ * Returns:
+ * 0 if OK
+ * 1 if character zero (e.g., \00 or \0x0) is found (it ends the string
+ * processing, since it is string terminator).
+ * =================================================== */
+STATIC int convstr(inp_string, out_string)
+char *inp_string, *out_string;
+{
+ int ch, ch1, i, l, num, n;
+ char buff[8];
+
+ n = 0;
+ while ((ch = *inp_string) != '\0') {
+ n++; /* count characters */
+ if(ch == '\\') {
+ /* skip blank sequence */
+ ch1 = *(inp_string + 1); /* charcode following "\" */
+ if(isspace(ch1) != 0) { /* if "\" followed by blanks */
+ inp_string++; /* skip over "\" */
+ n++;
+ while( isspace((*inp_string)) != 0) { /* skip all spaces */
+ n++;
+ inp_string++;
+ }
+ n--; /* it will be advanced at the top of loop */
+ ch = *inp_string;
+ if(ch == '\0') {
+ *out_string = '\0';
+ return(0);
+ }
+ continue; /* start new loop turn */
+ } /* ch is space */
+
+ /* now check is \020, etc., i.e., codes */
+ for(i = 1; i <= 6; i++) { /* copy possible number to a buffer */
+ buff[i-1] = *(inp_string+i);
+ }
+ buff[6] = '\0'; /* terminate buff */
+ if((num = str2code(buff)) >= 0) {
+ *out_string++ = charcode(num);
+ /* find how many characters have beed used ( number + \ ) */
+ if(num == 0) {
+ *out_string = '\0';
+ return(1);
+ }
+ l = strlen(buff) + 1;
+ inp_string += l;
+ continue;
+ }
+ }
+ *out_string++ = *inp_string;
+ inp_string++;
+ } /* end while */
+ *out_string = '\0';
+ return(0);
+}
+
+
+/* ====================== compstr ========================
+ * returns 1 if str1 is located at the beginning of str2 and 0 otherwise
+ * ======================================================= */
+STATIC int compstr(str1, str2)
+char str1[], str2[];
+{
+ int i;
+ if(str1[0] == '\0') { /* empty sequence never matches */
+ return(0);
+ }
+ for(i = 0; str1[i] != '\0'; i++) {
+ if(str1[i] != str2[i]) {
+ return(0);
+ }
+ }
+ return(1);
+}
+
+/* ====================== chkseqs ============================
+ * returns the sequence number if sequence is present at the beginning
+ * of buffer and -1 otherwise (first sequence has number 0);
+ * If regular expression, then SDATA.len is set to the length of
+ * the string which matches the regular expession.
+ * ============================================================= */
+STATIC int chkseqs(n_seq, seqstruc, buff)
+int n_seq;
+SDATA *seqstruc;
+char *buff;
+{
+ int i, j, l;
+ char *sp, *ep, *str;
+ reg_exp *reaux;
+
+ if(n_seq == 0) {
+ return(-1);
+ }
+ for (i = 0; i < n_seq; i++) {
+ if(seqstruc->typ == 0) { /* if plain string */
+ str = (seqstruc->ad).seq;
+ if(*str != '\0') {
+ l = 1;
+ for(j = 0; *str != '\0'; j++) {
+ if(*(buff + j) != *str++) {
+ l = 0;
+ break;
+ }
+ }
+ if(l == 1) {
+ return(i);
+ }
+ }
+ }
+ else if(seqstruc->typ == 1) { /* regexp */
+ if(reg_try((seqstruc->ad).re, buff) == 1) { /* if anchored match found */
+ reaux = (seqstruc->ad).re; /* get address of search program */
+ sp = reaux->startp[0]; /* address of 1st char of match */
+ ep = reaux->endp[0]; /* next char after match */
+ if(sp != buff) { /* matches are anchored, at the buff beginning ! */
+ tablerr(10, "Internal error in regexp package\n");
+ }
+ l = seqstruc->len = ep - sp; /* match length */
+ if(l <= 0) {
+ fprintf(stderr,"Error when matching regular expression %d\n", i+1);
+ exit(10);
+ }
+ return(i);
+ }
+ }
+ seqstruc++;
+ } /* end for */
+ return(-1);
+}
+
+/* =================== rdelim ==================
+ * read delimiters from tabl file
+ * ============================================= */
+STATIC int rdelim(startd, endd)
+int *startd, *endd;
+{
+ if(getnblkline(tabl, 1) < 0) {
+ tablerr(10, "Could not read left delimiter code");
+ }
+ if((*startd = chknblk(tabl)) < 0) {
+ tablerr(10, "Could not read left delimiter code");
+ }
+ lineptr++; /* point at next char */
+ if(isspace(*lineptr) == 0) {
+ tablerr(10,
+ "(Left Delimiter):Delimiters should be single chars separated by spaces");
+ }
+ if((*endd = chknblk(tabl)) < 0) {
+ tablerr(10, "Could not read right delimiter code");
+ }
+ lineptr++; /* point at next char */
+ if(isspace(*lineptr) == 0) {
+ tablerr(10,
+ "(Right Delimiter):Delimiters should be single chars separated by spaces");
+ }
+ return(0);
+}
+
+/* ================== beseq ==============
+ * read starting or ending sequence for output
+ * and return pointer
+ * ======================================= */
+STATIC char* beseq()
+{
+ char *scr1pt, *scr2pt;
+ int l;
+
+ if((getnblkline(tabl, 1) < 0) ||
+ ((scr1pt = getstring(strstart,strend,tabl)) == (char*)NULL)) {
+ tablerr(10, "Error when reading starting/ending sequence");
+ }
+ l = strlen(scr1pt) + 1;
+ if((scr2pt = (char*)malloc(l*sizeof(char))) == NULL) {
+ tablerr(10, "Out of memory");
+ }
+ convstr(scr1pt,scr2pt);
+ return(scr2pt);
+}
+
+/* ================= allomaps ===============
+ * Allocate space for maps
+ * ============================================ */
+STATIC int allomaps(n)
+int n;
+{
+ int i;
+ /* Allocate space for inp_maps and out_sets for input set 0 */
+ if((inp_maps[n] = (IMAP*)malloc(256*sizeof(char*))) == NULL) {
+ /*if failed */
+ tablerr(10, "Out of memory for storing sequences");
+ }
+
+ if((out_sets[n] = (OSET*)malloc(256*sizeof(int))) == NULL) { /* if failed */
+ tablerr(10, "Out of memory for storing sequences");
+ }
+
+ for(i = 0; i < 256; i++) { /* zero allocated memory */
+ (*inp_maps[n])[i] = (char*)NULL;
+ (*out_sets[n])[i] = 0;
+ }
+ return(0);
+}
+
+/* =================== savestring =================
+ * saves string in the allocated storage and returns pointer to it
+ * does all the housekeeping
+ * ================================================== */
+STATIC char *savestring(str)
+char *str;
+{
+ int l;
+ char *retptr;
+
+ l = strlen(str)+1;
+ if(memleft < l) {
+ memleft = 5*MAXPAIRS;
+ if((memptr = (char*)malloc(memleft*sizeof(char)))
+ == NULL) {
+ tablerr(10,"Out of memory for allocation");
+ }
+ }
+ strcpy(memptr, str);
+ retptr = memptr;
+ memptr += l;
+ memleft -= l;
+ return(retptr);
+}
+
+/* ================= splitlist =================
+ * unfolds the list [] to a list of characters (i.e. [a-d] = [abcd])
+ * =============================================== */
+STATIC int splitlist(inlist, unflist)
+char *inlist, *unflist;
+{
+ int ch, ch1, ch2, i, len;
+
+ convstr(inlist, inlist); /* convert codes */
+ len = strlen(inlist);
+ if(len == 0) {
+ tablerr(10, "Empty list specified");
+ }
+
+ *unflist++ = *inlist++; /* save first character */
+ while ( *inlist != '\0') {
+ ch = *inlist;
+ if((ch != '-') || (*(inlist+1) == '\0')) {
+ *unflist++ = ch;
+ }
+ else { /* the minus is inside */
+ ch1 = intcode(*(inlist-1));
+ ch2 = intcode(*(inlist+1));
+ if(ch2 <= ch1) {
+ tablerr(10, "The limits in the range within the list are reversed");
+ }
+ for(i = ch1+1; i < ch2; i++) {
+ *unflist++ = charcode(i);
+ }
+ }
+ inlist++;
+ }
+ *unflist = '\0';
+ return(0);
+}
+
+/* ======================== regerror ==================
+ * regerror --- routine called from within a regexp package. Aborts
+ * program with message
+ * ==================================================== */
+void reg_error(s)
+char *s;
+{
+ strcat(regerrstr,s);
+ tablerr(11,regerrstr);
+}
+
+/* ======================== rdinshift ==================
+ * reads in a shift sequence, assuming that the getnblkline was called
+ * Fills in structure SDATA. If typ = 1, it is assumed that it is data
+ * for matching, if typ = 2, this is data to be output
+ * If OK, returns 0, else dies
+ * ======================================================= */
+STATIC int rdinshift(sdstr, sttyp)
+SDATA *sdstr;
+int sttyp;
+{
+ int mode1;
+ ADDR ads;
+ curst1 = chknblk(tabl); /* check what type delimiter */
+ if(curst1 == strstart) {
+ mode1 = 1;
+ curend1 = strend;
+ }
+ else if(curst1 == liststart) {
+ mode1 = 2;
+ tablerr(10, "Lists not allowed for input SHIFT sequences");
+ }
+ else if(curst1 == regexstart) {
+ mode1 = 3;
+ curend1 = regexend;
+ }
+ else {
+ tablerr(10, "Error when reading SHIFT input sequences");
+ }
+
+ if((scr1pt = getstring(curst1, curend1, tabl)) == (char*)NULL) {
+ tablerr(10, "Error when reading input SHIFT sequences");
+ }
+
+ convstr(scr1pt, scr1); /* convert codes in the sequence */
+ scr1pt = savestring(scr1); /* save sequence in memory */
+ strcpy(regerrstr, "Error in regexp for input SHIFT sequences:");
+
+ if(mode1 == 1) {
+ sdstr->typ = 0; /* common string */
+ sdstr->len = strlen(scr1pt);
+ ads.seq = scr1pt; /* save string address */
+ sdstr->ad = ads;
+ }
+ else if(mode1 == 3) {
+ if(sttyp == 1) {
+ sdstr->typ = 1;
+ regauxptr = reg_comp(scr1pt);
+ if(regauxptr == (reg_exp *)NULL) {
+ tablerr(10, "Error in regular expression");
+ }
+ ads.re = regauxptr;
+ sdstr->ad = ads;
+ }
+ else {
+ sdstr->typ = 2;
+ sdstr->len = strlen(scr1pt);
+ ads.seq = scr1pt;
+ sdstr->ad = ads;
+ }
+ }
+ return(0);
+}
+
+/* ========================= match_subs ==========================
+ * match_subs matches the match_data sequence description to the
+ * current position of the input file string (scrcurptr) and if match
+ * is found, finds the replacement string and puts it in scr1 buffer.
+ * it sets the global variables out_seq_length, out_seq_ptr, inp_seq_length
+ * out_set_number. Returns 1 on success, and 0 if match was not found.
+ * ================================================================== */
+STATIC int match_subs(match_data, repl_data)
+SDATA *match_data, *repl_data;
+{
+ if(chkseqs(1, match_data, scrcurptr) >= 0) {
+ inp_seq_length = match_data->len; /*chkseqs sets it for inp.typ 1 */
+ out_set_number = repl_data->set;
+ if(repl_data->typ == 2) { /* if regexp substitution */
+ /* find a substitution string */
+ regauxptr = (match_data->ad).re; /* pointer to regexp prog */
+ /* scr contains the substitution string */
+ reg_sub(regauxptr, (repl_data->ad).seq, scr1);
+ out_seq_length = strlen(scr1); /*number of chars in substitute */
+ out_seq_ptr = scr1; /* pointer to substitute string */
+ }
+ else { /* if plain string (type = 0) */
+ out_seq_length = repl_data->len;
+ out_seq_ptr = (repl_data->ad).seq;
+ }
+ if(out_seq_length > MAXMATCH) {
+ fprintf(stderr,
+ "The substitution string is too long (%d chararacters):\n%s\n",
+ out_seq_length, out_seq_ptr);
+ exit(1);
+ }
+ return(1);
+ }
+ else {
+ return(0);
+ }
+}
+
+/* =================== repl_inp =============================
+ * replaces matching portion of an input text with a substitute string.
+ * ========================================================== */
+int repl_inp()
+{
+ int k, l, i;
+
+ if(out_seq_length > MAXMATCH) {
+ fprintf(stderr,
+ "The output substitution sequence is too long (%d characters):\n%s\n",
+ out_seq_length, out_seq_ptr);
+ exit(1);
+ }
+ if(inp_seq_length >= out_seq_length) { /* do not have to copy strings */
+ k = inp_seq_length - out_seq_length; /* diff in lengths */
+ scrcurptr += k; /* move forwarde by the diff */
+ chars_left -= k;
+ for (i = 0; i < out_seq_length; i++) { /* copy chars */
+ *(scrcurptr + i) = *(out_seq_ptr + i);
+ }
+ }
+ else { /* have to push remaining chars to the right to make space */
+ k = out_seq_length - inp_seq_length; /* diff in lengths */
+ l = strlen(scrcurptr); /* length of input text */
+ /* memmove could be used, but it is not in all libaries */
+ for (i = l; i >= 0; i--) { /* move to right, start with terminating '\0' */
+ *(scrcurptr + i + k) = *(scrcurptr + i);
+ }
+ for (i = 0; i < out_seq_length; i++) { /* place the output string */
+ *(scrcurptr + i) = *(out_seq_ptr + i);
+ }
+ chars_left += k; /* update chars_left, scrcurptr not changed */
+ }
+ return(0);
+}
+
+/*======================== main ================================== */
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+ char *tabl_file; /* name of file with conversion table */
+ static char deftablfile[200]=
+ DEFCONVNAME; /* default conversion file name */
+ static char deftablpath[200]=
+ TPATH; /* default conversion file path */
+ char table_name[300]; /* working array for conversion table */
+
+ int level; /* input set nesting level */
+ int inp_cur_set[MAXLEVEL];/* set input number being processed */
+ int inp_cur_nest[MAXLEVEL]; /* current nesting count for input set */
+ int cur_inp_set; /* current input set, same as inp_cur_set[level] */
+ int out_cur_set; /* output set level being processed */
+ int buffer_size; /* size of input buffer string */
+ int opt; /* option letter */
+ int mode1, mode2; /* type of string (1=str, 2=list, 3=regex) */
+
+ int flg, ch, i, j, k, l, n; /* aux variables */
+
+
+#if GETOPT
+ extern char *optarg; /* option argument from getopt */
+ extern int optind, opterr; /* needed for getopt */
+#endif
+
+ static char usage[]=
+ "Usage: translit [-i inpfil] [-o outfil] [-t convtabfil] [convtabfil]\n";
+
+
+ inpf = stdin; /* initialize input to standard input */ /*UNIX*/
+ outf = stdout; /* initialize output to standard output */ /*UNIX*/
+
+ /* set SIGNED_CHAR_TYPE flag */
+ scr1[0] = '\372';
+ if((int)scr1[0] < 0) {
+ SIGNED_CHAR_TYPE = 1;
+ }
+ else {
+ SIGNED_CHAR_TYPE = 0;
+ }
+
+/* if environment is supported */
+#if GETENV
+ /* if TRANSPATH variable defined, take its contents */
+ if((scr1pt = getenv(TRANSPATH)) != (char *)NULL) {
+ strcpy(deftablpath, scr1pt);
+ }
+ if((scr1pt = getenv(DEFNAME)) != (char *)NULL) {
+ strcpy(deftablfile, scr1pt);
+ }
+#endif
+
+ tabl_file = deftablfile; /* default table file name */
+
+ flg = 0; /* set to no conv table given as an argument */
+ i = j = k = 0; /* flags, for files specified: i-inp, j-out, k-tabl */
+ while ((opt = getopt(argc, argv, OPTIONS)) != EOF) {
+ switch (opt) {
+ case 'd':
+ debug_flg = 1;
+ break;
+ case 'i':
+ if(i != 0) {
+ fprintf(stderr, "You specified option -i twice\n");
+ return(1);
+ }
+ if((inpf = fopen(optarg, "r")) == NULL) {
+ fprintf(stderr,"Error: Could not find input file: %s\n", optarg);
+ return(1);
+ }
+ i = 1;
+ break;
+ case 'o':
+ if(j != 0) {
+ fprintf(stderr, "You specified option -o twice\n");
+ return(1);
+ }
+ if((outf = fopen(optarg, "r")) != NULL) {
+ fprintf(stderr,
+ "Error: Output file: %s already exists! Delete it first.\n", optarg);
+ exit(3);
+ }
+ if((outf = fopen(optarg, "w")) == NULL) {
+ fprintf(stderr,"Error: Could not open output file: %s\n", optarg);
+ exit(2);
+ }
+ j = 1;
+ break;
+
+ case 't':
+ if(k != 0) {
+ fprintf(stderr, "You specified option -t twice\n");
+ return(1);
+ }
+ tabl_file = optarg;
+ flg = 1;
+ k = 1;
+ break;
+ case '?':
+ fprintf(stderr,"Error: %s\n", usage);
+ exit(3);
+ } /* end switch */
+ } /* end while */
+
+ if(optind < argc) { /* check if translation table given w/o option -t */
+ if(flg == 1) {
+ fprintf (stderr,"Error: You specified conversion table file twice\n");
+ exit(4);
+ }
+ tabl_file = argv[optind];
+ if(argc > optind + 1) {
+ fprintf (stderr,"Error: %s\n", usage);
+ exit(5);
+ }
+ }
+
+ if((tabl = fopen(tabl_file, "r")) == NULL) { /* try to open file with table */
+ strcpy(table_name, deftablpath); /* copy path to scratch string */
+ strcat(table_name, tabl_file);
+ if((tabl = fopen(table_name, "r")) == NULL) { /* try to open path/file */
+ fprintf(stderr,"Could not find the conversion table file: %s\n",
+ tabl_file);
+ exit(6);
+ }
+ }
+
+ /* read in file version number */
+ if((getnblkline(tabl, 1) < 0) || ((file_version = getnumber(tabl)) < 0)) {
+ tablerr(7, "Could not read file format number");
+ }
+ if(file_version != 1) {
+ tablerr(10, "This format of conversion file is not supported");
+ }
+
+ /* read in delimiters */
+
+ rdelim(&strstart, &strend);
+ rdelim(&liststart, &listend);
+ rdelim(&regexstart, &regexend);
+
+ /* read in starting and ending sequences */
+ begseq = beseq();
+ endseq = beseq();
+
+ /* reserve memory for sequences */
+ chars_left = 5*MAXPAIRS; /* size of allocated block */
+ if((scr1ptr = (char*)malloc(chars_left*sizeof(char)))
+ == NULL) {
+ tablerr(10, "Out of memory for storing sequences");
+ }
+
+ /* Allocate space for inp_maps and out_sets for input set 0 */
+
+ allomaps(0);
+
+ /* Read number of input sets */
+ if((getnblkline(tabl, 1) <= 0) || ((n_inp_sets = getnumber(tabl)) < 0)) {
+ tablerr(10, "Error when reading input set count");
+ }
+
+ if(n_inp_sets >= MAXSETS) {
+ tablerr(10, "Too many input shift sequences");
+ }
+
+ /* read input SI/SO sequences */
+ for (i = 0; i < n_inp_sets; i++) {
+ /* Allocate space for inp_maps and out_sets for input set i+1 */
+ allomaps(i+1);
+
+ /* read in input SHIFTs seq */
+ if(getnblkline(tabl, 1) <= 0) {
+ tablerr(10, "Error when reading output shift sequences");
+ }
+ rdinshift(&inp_SO_data[i], 1);
+ rdinshift(&inp_SO_subs[i], 2);
+ if((inp_SO_subs[i].typ == 2) && (inp_SO_data[i].typ == 0)) {
+ tablerr(10,
+ "Plain string type for matching and substitution expression for output");
+ }
+ rdinshift(&inp_nest_open[i], 1);
+ rdinshift(&inp_nest_close[i], 1);
+ rdinshift(&inp_SI_data[i], 1);
+ rdinshift(&inp_SI_subs[i], 2);
+ if((inp_SI_subs[i].typ == 2) && (inp_SI_data[i].typ == 0)) {
+ tablerr(10,
+ "Plain string type for matching and substitution expression for output");
+ }
+
+ if(debug_flg == 1) {
+ if(inp_SO_data[i].typ == 0) {
+ fprintf(stderr,"%2d) inp_SO =|%s| ", i, (inp_SO_data[i].ad).seq);
+ }
+ else {
+ fprintf(stderr,"%2d) inp_SO =%d ", i, inp_SO_data[i].typ);
+ }
+ if((inp_SO_subs[i].typ == 0) || (inp_SO_subs[i].typ == 2)) {
+ fprintf(stderr,"%2d) inp_SOsub =|%s| ", i, (inp_SO_subs[i].ad).seq);
+ }
+ else {
+ fprintf(stderr,"%2d) inp_SOsub =%d ", i, inp_SO_subs[i].typ);
+ }
+ if(inp_nest_open[i].typ == 0) {
+ fprintf(stderr,"nest_open =|%s| ", (inp_nest_open[i].ad).seq);
+ }
+ else {
+ fprintf(stderr,"nest_open =%d ", inp_nest_open[i].typ);
+ }
+ if(inp_nest_close[i].typ == 0) {
+ fprintf(stderr,"nest_close =|%s| ", (inp_nest_close[i].ad).seq);
+ }
+ else {
+ fprintf(stderr,"nest_close =%d ", inp_nest_close[i].typ);
+ }
+ if(inp_SI_data[i].typ == 0) {
+ fprintf(stderr,"inp_SI =|%s|\n", (inp_SI_data[i].ad).seq);
+ }
+ else {
+ fprintf(stderr,"inp_SI =%d\n", inp_SI_data[i].typ);
+ }
+ if((inp_SI_subs[i].typ == 0) || (inp_SI_subs[i].typ == 2)) {
+ fprintf(stderr,"%2d) inp_SIsub =|%s| ", i, (inp_SI_subs[i].ad).seq);
+ }
+ else {
+ fprintf(stderr,"%2d) inp_SIsub =%d ", i, inp_SI_subs[i].typ);
+ }
+ } /* end debug_flg */
+ }
+
+ if((getnblkline(tabl, 1) <= 0) || ((n_out_sets = getnumber(tabl)) < 0)) {
+ /* read in out SHIFTs count */
+ tablerr(10, "Error when reading output set count");
+ }
+ if(n_out_sets > MAXSETS) {
+ tablerr(10, "Too many output SHIFT sequences requested");
+ }
+
+ for (i = 0; i < n_out_sets; i++) {
+ /* read in out SHIFTs seq */
+ if((getnblkline(tabl, 1) <= 0) ||
+ ((scr1pt = getstring(strstart, strend, tabl)) == (char*)NULL) ||
+ ((scr2pt = getstring(strstart, strend, tabl)) == (char*)NULL)) {
+ tablerr(10, "Error when reading output shift sequences");
+ }
+ convstr(scr1pt, scr1a);
+ out_SO_len[i]= strlen(scr1a);
+ out_SO[i] = savestring(scr1a);
+
+ convstr(scr2pt, scr2a);
+ out_SI_len[i] = strlen(scr2a);
+ out_SI[i] = savestring(scr2a);
+ if(debug_flg == 1) {
+ fprintf(stderr,"%2d) out_SO string=|%s| out_SI string=|%s|\n",
+ i, out_SO[i], out_SI[i]);
+ }
+ } /* end for */
+
+ i = 0;
+ while (getnblkline(tabl, 1) > 0) {
+ if((inp_data[i].set = getnumber(tabl)) < 0) { /* get inp set number */
+ tablerr(10, "Set number for input sequences is wrong");
+ }
+ if(((k = inp_data[i].set) > n_inp_sets) || (k < 0) ) {
+ tablerr(10,"Input set number for a sequence wrong");
+ }
+ curst1 = chknblk(tabl); /* check what type of string follows */
+ if(curst1 == strstart) {
+ mode1 = 1;
+ curend1 = strend;
+ }
+ else if(curst1 == liststart) {
+ mode1 = 2;
+ curend1 = listend;
+ }
+ else if(curst1 == regexstart) {
+ mode1 = 3;
+ curend1 = regexend;
+ }
+ else {
+ tablerr(10, "Delimiter wrong when reading input sequences");
+ }
+ /* get input sequence */
+ if((scr1pt = getstring(curst1, curend1, tabl)) == (char*)NULL) {
+ tablerr(10, "Error reading input sequence");
+ }
+ scr1pt = savestring(scr1pt); /* Save the string */
+
+ if((out_data[i].set = getnumber(tabl)) < -3) { /* get inp set number */
+ tablerr(10, "Wrong code for the output set number");
+ }
+
+ if(out_data[i].set > n_out_sets) {
+ tablerr(10, "Output set number for a sequence is wrong");
+ }
+
+ curst2 = chknblk(tabl); /* check what type of string follows */
+ if(curst2 == strstart) {
+ mode2 = 1;
+ curend2 = strend;
+ }
+ else if(curst2 == liststart) {
+ mode2 = 2;
+ curend2 = listend;
+ }
+ else if(curst2 == regexstart) {
+ mode2 = 3;
+ curend2 = regexend;
+ }
+ else {
+ tablerr(10, "Delimiter wrong when reading sequences");
+ }
+
+ if((scr2pt = getstring(curst2, curend2, tabl)) == (char*)NULL) {
+ tablerr(10, "Error reading input sequence");
+ }
+ scr2pt = savestring(scr2pt);
+
+ /* check if acceptable types for sequences */
+ if((mode2 == 3) && (mode1 != 3)) { /* no regular expressions for output */
+ tablerr(10,
+ "Regular expression as output sequence and input not a regular expression");
+ }
+ else if((mode1 == 1) && (mode2 == 2)) { /* inp string, out list */
+ tablerr(10, "You specified list for output and string for input");
+ }
+ else if((mode1 == 3) && (mode2 == 2)) { /* inp regex, out list */
+ tablerr(10, "You specified string for input and list for output");
+ }
+ else if((mode1 == 2) && (out_data[i].set < 0)) {
+ tablerr(10,
+ "Input LIST and output set code -1/-2/-3 is not supported at this moment");
+ }
+
+ if(mode1 == 2) { /* if list for input expression */
+ /* split string at - sign */
+ splitlist(scr1pt, scr1);
+ if(mode2 == 2) {
+ splitlist(scr2pt, scr2);
+ if(strlen(scr1) != strlen(scr2)) {
+ tablerr(10,
+ "The number of codes in the input and output list is different");
+ }
+ }
+ } /* end mode 2 */
+ else { /* for all other modes, convert the codes */
+ convstr(scr1pt, scr1a); /* convert codes in input string */
+ }
+
+ if((mode1 == 1) && (strlen(scr1a) == 1)) { /* single inp char */
+ /* it is like list with a single character, so cheat */
+ if(out_data[i].set >= 0) {
+ mode1 = 2;
+ strcpy(scr1, scr1a); /* make it a list */
+ }
+ else {
+ tablerr(10,
+ "One-character input strings and output codes -1/-2/-3 are not supported\n");
+ }
+ }
+
+ if(mode1 == 2) { /* fill the lists for mode 2 */
+ if(mode2 == 1) { /* if normal string as output sequence */
+ convstr(scr2pt, scr2);
+ scr2pt = savestring(scr2);
+ }
+ else { /* if mode2 = 2 */
+ scr2pt = scr2;
+ }
+ /* now fill the maps */
+ k = inp_data[i].set;
+ l = out_data[i].set;
+ scr1pt = scr1; /* points at input list */
+ scr2ptr = scr2pt; /* points at output list or string */
+ while (*scr1pt != '\0') {
+ if(mode2 == 2) { /* prepare string with code */
+ scr1a[0] = *scr2ptr++;
+ scr1a[1] = '\0';
+ scr2pt = savestring(scr1a);
+ }
+ ch = intcode(*scr1pt);
+ if((*inp_maps[k])[ch] != (char *)NULL) {
+ fprintf(stderr,
+"You have entered the character |%c| with code \\0d%d for input set %d\n",
+ charcode(ch), ch, k);
+ tablerr(10, "Delete previous references if not needed");
+ }
+
+ (*inp_maps[k])[ch] = scr2pt; /* save output sequence */
+ (*out_sets[k])[ch] = l; /* save output set number */
+ scr1pt++; /* next code for output */
+ }
+ i--; /* do not save this line in inp_str and out */
+ } /* end if mode1 = 2*/
+ else if(mode1 == 1) { /* if multicharacter input string */
+ scr1pt = savestring(scr1a);
+ convstr(scr2pt, scr2a);
+ scr2pt = savestring(scr2a);
+ inp_data[i].typ = 0;
+ inp_data[i].len = strlen(scr1pt);
+ (inp_data[i].ad).seq = scr1pt;
+ out_data[i].typ = 0;
+ out_data[i].len = strlen(scr2pt);
+ (out_data[i].ad).seq = scr2pt;
+ }
+ else if(mode1 == 3) { /* if regular expression for input */
+ inp_data[i].typ = 1;
+ l = strlen(scr1a); /* length of converted input expression */
+ if(scr1a[0] == '^') {
+ tablerr(10,
+ "The ^ (beginning anchor) is not supported");
+ }
+ if((scr1a[l-1] == '$') && (scr1a[l-1] != '\\')) {
+ tablerr(10, "The $ (end anchor) is not supported");
+ }
+
+ strcpy(regerrstr, "Error in input regular expression sequence: ");
+
+ if((regauxptr = reg_comp(scr1a)) == NULL) {
+ tablerr(10, "Error in the input regular expression sequence");
+ }
+ (inp_data[i].ad).re = regauxptr;
+ convstr(scr2pt, scr1a); /* convert codes in out string */
+ scr2pt = savestring(scr1a);
+ if(mode2 == 3) { /* mark type of expression plan(0)/substit string(2) */
+ out_data[i].typ = 2;
+ }
+ else {
+ out_data[i].typ = 0;
+ }
+ out_data[i].len = strlen(scr2pt);
+ (out_data[i].ad).seq = scr2pt;
+ }
+
+ /* advance pointers */
+
+ n_conv_seq = ++i;
+ if(n_conv_seq >= (MAXPAIRS-1)) {
+ tablerr(10,
+ "Too many transliteration sequences. Recompile program with larger MAXPAIRS");
+ }
+ } /* end while getnblkline */
+
+ if(debug_flg == 1) {
+ fprintf(stderr,"Multicharacter input sequences \n");
+ for(i=0; i < n_conv_seq; i++) {
+ fprintf(stderr,"%2d) inp.type=%2d inp.set=%2d out.type=%2d out.set=%2d\n",
+ i, inp_data[i].typ, inp_data[i].set, out_data[i].typ, out_data[i].set);
+ if(inp_data[i].typ == 0) {
+ fprintf(stderr," Inp.str=|%s| ", (inp_data[i].ad).seq);
+ }
+ fprintf(stderr, "Out.str=|%s|\n", (out_data[i].ad).seq);
+ }
+ fprintf(stderr,
+ "input_set charcode input_character --> output_set output_string/\n");
+ for(i = 0; i <= n_inp_sets; i++) {
+ for(k = 0; k < 256; k++) {
+ if((*inp_maps[i])[k] != (char *)NULL) {
+ fprintf(stderr," %2d \\%04o %c --> %2d %s\n",
+ i, k, charcode(k), (*out_sets[i])[k], (*inp_maps[i])[k]);
+ }
+ }
+ }
+ }
+
+
+ fprintf(outf,"%s",begseq); /* output starting sequence */
+
+ /* transliterate input file to output file */
+
+ level = 0;
+ if(n_inp_sets > 0) {
+ cur_inp_set = 1;
+ }
+ else {
+ cur_inp_set = 0;
+ }
+ inp_cur_set[level] = cur_inp_set; /* 1st input set is a default */
+ inp_cur_nest[level] = 0;
+ scr1ptr = scr1a;
+ scr1ptr[0] = '\0';
+ scr2ptr = scr2a;
+ scr2ptr[0] = '\0';
+ scrcurptr = scr2ptr;
+ chars_left = 0;
+ buffer_size = MAXBUFF/2; /* will be set to 0 if EOF */
+ out_cur_set = 1; /* no output set yet */
+
+
+ while ( buffer_size > 0) {
+ /* swap input buffer pointers */
+ scrauxptr = scr2ptr;
+ scr2ptr = scr1ptr;
+ scr1ptr = scrauxptr;
+
+ scrauxptr = scrcurptr; /* old buffer last pointer */
+ scrcurptr = scr1ptr; /* new buffer start */
+
+ /* copy remains of old buffer to new one */
+ strcpy(scrcurptr, scrauxptr);
+
+ l = chars_left;
+ for(i = 0; i < buffer_size; i++) { /* append input chars to scr1a */
+ if((k = fgetc(inpf)) == EOF) {
+ buffer_size = 0; /* end of file */
+ break;
+ }
+ else if(k == '\0') { /* skip zero characters */
+ i--;
+ continue;
+ }
+ else { /* if normal character */
+ *(scrcurptr + l++) = k;
+ }
+ }
+ *(scrcurptr + l) = '\0'; /* terminate buffer with 0 */
+ chars_left = l; ; /* length of combined string */
+ if(buffer_size == 0) { /* if EOF */
+ chars_left += MAXMATCH+1; /* fool the program that there is more */
+ }
+
+ while (chars_left > MAXMATCH) {
+ /* check if end of scrcurptr --- it means end of input file, since only
+ then it can get to the end of the string, otherwise it stops
+ MAXMATCH before */
+ if(*scrcurptr == '\0') { /* end of file */
+ if(n_out_sets > 0) { /* if multiple output sets */
+ l = out_SI_len[out_cur_set - 1];
+ for(i = 0; i < l; i++) {
+ k = out_SI[out_cur_set-1][i];
+ fputc(k, outf);
+ }
+ break;
+ }
+ }
+
+Backstep2:
+
+ /* check if SHIFT IN sequence for current input set */
+ if(n_inp_sets > 0) {
+ /* check SI sequence only when nesting count is 0 */
+ if(inp_cur_nest[level] == 0) {
+ if(match_subs(&inp_SI_data[cur_inp_set-1],
+ &inp_SO_subs[cur_inp_set-1]) > 0) { /* is SI */
+ repl_inp();
+ level--;
+ if(level < 0) {
+ level = 0;
+ fprintf(stderr,
+"More SHIFT_IN sequences than corresponding SHIFT_OUT sequences in text\n");
+ }
+ cur_inp_set = inp_cur_set[level]; /* set previous inp set number */
+ continue;
+ }
+ }
+ }
+
+ /* check if new set of input chars started */
+ l = -1;
+ for (i = 0; i < n_inp_sets; i++) {
+ if(match_subs(&inp_SO_data[i], &inp_SO_subs[i]) > 0) {
+ l = i;
+ break;
+ }
+ }
+ if(l >= 0) { /* is SO matched */
+ repl_inp(); /* substitute SO_data with SO_seqs */
+ if((inp_SI_data[l].len > 0) || (inp_SI_data[l].typ == 1)){
+ /* increase level only is SHIFT IN present */
+ level++; /* increase number of "opened" input sets */
+ inp_cur_nest[level] = 0; /* It is new level,zero nesting sequences */
+ if(level > MAXLEVEL) {
+ fprintf(stderr,
+ "Too many nested input character sets in input file\n");
+ exit(39);
+ }
+ }
+ l++; /* sets in arrays are saved starting from 0,
+ i.e., set nr 1 corresponds to element [0], 2 --> [1], etc. */
+ inp_cur_set[level] = l; /* save set number at current nesting level */
+ cur_inp_set = l;
+ continue;
+ }
+
+ /* Now check if the input sequence corresponding to cur_inp_set
+ matches the string */
+
+Backstep1: /* if output set number is -2, start again */
+ flg = -1;
+ for(i = 0; i < n_conv_seq; i++) {
+ k = inp_data[i].set; /*get set number for current transliteration seq */
+ if((k == cur_inp_set) || (k == 0)) { /* if equal to current or 0 */
+ if(match_subs(&inp_data[i], &out_data[i]) > 0) {
+ if(out_set_number < 0) { /* if backsteping */
+ repl_inp(); /* replace */
+ if (out_set_number == -1) {
+ flg = -1;
+ }
+ else if (out_set_number == -2) {
+ goto Backstep1;
+ }
+ else if (out_set_number == -3) {
+ goto Backstep2;
+ }
+ }
+ else { /* if set number >= 0 */
+ flg = i;
+ break;
+ }
+ }
+ }
+ }
+
+ if(flg < 0) { /* if no matching input multichar sequence found */
+ ch = intcode(*scrcurptr); /* current input character */
+ if((out_seq_ptr = (*inp_maps[cur_inp_set])[ch]) != NULL) {
+ /* if out_seq exists for current input set */
+ out_set_number = (*out_sets[cur_inp_set])[ch];
+ flg = 1;
+ }
+ else if((out_seq_ptr = (*inp_maps[0])[ch]) != NULL) {
+ /* if out_seq exitst for set number 0 */
+ flg = 1;
+ out_set_number = (*out_sets[0])[ch];
+ }
+ if(flg >= 0) { /* set other things */
+ out_seq_length = strlen(out_seq_ptr);
+ inp_seq_length = 1;
+ }
+ }
+
+ if(flg < 0) { /* if no match found, copy the input char to output */
+ scr1[0] = *scrcurptr;
+ scr1[1] = '\0';
+ if(*scrcurptr != '\0') {
+ out_seq_length = 1;
+ }
+ else {
+ out_seq_length = 0;
+ }
+
+ inp_seq_length = 1;
+ out_set_number = 0;
+ out_seq_ptr = scr1;
+ }
+
+ /* At this point all matches and substitutuions have been done */
+
+ /* check if nesting sequences found for a given set and increase or
+ decrease nesting if needed */
+ if((n_inp_sets > 0) && (out_cur_set > 0)) {
+ for(i = 0; i < inp_seq_length; i++) {
+ if(chkseqs(1, &inp_nest_close[cur_inp_set-1], scrcurptr+i) >= 0) {
+ inp_cur_nest[level]--;
+ }
+ if(chkseqs(1, &inp_nest_open[cur_inp_set-1], scrcurptr+i) >= 0) {
+ inp_cur_nest[level]++;
+ }
+ }
+ }
+
+ /* output the SI/SO sequences if output set changed */
+ if((n_out_sets > 0) &&
+ (out_set_number > 0)) { /* check if multiple output sets */
+ if(out_cur_set != out_set_number) { /* if new set starts */
+ if(out_cur_set > 0) { /* put SHIFT IN for a previous set */
+ l = out_SI_len[out_cur_set-1]; /* old SHIFT IN seq length */
+ for(i = 0; i < l; i++) { /* output old SHIFT IN */
+ k = out_SI[out_cur_set-1][i];
+ fputc(k, outf);
+ }
+ }
+ out_cur_set = out_set_number; /* make it current now */
+ if(out_cur_set > 0) {
+ l = out_SO_len[out_cur_set-1]; /* length of SHIFT OUT sequence */
+ for(i = 0; i < l; i++) { /* output SHIFT OUT seq for this set */
+ k = out_SO[out_cur_set-1][i];
+ fputc(k, outf);
+ }
+ }
+ } /* end out_set changes */
+ } /* if multiple output sets specified */
+
+ /* now output the corresponding sequence */
+ for(i = 0; i < out_seq_length; i++) {
+ k = *(out_seq_ptr+i);
+ fputc(k,outf);
+ }
+
+ /* move past processed input text */
+ scrcurptr += inp_seq_length;
+ chars_left -= inp_seq_length;
+
+
+ } /* while scanning input characters */
+
+ } /* end while reading input file */
+ fprintf(outf,"%s",endseq); /* output ending sequence */
+ fclose(inpf);
+ fclose(outf);
+ exit(0);
+}
+