home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / PROGRAM / C / PGP23S / LANGUAGE.C < prev    next >
C/C++ Source or Header  |  1993-07-02  |  9KB  |  418 lines

  1. /*
  2.  *    language.c - Foreign language translation for PGP
  3.  *    Finds foreign language "subtitles" for English phrases 
  4.  *    in external foriegn language text file.
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <ctype.h>
  11. #include "usuals.h"
  12. #include "fileio.h"
  13. #include "language.h"
  14. #include "pgp.h"
  15. #include "charset.h"
  16. #include "armor.h"
  17.  
  18. #define SUBTITLES_FILE    "language.txt"
  19. #define LANG_INDEXFILE    "language.idx"
  20.  
  21. #define    STRBUFSIZE        2048
  22.  
  23. char language[16] = "en";    /* The language code, defaults to English */
  24. static char    *strbuf;
  25. static char    lang[16];    /* readstr sets this to the language id of the msg it last read */
  26. static int    subtitles_available = 0;
  27. static int line = 0;
  28. /*    subtitles_available is used to determine if we know whether the special
  29.     subtitles_file exists.  subtitles_available has the following values:
  30.     0  = first time thru, we don't yet know if subtitles_file exists.
  31.     1  = we have already determined that subtitles_file exists.
  32.     -1 = we have already determined that subtitles_file does not exist.
  33. */
  34.  
  35. #define    NEWLINE        0
  36. #define    COMMENT        1
  37. #define    INSTRING    2
  38. #define    ESCAPE        3
  39. #define    IDENT        4
  40. #define    DONE        5
  41. #define    ERROR        6
  42. #define    ERR1        7
  43.  
  44. /* Look for and return a quoted string from the file.
  45.  * If nlabort is true, return failure if we find a blank line
  46.  * before we find the opening quote.
  47.  */
  48. static char    *
  49. readstr (FILE *f, char *buf, int nlabort)
  50. {    int        c, d;
  51.     char *p = buf;
  52.     int state = NEWLINE;
  53.     int i = 0;
  54.     
  55.     while ((c = getc(f)) != EOF)
  56.     {
  57.         if (c == '\r')
  58.             continue;
  59.         /* line numbers are only incremented when creating index file */
  60.         if (line && c == '\n')
  61.             ++line;
  62.         switch (state)
  63.         {
  64.             case NEWLINE:
  65.                 switch(c)
  66.                 {
  67.                     case '#': state = COMMENT; break;
  68.                     case '"': state = INSTRING; break;
  69.                     case '\n':
  70.                         if (nlabort)
  71.                         {    *buf = '\0';
  72.                             return(buf);
  73.                         }
  74.                     default:
  75.                         if (i == 0 && isalnum(c))
  76.                         {
  77.                             state = IDENT;
  78.                             lang[i++] = c;
  79.                             break;
  80.                         }
  81.                         if (!isspace(c))
  82.                         {
  83.                             fprintf(stderr, "language.txt:%d: syntax error\n", line);
  84.                             state = ERROR;
  85.                         }
  86.                 }
  87.                 break;
  88.             case COMMENT:
  89.                 if (c == '\n')
  90.                     state = NEWLINE;
  91.                 break;
  92.             case INSTRING:
  93.                 switch(c)
  94.                 {
  95.                     case '\\': state = ESCAPE; break;
  96.                     case '"': state = DONE; break;
  97.                     default: *p++ = c;
  98.                 }
  99.                 break;
  100.             case ESCAPE:
  101.                 switch (c)
  102.                 {
  103.                     case 'n':    *p++ = '\n';    break;
  104.                     case 'r':    *p++ = '\r';    break;
  105.                     case 't':    *p++ = '\t';    break;
  106.                     case 'e':    *p++ = '\033';    break;
  107.                     case 'a':    *p++ = '\007';    break;
  108.                     case '#':
  109.                     case '"':
  110.                     case '\\':    *p++ = c; break;
  111.                     case '\n':    break;
  112.                     case '0':
  113.                     case '1':
  114.                     case '2':
  115.                     case '3':
  116.                     case '4':
  117.                     case '5':
  118.                     case '6':
  119.                     case '7':
  120.                             d = c - '0';
  121.                             while ((c = fgetc(f)) >= '0' && c <= '7')
  122.                                 d = 8 * d + c - '0';
  123.                             *p++ = d;
  124.                             ungetc(c, f);
  125.                             break;
  126.                     default:
  127.                             fprintf(stderr, "language.txt:%d: illegal escape sequence: '\\%c'\n", line, c);
  128.                             break;
  129.                 }
  130.                 state = INSTRING;
  131.                 break;
  132.             case IDENT:        /* language identifier */
  133.                 if (c == ':') {
  134.                     state = NEWLINE;
  135.                     break;
  136.                 }
  137.                 if (c == '\n' && strncmp(lang, "No translation", 14) == 0)
  138.                 {
  139.                     i = 0;
  140.                     state = NEWLINE;
  141.                     break;
  142.                 }
  143.                 lang[i++] = c;
  144.                 if (i == 15 || !isalnum(c) && !isspace(c))
  145.                 {
  146.                     lang[i] = '\0';
  147.                     fprintf(stderr, "language.txt:%d: bad language identifier: '%s'\n", line, lang);
  148.                     state = ERROR;
  149.                     i = 0;
  150.                 }
  151.                 break;
  152.             case DONE:
  153.                 if (c == '\n')
  154.                 {
  155.                     lang[i] = '\0';
  156.                     *p = '\0';
  157.                     return(buf);
  158.                 }
  159.                 if (!isspace(c))
  160.                 {
  161.                     fprintf(stderr, "language.txt:%d: extra characters after '\"'\n", line);
  162.                     state = ERROR;
  163.                 }
  164.                 break;
  165.             case ERROR:
  166.                 if (c == '\n')
  167.                     state = ERR1;
  168.                 break;
  169.             case ERR1:
  170.                 state = (c == '\n' ? NEWLINE : ERROR);
  171.                 break;
  172.         }
  173.     }
  174.     if (state != NEWLINE)
  175.         fprintf(stderr, "language.txt: unexpected EOF\n");
  176.     return(NULL);
  177. }
  178.  
  179. #ifdef TEST
  180. main()
  181. {
  182.     char buf[2048];
  183.  
  184.     line = 1;
  185.     while (readstr(stdin, buf, 0)) {
  186.         printf("\nen: <%s>\n", buf);
  187.         while (readstr(stdin, buf, 1) && *buf != '\0')
  188.             printf("%s: <%s>\n", lang, buf);
  189.     }
  190.     exit(0);
  191. }
  192. #else
  193.  
  194. static struct indx_ent {
  195.     word32    crc;
  196.     long    offset;
  197. } *indx_tbl = NULL;
  198.  
  199. static int max_msgs = 0;
  200. static int nmsg = 0;
  201.  
  202. static FILE *langf;
  203.  
  204. static void init_lang(void);
  205.  
  206. static int make_indexfile(char *);
  207.  
  208. /*
  209.  * uses 24-bit CRC function from armor.c
  210.  */
  211. static word32
  212. message_crc(char *s)
  213. {
  214.     return crcbytes((byte *)s, strlen(s), (word32)0);
  215. }
  216.  
  217. /*
  218.  * lookup file offset in indx_tbl
  219.  */
  220. static long
  221. lookup_offset(word32 crc)
  222. {
  223.     int i;
  224.     
  225.     for (i = 0; i < nmsg; ++i)
  226.         if (indx_tbl[i].crc == crc)
  227.             return(indx_tbl[i].offset);
  228.     return(-1);
  229. }
  230.  
  231.  
  232. /*
  233.  * return foreign translation of s
  234.  */
  235. char *
  236. PSTR (char *s)
  237. {
  238.     long filepos;
  239.  
  240.     if (subtitles_available == 0)
  241.         init_lang();
  242.     if (subtitles_available < 0)
  243.         return(s);
  244.  
  245.     filepos = lookup_offset(message_crc(s));
  246.     if (filepos == -1)
  247.         return(s);
  248.     else
  249.     {
  250.         fseek(langf, filepos, SEEK_SET);
  251.         readstr(langf, strbuf, 1);
  252.     }
  253.  
  254.     if (strbuf[0] == '\0')
  255.         return(s);
  256.  
  257.     for (s = strbuf; *s; ++s)
  258.         *s = EXT_C(*s);
  259.     return(strbuf);
  260. }
  261.  
  262.  
  263. static struct {
  264.     long lang_fsize;    /* size of language.txt */
  265.     char lang[16];        /* language identifier */
  266.     int nmsg;            /* number of messages */
  267. } indx_hdr;
  268.  
  269.  
  270. /*
  271.  * initialize the index table: read it from language.idx or create
  272.  * a new one and write it to the index file. A new index file is
  273.  * created if the language set in config.pgp doesn't match the one
  274.  * in language.idx or if the size of language.txt has changed.
  275.  */
  276. static void
  277. init_lang()
  278. {
  279.     char indexfile[MAX_PATH];
  280.     char subtitles_file[MAX_PATH];
  281.     FILE *indexf;
  282.  
  283.     if (strcmp(language, "en") == 0)
  284.     {    subtitles_available = -1;
  285.         return;        /* use default messages */
  286.     }
  287.  
  288.     buildfilename (subtitles_file, SUBTITLES_FILE);
  289.     if ((langf = fopen(subtitles_file, FOPRTXT)) == NULL)
  290.     {
  291.         subtitles_available = -1;
  292.         return;
  293.     }
  294.     init_crc();
  295.     if ((strbuf = (char *) malloc(STRBUFSIZE)) == NULL)
  296.     {
  297.         fprintf(stderr, "Not enough memory for foreign subtitles\n");
  298.         fclose(langf);
  299.         subtitles_available = -1;
  300.         return;
  301.     }
  302.     buildfilename(indexfile, LANG_INDEXFILE);
  303.     if ((indexf = fopen(indexfile, FOPRBIN)) != NULL)
  304.     {
  305.         if (fread(&indx_hdr, 1, sizeof(indx_hdr), indexf) == sizeof(indx_hdr) &&
  306.             indx_hdr.lang_fsize == fsize(langf) &&
  307.             strcmp(indx_hdr.lang, language) == 0)
  308.         {
  309.             nmsg = indx_hdr.nmsg;
  310.             indx_tbl = (struct indx_ent *) malloc(nmsg * sizeof(struct indx_ent));
  311.             if (indx_tbl == NULL)
  312.             {
  313.                 fprintf(stderr, "Not enough memory for foreign subtitles\n");
  314.                 fclose(indexf);
  315.                 fclose(langf);
  316.                 subtitles_available = -1;
  317.                 return;
  318.             }
  319.             if (fread(indx_tbl, sizeof(struct indx_ent), nmsg, indexf) != nmsg)
  320.             {
  321.                 free(indx_tbl);    /* create a new one */
  322.                 indx_tbl = NULL;
  323.             }
  324.         }
  325.         fclose(indexf);
  326.     }
  327.     if (indx_tbl == NULL && make_indexfile(indexfile) < 0)
  328.     {
  329.         fclose(langf);
  330.         subtitles_available = -1;
  331.     }
  332.     else
  333.         subtitles_available = 1;
  334. }
  335.  
  336.  
  337. static int
  338. make_indexfile(char *indexfile)
  339. {
  340.     FILE *indexf;
  341.     long filepos;
  342.     int total_msgs = 0;
  343.     char *res;
  344.  
  345.     if (verbose)    /* must be set in config.pgp */
  346.         fprintf(stderr, "Creating language index file '%s' for language \"%s\"\n",
  347.                 indexfile, language);
  348.     rewind(langf);
  349.     indx_hdr.lang_fsize = fsize(langf);
  350.     strncpy(indx_hdr.lang, language, 15);
  351.     init_crc();
  352.     line = 1;
  353.     nmsg = 0;
  354.     while (readstr(langf, strbuf, 0))
  355.     {
  356.         if (nmsg == max_msgs)
  357.         {
  358.             if (max_msgs)
  359.             {    max_msgs *= 2;
  360.                 indx_tbl = (struct indx_ent *) realloc(indx_tbl, max_msgs *
  361.                             sizeof(struct indx_ent));
  362.             }
  363.             else
  364.             {    max_msgs = 400;
  365.                 indx_tbl = (struct indx_ent *) malloc(max_msgs *
  366.                             sizeof(struct indx_ent));
  367.             }
  368.             if (indx_tbl == NULL)
  369.             {
  370.                 fprintf(stderr, "Not enough memory for foreign subtitles\n");
  371.                 return(-1);
  372.             }
  373.         }
  374.         ++total_msgs;
  375.         indx_tbl[nmsg].crc = message_crc(strbuf);
  376.         if (lookup_offset(indx_tbl[nmsg].crc) != -1)
  377.             fprintf(stderr, "language.txt:%d: Message CRC not unique: \"%s\"\n",
  378.                     line, strbuf);
  379.         do
  380.         {
  381.             filepos = ftell(langf);
  382.             res = readstr (langf, strbuf, 1);        /* Abort if find newline first */
  383.         } while (res && strbuf[0] != '\0' && strcmp(language, lang) != 0);
  384.  
  385.         if (res == NULL)
  386.             break;
  387.         if (strbuf[0] == '\0')    /* No translation */
  388.             continue;
  389.  
  390.         indx_tbl[nmsg].offset = filepos;
  391.         ++nmsg;
  392.         do
  393.             res = readstr (langf, strbuf, 1);        /* Abort if find newline first */
  394.         while (res && strbuf[0] != '\0');
  395.     }
  396.     line = 0;
  397.     indx_hdr.nmsg = nmsg;
  398.     if (nmsg == 0)
  399.     {    fprintf(stderr, "No translations available for language \"%s\"\n\n",
  400.                 language);
  401.         return(-1);
  402.     }
  403.     if (verbose || total_msgs != nmsg)
  404.         fprintf(stderr, "%d messages, %d translations\n\n", total_msgs, nmsg);
  405.  
  406.     if ((indexf = fopen(indexfile, FOPWBIN)) == NULL)
  407.         fprintf(stderr, "Cannot create %s\n", indexfile);
  408.     else
  409.     {
  410.         fwrite(&indx_hdr, 1, sizeof(indx_hdr), indexf);
  411.         fwrite(indx_tbl, sizeof(struct indx_ent), nmsg, indexf);
  412.         if (ferror(indexf) || fclose(indexf))
  413.             fprintf(stderr, "error writing %s\n", indexfile);
  414.     }
  415.     return(0);
  416. }
  417. #endif /* TEST */
  418.