home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume36 / translit / part03 < prev    next >
Encoding:
Text File  |  1993-03-21  |  59.4 KB  |  1,868 lines

  1. Newsgroups: comp.sources.misc
  2. From: jkl@osc.edu (Jan Labanowski)
  3. Subject: v36i025:  translit - transliterate foreign alphabets, Part03/10
  4. Message-ID: <1993Mar19.224349.11873@sparky.imd.sterling.com>
  5. X-Md4-Signature: e266dff38e849f207e0bbd3b969b2c3f
  6. Date: Fri, 19 Mar 1993 22:43:49 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: jkl@osc.edu (Jan Labanowski)
  10. Posting-number: Volume 36, Issue 25
  11. Archive-name: translit/part03
  12. Environment: UNIX, MS-DOS, VMS
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then feed it
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # Contents:  order.txt translit.c
  19. # Wrapped by kent@sparky on Fri Mar 19 16:00:10 1993
  20. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  21. echo If this archive is complete, you will see the following message:
  22. echo '          "shar: End of archive 3 (of 10)."'
  23. if test -f 'order.txt' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'order.txt'\"
  25. else
  26.   echo shar: Extracting \"'order.txt'\" \(2315 characters\)
  27.   sed "s/^X//" >'order.txt' <<'END_OF_FILE'
  28. X    From:
  29. X
  30. X
  31. X
  32. X
  33. X    To: JKL ENTERPRISES, INC.
  34. X        P.O.Box 21821
  35. X        Upper Arlington, OH 43221-0821
  36. X
  37. X
  38. X    Please send me the executable, ready to run TRANSLIT program on
  39. X    a diskette for the IBM-PC computer or compatible for MS-DOS 2.1
  40. X    or higher [see footnote].
  41. X
  42. X    I request the following medium (choose one):
  43. X
  44. X       _____   5.25 inch 360 kByte diskette
  45. X
  46. X       _____   3.5  inch 720 kByte diskette
  47. X    with installation instructions. I understand that I will also receive
  48. X    the transliteration tables and complete source of the program and
  49. X    documentation as disk files.
  50. X
  51. X    I understand that the TRANSLIT program comes without any warranty, and
  52. X    the only claim which I can make towards JKL ENTERPRISES, INC. is to
  53. X    replace a defective diskette. I also understand that this offer may be
  54. X    withdrawn at any time.
  55. X
  56. X    Prepaid orders (i.e., orders accompanied with a check or money order)
  57. X    for the program are $15 (fifteen US Dollars). If an invoice is requested
  58. X    there will be additional charge of $5 (five US Dollars) for processing.
  59. X    There is no shipping and handling charge for orders within US. Outside
  60. X    US please add the $1 dollar for Shipping and Handling. Diskette with the
  61. X    program will be sent via 1st Class Mail or Air Mail, whichever applies.
  62. X    I understand that the shipment will be made when funds are received.
  63. X
  64. X    I enclose (fill in appropriate blanks):
  65. X       
  66. X        for the program ($15 per disk):                   ______
  67. X
  68. X        for the invoice to be billed later ($5)           ______
  69. X
  70. X        Shipping/Handling if outside USA ($1 per disk)    ______
  71. X    -------------------------------------------------------------
  72. X
  73. X        Total:                                            ______
  74. X
  75. X   Ohio residents must add 5.75% tax of the Total:        ______
  76. X
  77. X        Total+Tax(if Ohio Resident)                       ______ 
  78. X
  79. X   Please send the program to the following address:
  80. X
  81. X   Name:                     __________________________________
  82. X  
  83. X   Organization:             __________________________________
  84. X
  85. X   Address:                  __________________________________
  86. X
  87. X   Town, State, Zip-code:    __________________________________
  88. X
  89. X_____________________________________________________
  90. X [Footnote]: inquire for other computers/operating systems.
  91. END_OF_FILE
  92.   if test 2315 -ne `wc -c <'order.txt'`; then
  93.     echo shar: \"'order.txt'\" unpacked with wrong size!
  94.   fi
  95.   # end of 'order.txt'
  96. fi
  97. if test -f 'translit.c' -a "${1}" != "-c" ; then 
  98.   echo shar: Will not clobber existing file \"'translit.c'\"
  99. else
  100.   echo shar: Extracting \"'translit.c'\" \(54601 characters\)
  101.   sed "s/^X//" >'translit.c' <<'END_OF_FILE'
  102. X/* This is a program fom transliterating files from one character set to
  103. X   another. 
  104. X   TRANSLIT --- Version 1.0, Jan. 10, 1993.
  105. X   Copyright (c) by Jan Labanowski, 1993 and JKL Enterprises, Inc.
  106. X   Permission is given to disribute this program freely in accordance with
  107. X   the rules and conditions spelled out in the program documentation. If you
  108. X   got this program without the documentation, or if some files were missing,
  109. X   somebody must have violated the rules. In this case, please delete the the
  110. X   program and obtain the information on how to get the complete distribution
  111. X   from the author. The rules require that the whole package is distributed 
  112. X   (i.e., the source code, the transliteration tables, and the documentation).
  113. X
  114. X   Author: Jan Labanowski, P.O.Box 21821, Columbus, OH 43221-0821, USA
  115. X   E-mail: jkl@osc.edu, JKL@OHSTPY.BITNET
  116. X */
  117. X
  118. X#include "paths.h"              /* for local definitions */
  119. X#include "reg_exp.h"             /* for regexp package */
  120. X
  121. X
  122. X#define OPTIONS       "i:o:t:d"   /* allowed options on command line */
  123. X#define MAXPAIRS      1000        /* maximum number of conversion pairs */
  124. X#define MAXSETS       10          /* maximum number of shift in/out sets */
  125. X#define MAXLEVEL      10         /* maximum set nesting level */
  126. X#define MAXBUFF       1000        /* maximum size of the buffer */
  127. X#define MAXMATCH      100         /* maximum length of match to regular exp. */
  128. X
  129. X
  130. X/* define all local functions as static if compiler likes it */
  131. X#if STATICFUN
  132. X#define STATIC static
  133. X#else
  134. X#define STATIC
  135. X#endif
  136. X
  137. X/* types to hold the translation maps for single chars. If inp_maps is of
  138. X * type IMAPP, then character of code c in set k will correspond to
  139. X * a string pointed by (*inp_maps[k])[c]; 
  140. X */
  141. X
  142. X/*  ========== now include definitions for paths and regexp */
  143. X
  144. X
  145. Xtypedef char*   IMAP[256];      /* type IMAP is a 256 element array
  146. X                                             of pointers to string */
  147. Xtypedef IMAP*   IMAPP[MAXSETS]; /* array of pointers to IMAP */
  148. X
  149. X/* types to hold output set number for a single char. if out_sets is of type
  150. X *  OSETP and c is a code, and k is the set of input character, then output
  151. X *  set number is (*out_sets[k])[c]; */
  152. Xtypedef int        OSET[256];
  153. Xtypedef OSET*      OSETP[MAXSETS];
  154. X
  155. X
  156. Xtypedef union  {
  157. X                char   *seq;   /* pointer to a string */
  158. X                reg_exp  *re;   /* pointer to a regular expression "program */
  159. X               } ADDR;
  160. X
  161. X
  162. Xtypedef struct {
  163. X                 int   typ;    /* type of pointer in ADDR union:
  164. X                                  0-string (seq), 1-input regexp (re),
  165. X                                  2-output regexp (seq) (output regexp
  166. X                                  is a string !)*/
  167. X                 int   len;    /* length of a string if present */
  168. X                 int   set;    /* character set number for the string */
  169. X                 ADDR  ad;     /* string or regexp program */
  170. X                }   SDATA;
  171. X
  172. X
  173. X/* Some compiler represent character codes > 127 as negative numbers, i.e.,
  174. X * character 255 is -1, char 254 is -2, etc.
  175. X * The flag SIGNED_CHAR_TYPE is set by the program, (program checks which
  176. X * convention is used. It is set to 1, if characters have sign (i.e., 255=-1)
  177. X * and is set to 0 if characters are unsigned (i.e., 255=255). Do not touch
  178. X * this declaration, unless you know what you are doing.
  179. X */
  180. Xint  SIGNED_CHAR_TYPE;
  181. X
  182. X char tabline[MAXBUFF]; /* line of text from conversion table file */
  183. X char last_tab_line[MAXBUFF];
  184. X char *lineptr;         /* pointer to the first unread character of tabline */
  185. X int   n_line_chars;    /* number of characters in tabline buffer */
  186. X int  chars_left;       /* no. of chars left in input buffer */
  187. X
  188. X int  memleft;          /* tells how much memory is left in allocated area */
  189. X char *memptr;          /* pointer for memory allocation area */
  190. X char regerrstr[100];   /* string to hold error message from regular exp */
  191. X reg_exp *regauxptr;     /* aux pointer for regular expresion structure */
  192. X int debug_flg=0;       /* if 1, then additional info sent to stderr */
  193. X
  194. X FILE *inpf;            /* input file pointer */
  195. X FILE *outf;            /* output file pointer */
  196. X FILE *tabl;            /* file with translation table */
  197. X
  198. X int n_conv_seq;             /* number of conversion sequences */
  199. X SDATA inp_data[MAXPAIRS];   /* structure to hold types, lengths and pointers
  200. X                                for input sequences */
  201. X SDATA out_data[MAXPAIRS];   /* structure to hold types lengths and pointers
  202. X                                for output sequences */
  203. X SDATA inp_SO_data[MAXSETS]; /* structure with types, lens, ptrs for inp_SO*/
  204. X SDATA inp_SO_subs[MAXSETS]; /* holds substitution string/regexp for inp_SO*/
  205. X SDATA inp_SI_data[MAXSETS]; /* structure with types, lens, ptrs for inp_SI*/
  206. X SDATA inp_SI_subs[MAXSETS]; /* holds substitution string/regexp for inp SI*/
  207. X SDATA inp_nest_open[MAXSETS]; /* for sick transliteration cases, like TeX */
  208. X SDATA inp_nest_close[MAXSETS]; /* where you need to count {} pairs */
  209. X
  210. X SDATA *junky;
  211. X
  212. X IMAPP inp_maps;             /* maps for single character sequences, 
  213. X                    array of pointers. Element of the array is a pointer
  214. X                    to the array of pointers which point at strings */
  215. X OSETP out_sets;   /* output set numbers corresponding to inp_maps 
  216. X                    array of pointers to integer pointers */
  217. X int  n_inp_sets;            /* number of input sets */
  218. X int  n_out_sets;            /* number of output sets */
  219. X char *out_SI[MAXSETS];      /* pointer to output shift in sequences */
  220. X char *out_SO[MAXSETS];      /* pointer to output shift out sequences */
  221. X int  out_SI_len[MAXSETS];   /* out SI sequence length */
  222. X int  out_SO_len[MAXSETS];   /* out SO sequence length */
  223. X
  224. X char *begseq,   /* sequence to be written at the beginning of output*/
  225. X       *endseq;  /* sequence to be written at the end of output file */
  226. X
  227. X int file_version;           /* conversion table version number */
  228. X int strstart, strend,       /* codes delimiting strings */
  229. X     liststart, listend,     /* codes delimiting lists */
  230. X     regexstart, regexend,   /* codes delimiting expressions */
  231. X     curst1, curend1,
  232. X     curst2, curend2;        /* auxiliary */
  233. X
  234. X char  scr1[MAXBUFF], scr2[MAXBUFF],            /* scratch space */
  235. X      scr1a[MAXBUFF], scr2a[MAXBUFF];           /* scratch space */
  236. X char *scr1ptr, *scr2ptr, *scr1pt, *scr2pt,
  237. X                *scrauxptr, *scrcurptr;         /* aux string pointers */
  238. X
  239. X int  inp_seq_length;       /* length of input sequence */
  240. X int  out_seq_length;       /* length of output sequence */
  241. X int  out_set_number;       /* number of output set */
  242. X char *out_seq_ptr;        /* pointer to output sequence */
  243. X
  244. X reg_exp *reg_comp();
  245. X int reg_try();
  246. X void reg_sub();
  247. X void reg_error();
  248. X
  249. X/* fix  if no strchr routine in the libarry */
  250. X#if STRCHR
  251. X#else
  252. X#define strchr indexfun
  253. X#endif
  254. X
  255. X/* this is index which is equivalent to strchr */
  256. Xchar *indexfun (s, c)
  257. Xchar    *s;
  258. Xint     c;
  259. X    {
  260. X    while (*s)
  261. X        if (c == *s) return (s);
  262. X        else s++;
  263. X    return (NULL);
  264. X    }
  265. X
  266. X
  267. X/* ============================================================ */
  268. X
  269. X/* include code for getopt() if not known to compiler */
  270. X
  271. X#if GETOPT
  272. X#else
  273. X
  274. X/*
  275. X       This is a some getopt I took from the net and do not remember
  276. X       who actually wrote this
  277. X*/
  278. X
  279. X#define    ARGCH    (int)':'
  280. X#define BADCH     (int)'?'
  281. X#define EMSG     ""
  282. X#define    ENDARGS  "--"
  283. X
  284. X/*
  285. X * get option letter from argument vector
  286. X */
  287. Xint    opterr = 1,        /* useless, never set or used */
  288. X    optind = 1,        /* index into parent argv vector */
  289. X    optopt;            /* character checked for validity */
  290. Xchar    *optarg;        /* argument associated with option */
  291. X
  292. X#define tell(s)    fputs(*nargv,stderr);fputs(s,stderr); \
  293. X        fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
  294. X
  295. X
  296. XSTATIC int getopt(nargc,nargv,ostr)
  297. Xint    nargc;
  298. Xchar    **nargv,
  299. X    *ostr;
  300. X{
  301. X    static char    *place = EMSG;    /* option letter processing */
  302. X    register char    *oli;        /* option letter list index */
  303. X
  304. X    if(!*place) {            /* update scanning pointer */
  305. X        if(optind >= nargc || *(place = nargv[optind]) != '-' ||
  306. X             !*++place) return(EOF);
  307. X        if (*place == '-') {    /* found "--" */
  308. X            ++optind;
  309. X            return(EOF);
  310. X        }
  311. X    }                /* option letter okay? */
  312. X    if ((optopt = (int)*place++) == ARGCH || !(oli = strchr(ostr,optopt))) {
  313. X        if(!*place) ++optind;
  314. X        tell(": illegal option -- ");
  315. X    }
  316. X    if (*++oli != ARGCH) {        /* don't need argument */
  317. X        optarg = NULL;
  318. X        if (!*place) ++optind;
  319. X    }
  320. X    else {                /* need an argument */
  321. X        if (*place) optarg = place;    /* no white space */
  322. X        else if (nargc <= ++optind) {    /* no arg */
  323. X            place = EMSG;
  324. X            tell(": option requires an argument -- ");
  325. X        }
  326. X         else optarg = nargv[optind];    /* white space */
  327. X        place = EMSG;
  328. X        ++optind;
  329. X    }
  330. X    return(optopt);            /* dump back option letter */
  331. X}
  332. X
  333. X#endif
  334. X
  335. X
  336. X/* ================= charcode ======================
  337. X * returns the code of the character given its integer code. If global
  338. X * variable SIGNED_CHAR_TYPE flag is 1, then character code is negative
  339. X * for chars >= 128, otherwise they are passed through.
  340. X * ================================================== */
  341. XSTATIC char charcode (intcde)
  342. Xint intcde;
  343. X{
  344. X if(SIGNED_CHAR_TYPE == 1) {  /* if signed chars used */
  345. X   if(intcde >= 128) {        /* if integer code is larger than 128 */
  346. X     return((char)(intcde - 256));   /* make it negative complement */
  347. X     }
  348. X   else {      /* return the original code */
  349. X     return((char)intcde);
  350. X     }
  351. X   }
  352. X else {
  353. X   return((char)intcde);
  354. X   }
  355. X}
  356. X/* ================= intcode =====================
  357. X * returns integer code of a character depending on the value of
  358. X * SIGNED_CHAR_TYPE flag
  359. X * =============================================== */
  360. Xint intcode(charcde)
  361. Xchar charcde;
  362. X{
  363. X if(SIGNED_CHAR_TYPE == 1) {  /* if signed chars used */
  364. X   if((int)charcde < (int)0) {     /* if negative code */
  365. X     return((int)((int)charcde + 256));   /* convert to positive */
  366. X     }
  367. X   else {      /* return the original code */
  368. X     return((int)charcde);
  369. X     }
  370. X   }
  371. X else {
  372. X   return((int)charcde);
  373. X   }
  374. X}
  375. X
  376. X/* ================= tablerr ======================
  377. X * terminates the program with a message to stderr and contents of
  378. X * the buffer. num - exit status, errmsg - message
  379. X * ================================================ */
  380. XSTATIC int tablerr(num, errmsg)
  381. Xint num;
  382. Xchar *errmsg;
  383. X{
  384. X fprintf(stderr,"%s\n", errmsg);
  385. X fprintf(stderr,
  386. X "Current contents of the input buffer for conversion table file:\n");
  387. X fprintf(stderr,"%s\n", last_tab_line);
  388. X exit(num);
  389. X return(0);  /* to keep compiler happy that there is return from function */
  390. X}
  391. X   
  392. X/* ================= getnblkline ====================
  393. X * gets a nonblank line from tabl file and resets pointers if clearflg == 1,
  394. X * otherwise, appends the line to the current buffer.
  395. X * Line is stored in the global variable tabline. The global *lineptr
  396. X * is reset to line beginning.
  397. X * If EOF reached, or line too long, returns -1,  else a number of chars in
  398. X * the line. If line starts with # or ! in first column, it is skipped.
  399. X * ==================================================  */
  400. XSTATIC int getnblkline(fileptr, clearflg)
  401. XFILE *fileptr;
  402. Xint clearflg;
  403. X{
  404. X int  l, maxc;
  405. X char *auxptr;
  406. X if(clearflg == 1) {
  407. X   n_line_chars = 0;
  408. X   lineptr = tabline;
  409. X   }
  410. X maxc = MAXBUFF - n_line_chars -2;  /* how much space in the buffer */
  411. X while (fgets (lineptr, maxc, fileptr) != NULL) {
  412. X   strcpy(last_tab_line, lineptr);   /* save current line for error messages */
  413. X   if((*lineptr == '#') || (*lineptr == '!')) {   /* skip comment lines */
  414. X     continue;
  415. X     }
  416. X   l = strlen(lineptr);  /* how many chars we read ? */
  417. X   n_line_chars += l;    /* how many chars in the buffer */
  418. X
  419. X   if(n_line_chars >  MAXBUFF-5) {    /* if line too long */
  420. X     return(-1);
  421. X     }
  422. X   if(clearflg == 1) { /* do it only if first line is fetched */
  423. X     auxptr = lineptr;
  424. X     while ((isspace(*auxptr) != 0) && (*auxptr != '\0')) {
  425. X       auxptr++;   /* skip front spaces */
  426. X       }
  427. X
  428. X     if(*auxptr == '\0') {   /* if blank line */
  429. X       continue;
  430. X       }
  431. X     }
  432. X   return(l);   /* return length of line just read */
  433. X   }  /* end while */
  434. X return(-1);   /* end of file found */
  435. X}
  436. X/* ================= chknblk ==========================
  437. X * returns a code of the first nonblank character at the current position
  438. X * of tabline buffer. The lineptr is left at this char (NOT AT THE NEXT CHAR !
  439. X * If no nonblank  * character, returns -1.
  440. X * ==================================================== */
  441. XSTATIC int chknblk(fileptr)
  442. XFILE *fileptr;
  443. X{
  444. X int ch;
  445. X
  446. X Fetch_next:
  447. X while (*lineptr != '\0') {
  448. X   if(isspace(*lineptr) == 0) {
  449. X     ch = intcode(*lineptr);
  450. X     return(ch);
  451. X     }
  452. X   lineptr++;
  453. X   }
  454. X if(getnblkline(fileptr, 0) > 0) {
  455. X   goto Fetch_next;
  456. X   }
  457. X else {
  458. X   return(-1);
  459. X   }
  460. X}
  461. X
  462. X/* ================= getnumber ===========================
  463. X * retrieves integer nonnegative decimal number from a the current
  464. X * line (tabline).
  465. X * Returns the number, or -9999 if no good number in the line 
  466. X * only number < 1000 allowed
  467. X * ========================================================== */
  468. XSTATIC int getnumber(fileptr)
  469. XFILE *fileptr;
  470. X{
  471. X int num, flg, sign;
  472. X num = 0;
  473. X flg = 0; 
  474. X sign = 0;
  475. X
  476. XNext_line:
  477. X while (*lineptr != '\0') {
  478. X   if(flg == 0) {   /* only spaces found till now */
  479. X     if(isspace(*lineptr) != 0) {
  480. X       lineptr++;
  481. X       continue;
  482. X       }
  483. X     else {
  484. X       flg = 1;   /* the nonblank char found */
  485. X       }
  486. X     }
  487. X
  488. X   if(flg == 1) {  /* the nonblank char was found */
  489. X     if(sign == 0) {   /* sign may only be located before the number */
  490. X       if(*lineptr == '-') {   
  491. X         sign = -1;
  492. X         lineptr++;
  493. X         }
  494. X       else if(*lineptr == '+') {
  495. X         sign = 1;
  496. X         lineptr++;
  497. X         }
  498. X       else {  /* set it to +1, so it is checked only once */
  499. X         sign = 1;
  500. X         }
  501. X       }
  502. X     if(isdigit(*lineptr) != 0) {
  503. X       num = 10*num + *lineptr - '0';
  504. X       if(num > 1000) {
  505. X         return(-9999);    /* number too large */
  506. X         }
  507. X       } 
  508. X     else if(isspace(*lineptr) != 0) {  /* end of number */
  509. X       return(num*sign);
  510. X       }
  511. X     else {
  512. X       return(-9999);  /* some strange character */
  513. X       }
  514. X     }
  515. X   lineptr++;   /* to next character */
  516. X   }
  517. X if(flg == 1) {  /* if valid number collected before '\0' */
  518. X   return(num*sign);
  519. X   }
  520. X else {
  521. X   if(getnblkline(fileptr, 0) > 0) {
  522. X     goto Next_line;
  523. X     }
  524. X   else {
  525. X     return(-9999);   /* if no number before end of file, error */
  526. X     }
  527. X   }
  528. X}
  529. X
  530. X
  531. X/* ================= getstring ==========================
  532. X * returns the pointer to the string from the tabline. The pointer is
  533. X * volatile, and will point to garbage after next getnblkline call, so
  534. X * you need to copy it (or use it) immedaitely after the call.
  535. X * Returns a pointer to string if successful, and NULL pointer if not.
  536. X * startcode --- character code which starts the string (it is not
  537. X *               included in the string. If startcode = '\0', the
  538. X *               string is collected from the curent pointer to a buffer.
  539. X * endcode   --- character which ends the string. It is not included in
  540. X *               the string. If endcode = '\0', then string is collected
  541. X *               until first blank or end of string found.
  542. X * If no startcode found or no endcode found, the NULL string is returned.
  543. X * ========================================================= */
  544. X
  545. XSTATIC char *getstring(startcode, endcode, fileptr)
  546. Xint startcode, endcode;
  547. XFILE *fileptr;
  548. X{
  549. X int flg;
  550. X char *startptr;
  551. X
  552. X flg = 0; 
  553. XRead_next_line:
  554. X while (*lineptr != '\0') {
  555. X   if(flg == 0) {   /* if startcode not found yet */
  556. X     if(startcode != 0) {
  557. X       if(charcode(startcode) == *lineptr) {
  558. X         flg = 1;   /* the startcode found */
  559. X         lineptr++;
  560. X         startptr = lineptr;  /* skip startcode */
  561. X         continue;
  562. X         }
  563. X       else {
  564. X         lineptr++;
  565. X         continue;
  566. X         }
  567. X       }
  568. X     else {   /* startcode is 0 */
  569. X       flg = 1;
  570. X       startptr = lineptr;
  571. X       lineptr++;
  572. X       continue;
  573. X       }
  574. X     }  /* end flg == 0 */
  575. X
  576. X   if(flg == 1) {  /* the 1st char was found */
  577. X     if(endcode == 0) {   /* if stop on blank requested */
  578. X       if(isspace(*lineptr) != 0) {  /* if space found */
  579. X         *lineptr = '\0';   /* mark string end */
  580. X         lineptr++;         /* advance pointer */
  581. X         return(startptr);
  582. X         }
  583. X       else {   /* collect chars */
  584. X         lineptr++;
  585. X         continue;
  586. X         }
  587. X       }
  588. X     else if(charcode(*lineptr) == endcode) {  /* if stop at endcode */
  589. X       *lineptr = '\0';
  590. X       lineptr++;
  591. X       return(startptr);
  592. X       }
  593. X     else { /* if not endcode , collect next characters */
  594. X       lineptr++;
  595. X       continue;
  596. X       }
  597. X     }   /* end flg == 1 */  
  598. X   }   /* end while */
  599. X
  600. X /* the buffer was exhausted */
  601. X if(endcode == 0) {
  602. X   return(startptr);
  603. X   }
  604. X else {
  605. X   if(getnblkline(fileptr, 0) > 0) {
  606. X     goto Read_next_line;
  607. X     }
  608. X   else {
  609. X     return((char *)NULL);
  610. X     }
  611. X   }
  612. X}
  613. X
  614. X/* ============================ convnum ===================
  615. X * returns a nonegative number based on str. Scans the string
  616. X * from position posbeg, and returns first invalid character position
  617. X * in posend. If error, returns -1 (less than 2 characters, num > 255).
  618. X * str - scanned string
  619. X * digits  string of allowed ordered digits in lowercase
  620. X * posbeg - start
  621. X * ======================================================== */
  622. XSTATIC int convnum(buff, digits, posbeg)
  623. Xchar *buff, *digits;
  624. Xint posbeg;
  625. X{
  626. X int num, i, l, d, base;
  627. X
  628. X base = strlen(digits);
  629. X num = 0;
  630. X i = posbeg;
  631. X
  632. X while (buff[i] != '\0') {
  633. X   d = -1;
  634. X   for(l = 0; l < base; l++) {
  635. X     if(buff[i] == digits[l]) {
  636. X       d = l;
  637. X       break;
  638. X       }
  639. X     }
  640. X   if(d >= 0) {
  641. X     num = d + num*base;
  642. X     if(num > 255) {  /* if code too large */
  643. X       return(-1);
  644. X       }
  645. X     i++;
  646. X     }
  647. X   else {
  648. X     break;
  649. X     }
  650. X   }
  651. X if((i - posbeg) < 2) { /* if less than two characters in a number */
  652. X   return(-1);
  653. X   }
  654. X buff[i] = '\0';
  655. X return(num);
  656. X}
  657. X
  658. X/* ============================ str2code ==================
  659. X * str2code returns a code specified in buff. The valid numbers must have at
  660. X * least 2 digits. Here is a format of the code string
  661. X * (n represents valid  digit for a given base).
  662. X * nnn        (up to 3 decimal digits, first is not zero)
  663. X * 0nnn       (up to 3 octal digits)
  664. X * 0xnn       (up to 3 hex digits)
  665. X * 0onnn      (up to 3 octal digits)
  666. X * 0dnnn      (up to 3 decimal digits)
  667. X * The buff string will have '\0' put at the position after a valid number
  668. X * If no valid number can be parsed, or number is greater than 255, -1
  669. X * is returned.
  670. X * ======================================================== */
  671. XSTATIC int str2code(buff)
  672. Xchar *buff;
  673. X{
  674. X int i, l, num;
  675. X static char decdig[]="0123456789",
  676. X              octdig[]="01234567",
  677. X              hexdig[]="0123456789abcdef";
  678. X
  679. X l = strlen(buff);   /* get length */
  680. X if(l < 2) {  /* string too short */
  681. X   return(-1);
  682. X   }
  683. X
  684. X for(i = 0; i < l; i++) {    /* convert to lowercase */
  685. X   if(isalpha(buff[i]) != 0) {  /* if letter */
  686. X     buff[i] = tolower(buff[i]);
  687. X     }
  688. X   }
  689. X
  690. X if(isdigit(buff[0]) == 0) {  /* if first char not a digit */
  691. X   return(-1);
  692. X   }
  693. X
  694. X if(buff[0] == '0') { /*if starting char is 0, then octal */
  695. X   if((num = convnum(buff, octdig, 0)) != -1) { /* check if no base */
  696. X     return(num);
  697. X     }
  698. X   }
  699. X else { /* this has to be a decimal number */
  700. X   if((num = convnum(buff, decdig, 0)) != -1) {
  701. X     return(num);
  702. X     }
  703. X   else { /* error in decimal number */
  704. X     return(-1);
  705. X     }
  706. X   }
  707. X /* the base is specified at buff[1] */
  708. X if(buff[1] == 'o') {
  709. X   num = convnum(buff, octdig, 2);
  710. X   }
  711. X else if(buff[1] == 'd') {
  712. X   num = convnum(buff, decdig, 2);
  713. X   }
  714. X else if(buff[1] == 'x') {
  715. X   num = convnum(buff, hexdig, 2);
  716. X   }
  717. X else {  /* no base found */
  718. X   return(-1);
  719. X   }
  720. X return(num);
  721. X}
  722. X
  723. X/* ================= convstr ========================
  724. X * copies inp_string to out_strings, and when codes are given as \xxx
  725. X * converts them to characters. 
  726. X * Returns:
  727. X *  0 if OK
  728. X *  1 if character zero (e.g., \00 or \0x0) is found (it ends the string
  729. X *       processing, since it is string terminator).
  730. X * =================================================== */
  731. XSTATIC int convstr(inp_string, out_string)
  732. Xchar *inp_string, *out_string;
  733. X{
  734. X int ch, ch1, i, l, num, n;
  735. X char buff[8];
  736. X
  737. X n = 0;
  738. X while ((ch = *inp_string) != '\0') {
  739. X   n++;    /* count characters */
  740. X   if(ch == '\\')  {
  741. X     /* skip blank sequence */
  742. X     ch1 = *(inp_string + 1);     /* charcode following "\" */
  743. X     if(isspace(ch1) != 0) {  /* if "\" followed by blanks */
  744. X       inp_string++;  /* skip over "\" */
  745. X       n++;
  746. X       while( isspace((*inp_string)) != 0)  { /* skip all spaces */
  747. X         n++;
  748. X         inp_string++;
  749. X         }
  750. X       n--;  /* it will be advanced at the top of loop */
  751. X       ch = *inp_string;
  752. X       if(ch == '\0') {
  753. X         *out_string = '\0';
  754. X         return(0);
  755. X         }
  756. X       continue;   /* start new loop turn */
  757. X       }  /* ch is space */
  758. X
  759. X     /* now check is \020, etc., i.e., codes */
  760. X     for(i = 1; i <= 6; i++) {   /* copy possible number to a buffer */
  761. X       buff[i-1] = *(inp_string+i);
  762. X       }
  763. X     buff[6] = '\0';  /* terminate buff */
  764. X     if((num = str2code(buff)) >= 0) {
  765. X       *out_string++ = charcode(num);
  766. X       /* find how many characters have beed used ( number + \ )  */
  767. X       if(num == 0) {
  768. X         *out_string = '\0';
  769. X         return(1);
  770. X         }
  771. X       l = strlen(buff) + 1;
  772. X       inp_string += l;
  773. X       continue;
  774. X       }
  775. X     }
  776. X   *out_string++ = *inp_string;
  777. X   inp_string++;
  778. X   }   /* end while */
  779. X *out_string = '\0';
  780. X return(0);
  781. X}
  782. X
  783. X
  784. X/* ====================== compstr ========================
  785. X * returns 1 if str1 is located at the beginning of str2 and 0 otherwise
  786. X * ======================================================= */
  787. XSTATIC int compstr(str1, str2)
  788. Xchar str1[], str2[];
  789. X{
  790. X int i;
  791. X if(str1[0] == '\0') { /* empty sequence never matches */
  792. X   return(0);
  793. X   }
  794. X for(i = 0; str1[i] != '\0'; i++) {
  795. X   if(str1[i] != str2[i]) {
  796. X     return(0);
  797. X     } 
  798. X   }
  799. X return(1);
  800. X}
  801. X/* ====================== chkseqs ============================
  802. X * returns the sequence number if sequence is present at the beginning
  803. X * of buffer and -1 otherwise (first sequence has number 0);
  804. X * If regular expression, then SDATA.len is set to the length of
  805. X * the string which matches the regular expession.
  806. X * ============================================================= */
  807. XSTATIC int chkseqs(n_seq, seqstruc, buff)
  808. Xint n_seq;
  809. XSDATA *seqstruc;
  810. Xchar *buff;
  811. X{
  812. X int i, j, l;
  813. X char *sp, *ep, *str;
  814. X reg_exp *reaux;
  815. X if(n_seq == 0) {
  816. X   return(-1);
  817. X   }
  818. X for (i = 0; i < n_seq; i++) {
  819. X   if(seqstruc->typ == 0) {  /* if plain string */
  820. X     str = (seqstruc->ad).seq;
  821. X     if(*str != '\0') {
  822. X       l = 1;
  823. X       for(j = 0; *str != '\0'; j++) {
  824. X          if(*(buff + j) != *str++) {
  825. X            l = 0;
  826. X            break;
  827. X            }
  828. X          }
  829. X       if(l == 1) {
  830. X         return(i);
  831. X         }
  832. X       }
  833. X     }
  834. X   else if(seqstruc->typ == 1) {  /* regexp */
  835. X     if(reg_try((seqstruc->ad).re, buff) == 1) {  /* if anchored match found */
  836. X       reaux = (seqstruc->ad).re;  /* get address of search program */
  837. X       sp = reaux->startp[0];      /* address of 1st char of match */
  838. X       ep = reaux->endp[0];        /* next char after match */
  839. X       if(sp != buff) {  /* matches are anchored, at the buff beginning ! */
  840. X         tablerr(10, "Internal error in regexp package\n");
  841. X         }
  842. X       l = seqstruc->len = ep - sp;   /* match length */
  843. X       if(l <= 0) {
  844. X         fprintf(stderr,"Error when matching regular expression %d\n", i+1);
  845. X         exit(10);
  846. X         }
  847. X       return(i);
  848. X       }
  849. X     }
  850. X   seqstruc++;
  851. X   }   /* end for */
  852. X return(-1);
  853. X}
  854. X
  855. X/* =================== rdelim ==================
  856. X * read delimiters from tabl file
  857. X * ============================================= */
  858. XSTATIC int rdelim(startd, endd)
  859. Xint *startd, *endd;
  860. X{
  861. X if(getnblkline(tabl, 1) < 0) {
  862. X   tablerr(10,  "Could not read left delimiter code");
  863. X   }
  864. X if((*startd = chknblk(tabl)) < 0) {
  865. X   tablerr(10,  "Could not read left delimiter code");
  866. X   }
  867. X lineptr++;  /* point at next char */
  868. X if(isspace(*lineptr) == 0) {
  869. X   tablerr(10,
  870. X   "(Left Delimiter):Delimiters should be single chars separated by spaces");
  871. X   }
  872. X if((*endd = chknblk(tabl)) < 0) {
  873. X   tablerr(10,  "Could not read right delimiter code");
  874. X   }
  875. X lineptr++;  /* point at next char */
  876. X if(isspace(*lineptr) == 0) {
  877. X   tablerr(10,
  878. X   "(Right Delimiter):Delimiters should be single chars separated by spaces");
  879. X   }
  880. X return(0);
  881. X}
  882. X
  883. X/* ================== beseq ==============
  884. X * read starting or ending sequence for output
  885. X * and return pointer
  886. X * ======================================= */
  887. XSTATIC char* beseq()
  888. X{
  889. X char *scr1pt, *scr2pt;
  890. X int l;
  891. X
  892. X if((getnblkline(tabl, 1) < 0) ||
  893. X    ((scr1pt = getstring(strstart,strend,tabl)) == (char*)NULL)) {
  894. X   tablerr(10, "Error when reading starting/ending sequence");
  895. X   }
  896. X l = strlen(scr1pt) + 1;
  897. X if((scr2pt = (char*)malloc(l*sizeof(char))) == NULL) {
  898. X   tablerr(10, "Out of memory");
  899. X   }
  900. X convstr(scr1pt,scr2pt);
  901. X return(scr2pt);
  902. X}
  903. X
  904. X/* ================= allomaps ===============
  905. X * Allocate space for maps
  906. X * ============================================ */
  907. XSTATIC int allomaps(n)
  908. Xint n;
  909. X{
  910. X int i;
  911. X /* Allocate space for inp_maps and out_sets for input set 0 */
  912. X if((inp_maps[n] = (IMAP*)malloc(256*sizeof(char*))) == NULL) {
  913. X    /*if failed */
  914. X   tablerr(10, "Out of memory for storing sequences");
  915. X   }
  916. X
  917. X if((out_sets[n] = (OSET*)malloc(256*sizeof(int))) == NULL) { /* if failed */
  918. X   tablerr(10, "Out of memory for storing sequences");
  919. X   }
  920. X
  921. X for(i = 0; i < 256; i++) { /* zero allocated memory */
  922. X   (*inp_maps[n])[i] = (char*)NULL;
  923. X   (*out_sets[n])[i] = 0;
  924. X   }
  925. X return(0);
  926. X}
  927. X
  928. X/* =================== savestring ================= 
  929. X * saves string in the allocated storage and returns pointer to it
  930. X * does all the housekeeping
  931. X * ================================================== */
  932. XSTATIC char *savestring(str)
  933. Xchar *str;
  934. X{
  935. X int l;
  936. X char *retptr;
  937. X
  938. X l = strlen(str)+1;
  939. X if(memleft < l) {
  940. X    memleft = 5*MAXPAIRS;
  941. X    if((memptr = (char*)malloc(memleft*sizeof(char)))
  942. X                         == NULL) {
  943. X      tablerr(10,"Out of memory for allocation");
  944. X      }
  945. X    }
  946. X strcpy(memptr, str);
  947. X retptr = memptr;
  948. X memptr += l;
  949. X memleft -= l;
  950. X return(retptr);
  951. X}
  952. X
  953. X/* ================= splitlist =================
  954. X * unfolds the list [] to a list of characters (i.e. [a-d] = [abcd])
  955. X * =============================================== */
  956. XSTATIC int splitlist(inlist, unflist)
  957. Xchar *inlist, *unflist;
  958. X{
  959. X int ch, ch1, ch2, i, len;
  960. X convstr(inlist, inlist);   /* convert codes */
  961. X len = strlen(inlist);
  962. X if(len == 0) {
  963. X   tablerr(10, "Empty list specified");
  964. X   }
  965. X
  966. X *unflist++ = *inlist++;   /* save first character */
  967. X while ( *inlist != '\0') {
  968. X   ch = *inlist;
  969. X   if((ch != '-') || (*(inlist+1) == '\0')) {
  970. X     *unflist++ = ch;
  971. X     }
  972. X   else { /* the minus is inside */
  973. X     ch1 = intcode(*(inlist-1));
  974. X     ch2 = intcode(*(inlist+1));
  975. X     if(ch2 <= ch1) {
  976. X       tablerr(10, "The limits in the range within the list are reversed");
  977. X       }
  978. X     for(i = ch1+1; i < ch2; i++) {
  979. X       *unflist++ = charcode(i);
  980. X       }
  981. X     }
  982. X   inlist++;
  983. X   }
  984. X *unflist = '\0';
  985. X return(0);
  986. X}
  987. X
  988. X/* ======================== regerror ==================
  989. X * regerror --- routine called from within a regexp package. Aborts
  990. X * program with message
  991. X * ====================================================  */
  992. Xvoid reg_error(s)
  993. Xchar *s;
  994. X{
  995. X strcat(regerrstr,s);
  996. X tablerr(11,regerrstr);
  997. X}
  998. X
  999. X/* ========================  rdinshift ==================
  1000. X * reads in a shift sequence, assuming that the getnblkline was called
  1001. X * Fills in structure SDATA. If typ = 1, it is assumed that it is data
  1002. X * for matching, if typ = 2, this is data to be output 
  1003. X * If OK, returns 0, else dies
  1004. X * ======================================================= */
  1005. XSTATIC int rdinshift(sdstr, sttyp)
  1006. XSDATA *sdstr;
  1007. Xint sttyp;
  1008. X{
  1009. X int mode1;
  1010. X ADDR ads;
  1011. X curst1 = chknblk(tabl);  /* check what type delimiter */
  1012. X if(curst1 == strstart) {
  1013. X   mode1 = 1;
  1014. X   curend1 = strend;
  1015. X   }
  1016. X else if(curst1 == liststart) {
  1017. X   mode1 = 2;
  1018. X   tablerr(10, "Lists not allowed for input SHIFT sequences");
  1019. X   }
  1020. X else if(curst1 == regexstart) {
  1021. X   mode1 = 3;
  1022. X   curend1 = regexend;
  1023. X   }
  1024. X else {
  1025. X   tablerr(10, "Error when reading SHIFT input sequences");
  1026. X   }
  1027. X
  1028. X if((scr1pt = getstring(curst1, curend1, tabl)) == (char*)NULL) {
  1029. X   tablerr(10, "Error when reading input SHIFT sequences");
  1030. X   }
  1031. X
  1032. X convstr(scr1pt, scr1);   /* convert codes in the sequence  */
  1033. X scr1pt = savestring(scr1);   /* save sequence in memory */
  1034. X strcpy(regerrstr, "Error in regexp for input SHIFT sequences:");
  1035. X
  1036. X if(mode1 == 1) {
  1037. X   sdstr->typ = 0;   /* common string */
  1038. X   sdstr->len = strlen(scr1pt);
  1039. X   ads.seq = scr1pt;  /* save string address */
  1040. X   sdstr->ad = ads;
  1041. X   }
  1042. X else if(mode1 == 3) {
  1043. X   if(sttyp == 1) {
  1044. X     sdstr->typ = 1;
  1045. X     regauxptr = reg_comp(scr1pt);
  1046. X     if(regauxptr == (reg_exp *)NULL) {
  1047. X       tablerr(10, "Error in regular expression");
  1048. X       }
  1049. X     ads.re = regauxptr;
  1050. X     sdstr->ad = ads;
  1051. X     }
  1052. X   else {
  1053. X     sdstr->typ = 2;
  1054. X     sdstr->len = strlen(scr1pt);
  1055. X     ads.seq = scr1pt;
  1056. X     sdstr->ad = ads;
  1057. X     }
  1058. X   }
  1059. X return(0);
  1060. X}
  1061. X
  1062. X/* =========================  match_subs ==========================
  1063. X * match_subs matches the match_data sequence description to the
  1064. X * current position of the input file string (scrcurptr) and if match
  1065. X * is found, finds the replacement string and puts it in scr1 buffer.
  1066. X * it sets the global variables out_seq_length, out_seq_ptr, inp_seq_length
  1067. X * out_set_number. Returns 1 on success, and 0 if match was not found.
  1068. X * ================================================================== */
  1069. XSTATIC int match_subs(match_data, repl_data)
  1070. XSDATA *match_data, *repl_data;
  1071. X{
  1072. X if(chkseqs(1, match_data, scrcurptr) >= 0) {
  1073. X   inp_seq_length = match_data->len; /*chkseqs sets it for inp.typ 1 */
  1074. X   out_set_number = repl_data->set;
  1075. X   if(repl_data->typ == 2) {  /* if regexp substitution */
  1076. X     /* find a substitution string */
  1077. X     regauxptr = (match_data->ad).re; /* pointer to regexp prog */
  1078. X     /* scr contains the substitution string */
  1079. X     reg_sub(regauxptr, (repl_data->ad).seq, scr1);
  1080. X     out_seq_length = strlen(scr1);  /*number of chars in substitute */
  1081. X     out_seq_ptr = scr1;  /* pointer to substitute string */
  1082. X     }
  1083. X   else { /* if plain string (type = 0) */
  1084. X     out_seq_length = repl_data->len;
  1085. X     out_seq_ptr = (repl_data->ad).seq;
  1086. X     }
  1087. X   if(out_seq_length > MAXMATCH) {
  1088. X     fprintf(stderr,
  1089. X     "The substitution string is too long (%d chararacters):\n%s\n",
  1090. X     out_seq_length, out_seq_ptr);
  1091. X     exit(1);
  1092. X     }
  1093. X   return(1);
  1094. X   }
  1095. X else {
  1096. X   return(0);
  1097. X   }
  1098. X}
  1099. X
  1100. X/* =================== repl_inp =============================
  1101. X * replaces matching portion of an input text with a substitute string.
  1102. X * ========================================================== */
  1103. Xint repl_inp()
  1104. X{
  1105. X int k, l, i;
  1106. X
  1107. X if(out_seq_length > MAXMATCH) {
  1108. X   fprintf(stderr,
  1109. X   "The output substitution sequence is too long (%d characters):\n%s\n",
  1110. X                                             out_seq_length, out_seq_ptr);
  1111. X   exit(1);
  1112. X   }
  1113. X if(inp_seq_length >= out_seq_length) { /* do not have to copy strings */
  1114. X   k = inp_seq_length - out_seq_length;  /* diff in lengths */
  1115. X   scrcurptr += k;    /* move forwarde by the diff */
  1116. X   chars_left -= k;
  1117. X   for (i = 0; i < out_seq_length; i++) {  /* copy chars */
  1118. X     *(scrcurptr + i) = *(out_seq_ptr + i);
  1119. X     }
  1120. X   }
  1121. X else  {  /* have to push remaining chars to the right to make space */
  1122. X   k = out_seq_length - inp_seq_length;  /* diff in lengths */
  1123. X   l = strlen(scrcurptr);                /* length of input text */
  1124. X   /* memmove could be used, but it is not in all libaries */
  1125. X   for (i = l; i >= 0; i--) { /* move to right, start with terminating '\0' */
  1126. X     *(scrcurptr + i + k) = *(scrcurptr + i);
  1127. X     }
  1128. X   for (i = 0; i < out_seq_length; i++) { /* place the output string */
  1129. X     *(scrcurptr + i) = *(out_seq_ptr + i);
  1130. X     }
  1131. X   chars_left += k;     /* update chars_left, scrcurptr not changed */
  1132. X   }
  1133. X return(0);
  1134. X}
  1135. X
  1136. X/*======================== main ================================== */
  1137. X
  1138. Xint main(argc, argv)
  1139. Xint argc;
  1140. Xchar **argv;
  1141. X{
  1142. X char *tabl_file;           /* name of file with conversion table */
  1143. X static char deftablfile[200]=
  1144. X       DEFCONVNAME;         /* default conversion file name */
  1145. X static char deftablpath[200]=
  1146. X       TPATH;               /* default conversion file path */
  1147. X char table_name[300];      /* working array for conversion table */
  1148. X
  1149. X int  level;                /* input set nesting level */
  1150. X int  inp_cur_set[MAXLEVEL];/* set input number being processed */
  1151. X int  inp_cur_nest[MAXLEVEL]; /* current nesting count for input set */
  1152. X int  cur_inp_set;          /* current input set, same as inp_cur_set[level] */
  1153. X int  out_cur_set;          /* output set level being processed */
  1154. X int  buffer_size;          /* size of input buffer string */
  1155. X int opt;                   /* option letter */
  1156. X int mode1, mode2; /* type of string (1=str, 2=list, 3=regex) */
  1157. X
  1158. X int flg, ch, i, j, k, l, n;          /* aux variables */
  1159. X
  1160. X#if GETOPT     
  1161. X extern char *optarg;       /* option argument from getopt */
  1162. X extern int optind, opterr; /* needed for getopt */
  1163. X#endif
  1164. X
  1165. X static char usage[]=
  1166. X     "Usage: translit [-i inpfil] [-o outfil] [-t convtabfil] [convtabfil]\n";
  1167. X
  1168. X
  1169. X inpf = stdin;              /* initialize input to standard input */   /*UNIX*/
  1170. X outf = stdout;             /* initialize output to standard output */ /*UNIX*/
  1171. X
  1172. X /* set SIGNED_CHAR_TYPE flag */
  1173. X scr1[0] = '\372';
  1174. X if((int)scr1[0] < 0) {
  1175. X   SIGNED_CHAR_TYPE = 1;
  1176. X   }
  1177. X else {
  1178. X   SIGNED_CHAR_TYPE = 0;
  1179. X   }
  1180. X
  1181. X/* if environment is supported */
  1182. X#if GETENV
  1183. X /* if TRANSPATH variable defined, take its contents */
  1184. X if((scr1pt = getenv(TRANSPATH)) != (char *)NULL) {
  1185. X   strcpy(deftablpath, scr1pt);
  1186. X   }
  1187. X if((scr1pt = getenv(DEFNAME)) != (char *)NULL) {
  1188. X   strcpy(deftablfile, scr1pt);
  1189. X   }
  1190. X#endif
  1191. X
  1192. X tabl_file = deftablfile;   /* default table file name */
  1193. X flg = 0;    /* set to no conv table given as an argument */
  1194. X i = j = k = 0;   /* flags, for files specified: i-inp, j-out, k-tabl */
  1195. X while ((opt = getopt(argc, argv, OPTIONS)) != EOF) {
  1196. X   switch (opt) {
  1197. X     case 'd':
  1198. X       debug_flg = 1;
  1199. X       break;
  1200. X     case 'i':
  1201. X       if(i != 0) {
  1202. X         fprintf(stderr, "You specified option -i twice\n");
  1203. X         return(1);
  1204. X         }
  1205. X       if((inpf = fopen(optarg, "r")) == NULL)  {
  1206. X         fprintf(stderr,"Error: Could not find input file: %s\n", optarg);
  1207. X         return(1);
  1208. X         }
  1209. X       i = 1;
  1210. X       break;
  1211. X     case 'o':
  1212. X       if(j != 0) {
  1213. X         fprintf(stderr, "You specified option -o twice\n");
  1214. X         return(1);
  1215. X         }
  1216. X       if((outf = fopen(optarg, "r")) != NULL)  {
  1217. X         fprintf(stderr,
  1218. X         "Error: Output file: %s already exists! Delete it first.\n", optarg);
  1219. X         exit(3);
  1220. X         }
  1221. X       if((outf = fopen(optarg, "w")) == NULL)  {
  1222. X         fprintf(stderr,"Error: Could not open output file: %s\n", optarg);
  1223. X         exit(2);
  1224. X         }
  1225. X       j = 1;
  1226. X       break;
  1227. X
  1228. X     case 't':
  1229. X       if(k != 0) {
  1230. X         fprintf(stderr, "You specified option -t twice\n");
  1231. X         return(1);
  1232. X         }
  1233. X       tabl_file = optarg;
  1234. X       flg = 1;
  1235. X       k = 1;
  1236. X       break;
  1237. X     case '?':
  1238. X       fprintf(stderr,"Error: %s\n", usage);
  1239. X       exit(3);
  1240. X     }  /* end switch */
  1241. X   }  /* end while */
  1242. X
  1243. X if(optind < argc) {    /* check if translation table given w/o option -t */
  1244. X   if(flg == 1) {
  1245. X     fprintf (stderr,"Error: You specified conversion table file twice\n");
  1246. X     exit(4);
  1247. X     }
  1248. X   tabl_file = argv[optind];
  1249. X   if(argc > optind + 1) {
  1250. X     fprintf (stderr,"Error: %s\n", usage);
  1251. X     exit(5);
  1252. X     }
  1253. X   }
  1254. X
  1255. X if((tabl = fopen(tabl_file, "r")) == NULL) { /* try to open file with table */
  1256. X   strcpy(table_name, deftablpath);  /* copy path to scratch string */
  1257. X   strcat(table_name, tabl_file);
  1258. X   if((tabl = fopen(table_name, "r")) == NULL) {  /* try to open path/file */
  1259. X     fprintf(stderr,"Could not find the conversion table file: %s\n",
  1260. X             tabl_file);
  1261. X     exit(6);
  1262. X     }
  1263. X   }
  1264. X
  1265. X /* read in file version number */
  1266. X if((getnblkline(tabl, 1) < 0) || ((file_version = getnumber(tabl)) < 0)) {
  1267. X   tablerr(7, "Could not read file format number");
  1268. X   }
  1269. X if(file_version != 1) {
  1270. X   tablerr(10,  "This format of conversion file is not supported");
  1271. X   }
  1272. X
  1273. X /* read in delimiters */
  1274. X
  1275. X rdelim(&strstart, &strend);
  1276. X rdelim(&liststart, &listend);
  1277. X rdelim(®exstart, ®exend);
  1278. X
  1279. X /* read in starting and ending sequences */
  1280. X begseq = beseq();
  1281. X endseq = beseq();
  1282. X   
  1283. X /* reserve memory for sequences */
  1284. X chars_left = 5*MAXPAIRS;  /* size of allocated block */
  1285. X if((scr1ptr = (char*)malloc(chars_left*sizeof(char)))
  1286. X                   == NULL) {
  1287. X   tablerr(10, "Out of memory for storing sequences");
  1288. X   }
  1289. X /* Allocate space for inp_maps and out_sets for input set 0 */
  1290. X
  1291. X allomaps(0);
  1292. X
  1293. X /* Read number of input sets */
  1294. X if((getnblkline(tabl, 1) <= 0) || ((n_inp_sets = getnumber(tabl)) < 0)) {
  1295. X   tablerr(10, "Error when reading input set count");
  1296. X   }
  1297. X
  1298. X if(n_inp_sets >= MAXSETS) {
  1299. X   tablerr(10, "Too many input shift sequences");
  1300. X   }
  1301. X
  1302. X /* read input SI/SO sequences */
  1303. X for (i = 0; i < n_inp_sets; i++) { 
  1304. X   /* Allocate space for inp_maps and out_sets for input set i+1 */
  1305. X   allomaps(i+1);
  1306. X
  1307. X   /* read in input SHIFTs seq */
  1308. X   if(getnblkline(tabl, 1) <= 0) {  
  1309. X     tablerr(10, "Error when reading output shift sequences");
  1310. X     }
  1311. X   rdinshift(&inp_SO_data[i], 1);
  1312. X   rdinshift(&inp_SO_subs[i], 2);
  1313. X   if((inp_SO_subs[i].typ == 2) && (inp_SO_data[i].typ == 0)) {
  1314. X     tablerr(10,
  1315. X     "Plain string type for matching and substitution expression for output");
  1316. X     }
  1317. X   rdinshift(&inp_nest_open[i], 1);
  1318. X   rdinshift(&inp_nest_close[i], 1);
  1319. X   rdinshift(&inp_SI_data[i], 1);
  1320. X   rdinshift(&inp_SI_subs[i], 2);
  1321. X   if((inp_SI_subs[i].typ == 2) && (inp_SI_data[i].typ == 0)) {
  1322. X     tablerr(10,
  1323. X     "Plain string type for matching and substitution expression for output");
  1324. X     }
  1325. X
  1326. X   if(debug_flg == 1) {
  1327. X     if(inp_SO_data[i].typ == 0) {
  1328. X       fprintf(stderr,"%2d) inp_SO =|%s|     ", i, (inp_SO_data[i].ad).seq);
  1329. X       }
  1330. X     else {
  1331. X       fprintf(stderr,"%2d) inp_SO =%d     ", i, inp_SO_data[i].typ);
  1332. X       }
  1333. X     if((inp_SO_subs[i].typ == 0) || (inp_SO_subs[i].typ == 2)) {
  1334. X       fprintf(stderr,"%2d) inp_SOsub =|%s|     ", i, (inp_SO_subs[i].ad).seq);
  1335. X       }
  1336. X     else {
  1337. X       fprintf(stderr,"%2d) inp_SOsub =%d     ", i, inp_SO_subs[i].typ);
  1338. X       }
  1339. X     if(inp_nest_open[i].typ == 0) {
  1340. X       fprintf(stderr,"nest_open =|%s|     ",  (inp_nest_open[i].ad).seq);
  1341. X       }
  1342. X     else {
  1343. X       fprintf(stderr,"nest_open =%d     ", inp_nest_open[i].typ);
  1344. X       }
  1345. X     if(inp_nest_close[i].typ == 0) {
  1346. X       fprintf(stderr,"nest_close =|%s|     ", (inp_nest_close[i].ad).seq);
  1347. X       }
  1348. X     else {
  1349. X       fprintf(stderr,"nest_close =%d     ", inp_nest_close[i].typ);
  1350. X       }
  1351. X     if(inp_SI_data[i].typ == 0) {
  1352. X       fprintf(stderr,"inp_SI =|%s|\n", (inp_SI_data[i].ad).seq);
  1353. X       }
  1354. X     else {
  1355. X       fprintf(stderr,"inp_SI =%d\n", inp_SI_data[i].typ);
  1356. X       }
  1357. X     if((inp_SI_subs[i].typ == 0) || (inp_SI_subs[i].typ == 2)) {
  1358. X       fprintf(stderr,"%2d) inp_SIsub =|%s|     ", i, (inp_SI_subs[i].ad).seq);
  1359. X       }
  1360. X     else {
  1361. X       fprintf(stderr,"%2d) inp_SIsub =%d     ", i, inp_SI_subs[i].typ);
  1362. X       }
  1363. X     }  /* end debug_flg */
  1364. X   }
  1365. X
  1366. X if((getnblkline(tabl, 1) <= 0) || ((n_out_sets = getnumber(tabl)) < 0)) {
  1367. X  /* read in out SHIFTs count */
  1368. X   tablerr(10, "Error when reading output set count");
  1369. X   }
  1370. X if(n_out_sets > MAXSETS) {
  1371. X   tablerr(10, "Too many output SHIFT sequences requested");
  1372. X   }
  1373. X
  1374. X for (i = 0; i < n_out_sets; i++) {
  1375. X   /* read in out SHIFTs seq */
  1376. X   if((getnblkline(tabl, 1) <= 0) ||
  1377. X      ((scr1pt = getstring(strstart, strend, tabl)) == (char*)NULL) ||
  1378. X      ((scr2pt = getstring(strstart, strend, tabl)) == (char*)NULL)) {
  1379. X     tablerr(10, "Error when reading output shift sequences");
  1380. X     }
  1381. X   convstr(scr1pt, scr1a);
  1382. X   out_SO_len[i]= strlen(scr1a);
  1383. X   out_SO[i] = savestring(scr1a);   
  1384. X
  1385. X   convstr(scr2pt, scr2a);
  1386. X   out_SI_len[i] = strlen(scr2a);
  1387. X   out_SI[i] = savestring(scr2a);
  1388. X   if(debug_flg == 1) {
  1389. X     fprintf(stderr,"%2d) out_SO string=|%s|   out_SI string=|%s|\n",
  1390. X     i, out_SO[i], out_SI[i]);
  1391. X     }
  1392. X   }  /* end for */
  1393. X
  1394. X i = 0;
  1395. X while (getnblkline(tabl, 1) > 0)  {
  1396. X   if((inp_data[i].set = getnumber(tabl)) < 0) {  /* get inp set number */
  1397. X     tablerr(10, "Set number for input sequences is wrong");
  1398. X     }
  1399. X   if(((k = inp_data[i].set) > n_inp_sets) || (k < 0) ) {
  1400. X     tablerr(10,"Input set number for a sequence wrong");
  1401. X     }
  1402. X   curst1 = chknblk(tabl);  /* check what type of string follows */
  1403. X   if(curst1 == strstart) {
  1404. X     mode1 = 1;
  1405. X     curend1 = strend;
  1406. X     }
  1407. X   else if(curst1 == liststart) {
  1408. X     mode1 = 2;
  1409. X     curend1 = listend;
  1410. X     }
  1411. X   else if(curst1 == regexstart) {
  1412. X     mode1 = 3;
  1413. X     curend1 = regexend;
  1414. X     }
  1415. X   else {
  1416. X     tablerr(10, "Delimiter wrong when reading input sequences");
  1417. X     }
  1418. X   /* get input sequence */
  1419. X   if((scr1pt = getstring(curst1, curend1, tabl)) == (char*)NULL) {
  1420. X     tablerr(10, "Error reading input sequence");
  1421. X     }
  1422. X   scr1pt = savestring(scr1pt);  /* Save the string */
  1423. X
  1424. X   if((out_data[i].set = getnumber(tabl)) < -3) {  /* get inp set number */
  1425. X     tablerr(10, "Wrong code for the output set number");
  1426. X     }
  1427. X
  1428. X   if(out_data[i].set > n_out_sets) {
  1429. X     tablerr(10, "Output set number for a sequence is wrong");
  1430. X     }
  1431. X
  1432. X   curst2 = chknblk(tabl);  /* check what type of string follows */
  1433. X   if(curst2 == strstart) {
  1434. X     mode2 = 1;
  1435. X     curend2 = strend;
  1436. X     }
  1437. X   else if(curst2 == liststart) {
  1438. X     mode2 = 2;
  1439. X     curend2 = listend;
  1440. X     }
  1441. X   else if(curst2 == regexstart) {
  1442. X     mode2 = 3;
  1443. X     curend2 = regexend;
  1444. X     }
  1445. X   else {
  1446. X     tablerr(10, "Delimiter wrong when reading sequences");
  1447. X     }
  1448. X  
  1449. X   if((scr2pt = getstring(curst2, curend2, tabl)) == (char*)NULL) {
  1450. X     tablerr(10, "Error reading input sequence");
  1451. X     }
  1452. X   scr2pt = savestring(scr2pt);
  1453. X
  1454. X   /* check if acceptable types for sequences */
  1455. X   if((mode2 == 3) && (mode1 != 3)) {  /* no regular expressions for output */
  1456. X     tablerr(10,
  1457. X   "Regular expression as output sequence and input not a regular expression");
  1458. X     }
  1459. X   else if((mode1 == 1) && (mode2 == 2)) { /* inp string, out list */
  1460. X     tablerr(10, "You specified list for output and string for input");
  1461. X     }
  1462. X   else if((mode1 == 3) && (mode2 == 2)) { /* inp regex, out list */
  1463. X     tablerr(10, "You specified string for input and list for output");
  1464. X     }
  1465. X   else if((mode1 == 2) && (out_data[i].set < 0)) {
  1466. X     tablerr(10,
  1467. X    "Input LIST and output set code -1/-2/-3 is not supported at this moment");
  1468. X     }
  1469. X
  1470. X   if(mode1 == 2) {  /* if list for input expression */
  1471. X     /* split string at - sign */
  1472. X     splitlist(scr1pt, scr1);
  1473. X     if(mode2 == 2) {
  1474. X       splitlist(scr2pt, scr2); 
  1475. X       if(strlen(scr1) != strlen(scr2)) {
  1476. X         tablerr(10,
  1477. X         "The number of codes in the input and output list is different");
  1478. X         }
  1479. X       }
  1480. X     }  /* end mode 2 */
  1481. X   else {  /* for all other modes, convert the codes */
  1482. X     convstr(scr1pt, scr1a); /* convert codes in input string */
  1483. X     }
  1484. X
  1485. X   if((mode1 == 1) && (strlen(scr1a) == 1)) { /* single inp char */
  1486. X     /* it is like list with a single character, so cheat */
  1487. X     if(out_data[i].set >= 0) {
  1488. X       mode1 = 2;
  1489. X       strcpy(scr1, scr1a);  /* make it a list */ 
  1490. X       }
  1491. X     else {
  1492. X       tablerr(10,
  1493. X  "One-character input strings and output codes -1/-2/-3 are not supported\n");
  1494. X       }
  1495. X     }
  1496. X     
  1497. X   if(mode1 == 2) {  /* fill the lists for mode 2 */     
  1498. X     if(mode2 == 1) { /* if normal string as output sequence */
  1499. X       convstr(scr2pt, scr2);
  1500. X       scr2pt = savestring(scr2);
  1501. X       }
  1502. X     else { /* if mode2 = 2 */
  1503. X       scr2pt = scr2;
  1504. X       }
  1505. X     /* now fill the maps */
  1506. X     k = inp_data[i].set;
  1507. X     l = out_data[i].set;
  1508. X     scr1pt = scr1;  /* points at input list */
  1509. X     scr2ptr = scr2pt;  /* points at output list or string */
  1510. X     while (*scr1pt != '\0') {
  1511. X       if(mode2 == 2) {  /* prepare string with code */
  1512. X         scr1a[0] = *scr2ptr++;
  1513. X         scr1a[1] = '\0';
  1514. X         scr2pt = savestring(scr1a);
  1515. X         }
  1516. X       ch = intcode(*scr1pt);
  1517. X       if((*inp_maps[k])[ch] != (char *)NULL) {
  1518. X         fprintf(stderr,
  1519. X"You have entered the character |%c| with code \\0d%d for input set %d\n",
  1520. X         charcode(ch), ch, k);
  1521. X         tablerr(10, "Delete previous references if not needed");
  1522. X         }
  1523. X       (*inp_maps[k])[ch] = scr2pt;  /* save output sequence */
  1524. X       (*out_sets[k])[ch] = l;       /* save output set number */
  1525. X       scr1pt++;  /* next code for output */
  1526. X       }
  1527. X     i--;  /* do not save this line in inp_str and out */
  1528. X     } /* end if mode1 = 2*/
  1529. X   else if(mode1 == 1) { /* if multicharacter input string */
  1530. X     scr1pt = savestring(scr1a);
  1531. X     convstr(scr2pt, scr2a);
  1532. X     scr2pt = savestring(scr2a);
  1533. X     inp_data[i].typ = 0;
  1534. X     inp_data[i].len =  strlen(scr1pt);
  1535. X     (inp_data[i].ad).seq = scr1pt;
  1536. X     out_data[i].typ = 0;
  1537. X     out_data[i].len =  strlen(scr2pt);
  1538. X     (out_data[i].ad).seq = scr2pt;
  1539. X     }
  1540. X   else if(mode1 == 3) { /* if regular expression for input */
  1541. X     inp_data[i].typ = 1;
  1542. X     l = strlen(scr1a);    /* length of converted input expression */
  1543. X     if(scr1a[0] == '^') {
  1544. X       tablerr(10,
  1545. X       "The ^ (beginning anchor) is not supported");
  1546. X       }
  1547. X     if((scr1a[l-1] == '$') && (scr1a[l-1] != '\\')) {
  1548. X       tablerr(10, "The $ (end anchor) is not supported");
  1549. X       }
  1550. X
  1551. X     strcpy(regerrstr, "Error in input regular expression sequence: ");
  1552. X
  1553. X     if((regauxptr = reg_comp(scr1a)) == NULL) {
  1554. X       tablerr(10, "Error in the input regular expression sequence");
  1555. X       }
  1556. X     (inp_data[i].ad).re = regauxptr;
  1557. X     convstr(scr2pt, scr1a);   /* convert codes in out string */
  1558. X     scr2pt = savestring(scr1a);
  1559. X     if(mode2 == 3) {  /* mark type of expression plan(0)/substit string(2) */
  1560. X       out_data[i].typ = 2;
  1561. X       }
  1562. X     else  {
  1563. X       out_data[i].typ = 0;
  1564. X       }
  1565. X     out_data[i].len = strlen(scr2pt);
  1566. X     (out_data[i].ad).seq = scr2pt;
  1567. X     }
  1568. X
  1569. X   /* advance pointers */
  1570. X
  1571. X   n_conv_seq = ++i;
  1572. X   if(n_conv_seq >= (MAXPAIRS-1)) {
  1573. X     tablerr(10, 
  1574. X "Too many transliteration sequences. Recompile program with larger MAXPAIRS");
  1575. X     }
  1576. X   }  /* end while getnblkline */
  1577. X
  1578. X if(debug_flg == 1) {
  1579. X   fprintf(stderr,"Multicharacter input sequences \n");
  1580. X   for(i=0; i < n_conv_seq; i++) {
  1581. X     fprintf(stderr,"%2d) inp.type=%2d inp.set=%2d out.type=%2d out.set=%2d\n",
  1582. X        i, inp_data[i].typ, inp_data[i].set, out_data[i].typ, out_data[i].set);
  1583. X      if(inp_data[i].typ == 0) {
  1584. X        fprintf(stderr,"       Inp.str=|%s|   ", (inp_data[i].ad).seq);
  1585. X        }
  1586. X      fprintf(stderr, "Out.str=|%s|\n", (out_data[i].ad).seq);
  1587. X      }
  1588. X   fprintf(stderr,
  1589. X        "input_set charcode input_character  --> output_set output_string/\n");
  1590. X   for(i = 0; i <= n_inp_sets; i++) {
  1591. X     for(k = 0; k < 256; k++) {
  1592. X       if((*inp_maps[i])[k] != (char *)NULL) {
  1593. X         fprintf(stderr," %2d  \\%04o  %c   -->  %2d  %s\n",
  1594. X         i, k,  charcode(k), (*out_sets[i])[k], (*inp_maps[i])[k]);
  1595. X         }
  1596. X       }
  1597. X     }
  1598. X   }
  1599. X
  1600. X
  1601. X fprintf(outf,"%s",begseq);   /* output starting sequence */
  1602. X
  1603. X /* transliterate input file to output file */
  1604. X
  1605. X level = 0;
  1606. X if(n_inp_sets > 0) {
  1607. X   cur_inp_set = 1;
  1608. X   }
  1609. X else {
  1610. X   cur_inp_set = 0;
  1611. X   }
  1612. X inp_cur_set[level] = cur_inp_set;   /* 1st input set is a default */
  1613. X inp_cur_nest[level] = 0;
  1614. X scr1ptr = scr1a;
  1615. X scr1ptr[0] = '\0';
  1616. X scr2ptr = scr2a;
  1617. X scr2ptr[0] = '\0';
  1618. X scrcurptr = scr2ptr;
  1619. X chars_left = 0;
  1620. X buffer_size = MAXBUFF/2;   /* will be set to 0 if EOF */
  1621. X out_cur_set = 1;  /* no output set yet */
  1622. X
  1623. X
  1624. X while ( buffer_size > 0) {
  1625. X   /* swap input buffer pointers */
  1626. X   scrauxptr = scr2ptr;
  1627. X   scr2ptr = scr1ptr;
  1628. X   scr1ptr = scrauxptr;
  1629. X
  1630. X   scrauxptr = scrcurptr;   /* old buffer last pointer */
  1631. X   scrcurptr = scr1ptr;     /* new buffer start */
  1632. X
  1633. X   /* copy remains of old buffer to new one */
  1634. X   strcpy(scrcurptr, scrauxptr);
  1635. X
  1636. X   l = chars_left;
  1637. X   for(i = 0; i < buffer_size; i++) {  /* append input chars to scr1a */
  1638. X     if((k = fgetc(inpf)) == EOF) {
  1639. X       buffer_size = 0;   /* end of file */
  1640. X       break;
  1641. X       }
  1642. X     else if(k == '\0') { /* skip zero characters */
  1643. X       i--;
  1644. X       continue;
  1645. X       }
  1646. X     else { /* if normal character */
  1647. X       *(scrcurptr + l++) = k;
  1648. X       }
  1649. X     }
  1650. X   *(scrcurptr + l) = '\0';    /* terminate buffer with 0 */
  1651. X   chars_left = l;    ;   /* length of combined string */
  1652. X   if(buffer_size == 0) {  /* if EOF */
  1653. X     chars_left += MAXMATCH+1; /* fool the program that there is more */
  1654. X     }
  1655. X
  1656. X   while (chars_left > MAXMATCH) {
  1657. X     /* check if end of scrcurptr --- it means end of input file, since only
  1658. X        then it can get to the end of the string, otherwise it stops
  1659. X        MAXMATCH before */
  1660. X     if(*scrcurptr == '\0') {  /* end of file */
  1661. X       if(n_out_sets > 0) {  /* if multiple output sets */
  1662. X         l = out_SI_len[out_cur_set - 1];
  1663. X         for(i = 0; i < l; i++) {
  1664. X           k = out_SI[out_cur_set-1][i];
  1665. X           fputc(k, outf);
  1666. X           }
  1667. X         break;
  1668. X         }
  1669. X       }
  1670. X
  1671. XBackstep2:       
  1672. X     /* check if new set of input chars started */
  1673. X     l = -1;
  1674. X     for (i = 0; i < n_inp_sets; i++) {
  1675. X       if(match_subs(&inp_SO_data[i], &inp_SO_subs[i]) > 0) {
  1676. X         l = i;
  1677. X         break;
  1678. X         }
  1679. X       }
  1680. X     if(l >= 0) {   /* is SO matched */
  1681. X       repl_inp();    /* substitute SO_data with SO_seqs */
  1682. X       if((inp_SI_data[l].len > 0) || (inp_SI_data[l].typ == 1)){
  1683. X       /* increase level only is SHIFT IN present */
  1684. X         level++;  /* increase number of "opened" input sets */
  1685. X         inp_cur_nest[level] = 0;  /* It is new level,zero nesting sequences */
  1686. X         if(level > MAXLEVEL) {
  1687. X           fprintf(stderr,
  1688. X           "Too many nested input character sets in input file\n");
  1689. X           exit(39);
  1690. X           }
  1691. X         }
  1692. X       l++;   /* sets in arrays are saved starting from 0, 
  1693. X               i.e., set nr 1 corresponds to element [0], 2 --> [1], etc. */
  1694. X       inp_cur_set[level] = l;   /* save set number at current nesting level */
  1695. X       cur_inp_set = l;
  1696. X       continue;
  1697. X       }
  1698. X     /* check if SHIFT IN sequence for current input set */
  1699. X     if(n_inp_sets > 0) {
  1700. X       /* check SI sequence only when nesting count is 0 */
  1701. X       if(inp_cur_nest[level] == 0) {
  1702. X         if(match_subs(&inp_SI_data[cur_inp_set-1], 
  1703. X                       &inp_SO_subs[cur_inp_set-1]) > 0) {  /* is SI */
  1704. X           repl_inp();
  1705. X           level--;
  1706. X           if(level < 0) {
  1707. X             level = 0;
  1708. X             fprintf(stderr,
  1709. X"More SHIFT_IN sequences than corresponding SHIFT_OUT sequences in text\n");
  1710. X             }
  1711. X           cur_inp_set = inp_cur_set[level];  /* set previous inp set number */
  1712. X           continue;
  1713. X           }
  1714. X         }
  1715. X       }
  1716. X
  1717. X     /* Now check if the input sequence corresponding to cur_inp_set
  1718. X        matches the string */
  1719. X
  1720. XBackstep1:                        /* if output set number is -1, start again */
  1721. X     flg = -1;
  1722. X     for(i = 0; i < n_conv_seq; i++) {
  1723. X       k = inp_data[i].set; /*get set number for current transliteration seq */
  1724. X       if((k == cur_inp_set) || (k == 0)) { /* if equal to current or 0 */
  1725. X         if(match_subs(&inp_data[i], &out_data[i]) > 0) {
  1726. X           if(out_set_number < 0) { /* if backsteping */
  1727. X             repl_inp();  /* replace */
  1728. X             if (out_set_number == -1) {
  1729. X               flg = -1;
  1730. X               }
  1731. X             else if (out_set_number == -2) {
  1732. X               goto Backstep1;
  1733. X               }
  1734. X             else if (out_set_number == -3) {
  1735. X               goto Backstep2;
  1736. X               }
  1737. X             }
  1738. X           else {  /* if set number >= 0 */
  1739. X             flg = i;
  1740. X             break;
  1741. X             }
  1742. X           }  
  1743. X         }
  1744. X       }
  1745. X
  1746. X     if(flg < 0) {  /* if no matching input multichar sequence found */
  1747. X       ch = intcode(*scrcurptr);  /* current input character */
  1748. X       if((out_seq_ptr = (*inp_maps[cur_inp_set])[ch]) != NULL) { 
  1749. X            /* if out_seq exists for current input set */
  1750. X         out_set_number = (*out_sets[cur_inp_set])[ch];
  1751. X         flg = 1;
  1752. X         }
  1753. X       else if((out_seq_ptr = (*inp_maps[0])[ch]) != NULL) {
  1754. X          /* if out_seq exitst for set number 0 */
  1755. X         flg = 1;
  1756. X         out_set_number = (*out_sets[0])[ch];
  1757. X         }
  1758. X       if(flg >= 0) {  /* set other things */
  1759. X         out_seq_length = strlen(out_seq_ptr);
  1760. X         inp_seq_length = 1;
  1761. X         }         
  1762. X       }
  1763. X
  1764. X     if(flg < 0) {  /* if no match found, copy the input char to output */
  1765. X       scr1[0] = *scrcurptr;
  1766. X       scr1[1] = '\0';
  1767. X       if(*scrcurptr != '\0') {
  1768. X         out_seq_length = 1;
  1769. X         }
  1770. X       else {
  1771. X         out_seq_length = 0;
  1772. X         }
  1773. X
  1774. X       inp_seq_length = 1;
  1775. X       out_set_number = 0;
  1776. X       out_seq_ptr = scr1;
  1777. X       }
  1778. X
  1779. X     /* At this point all matches and substitutuions have been done */
  1780. X
  1781. X     /* check if nesting sequences found for a given set and increase or
  1782. X       decrease nesting if needed */
  1783. X     if((n_inp_sets > 0) && (out_cur_set > 0)) {
  1784. X       for(i = 0; i < inp_seq_length; i++) {
  1785. X         if(chkseqs(1, &inp_nest_close[cur_inp_set-1], scrcurptr+i) >= 0) {
  1786. X           inp_cur_nest[level]--;
  1787. X           }
  1788. X         if(chkseqs(1, &inp_nest_open[cur_inp_set-1], scrcurptr+i) >= 0) {
  1789. X           inp_cur_nest[level]++;
  1790. X           }
  1791. X         }
  1792. X       }
  1793. X
  1794. X     /* output  the SI/SO sequences if output set changed */
  1795. X     if((n_out_sets > 0) &&
  1796. X        (out_set_number > 0)) {  /* check if multiple output sets */
  1797. X       if(out_cur_set !=  out_set_number) { /* if new set starts */
  1798. X         if(out_cur_set > 0) { /* put SHIFT IN for a previous set */
  1799. X           l = out_SI_len[out_cur_set-1];  /* old SHIFT IN seq length */
  1800. X           for(i = 0; i < l; i++) { /* output old SHIFT IN */
  1801. X             k = out_SI[out_cur_set-1][i];
  1802. X             fputc(k, outf);
  1803. X             }
  1804. X           }
  1805. X         out_cur_set = out_set_number;  /* make it current now */
  1806. X         if(out_cur_set > 0) {
  1807. X           l = out_SO_len[out_cur_set-1]; /* length of SHIFT OUT sequence */
  1808. X           for(i = 0; i < l; i++) {  /* output SHIFT OUT seq for this set */
  1809. X             k = out_SO[out_cur_set-1][i];
  1810. X             fputc(k, outf);
  1811. X             }
  1812. X           }
  1813. X         }  /* end out_set changes */
  1814. X       }  /* if multiple output sets specified */
  1815. X
  1816. X     /* now output the corresponding sequence */
  1817. X     for(i = 0; i < out_seq_length; i++) { 
  1818. X       k = *(out_seq_ptr+i);
  1819. X       fputc(k,outf);
  1820. X       }
  1821. X
  1822. X     /* move past processed input text */
  1823. X     scrcurptr += inp_seq_length;
  1824. X     chars_left -= inp_seq_length;
  1825. X
  1826. X
  1827. X     }  /* while scanning input characters */
  1828. X
  1829. X   }  /* end while reading input file */
  1830. X fprintf(outf,"%s",endseq);   /* output ending sequence */
  1831. X fclose(inpf);
  1832. X fclose(outf);
  1833. X exit(0);
  1834. X}
  1835. X
  1836. END_OF_FILE
  1837.   if test 54601 -ne `wc -c <'translit.c'`; then
  1838.     echo shar: \"'translit.c'\" unpacked with wrong size!
  1839.   fi
  1840.   # end of 'translit.c'
  1841. fi
  1842. echo shar: End of archive 3 \(of 10\).
  1843. cp /dev/null ark3isdone
  1844. MISSING=""
  1845. for I in 1 2 3 4 5 6 7 8 9 10 ; do
  1846.     if test ! -f ark${I}isdone ; then
  1847.     MISSING="${MISSING} ${I}"
  1848.     fi
  1849. done
  1850. if test "${MISSING}" = "" ; then
  1851.     echo You have unpacked all 10 archives.
  1852.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1853. else
  1854.     echo You still must unpack the following archives:
  1855.     echo "        " ${MISSING}
  1856. fi
  1857. exit 0
  1858. exit 0 # Just in case...
  1859.