Annotation of pgp/src/language.c, revision 1.1.1.4

1.1.1.2   root        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"
1.1.1.3   root       15: #include "charset.h"
1.1.1.4 ! root       16: #include "armor.h"
1.1.1.2   root       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':
1.1.1.4 ! root      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';
1.1.1.2   root      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: 
1.1.1.3   root      204: static void init_lang(void);
                    205: 
1.1.1.2   root      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: {
1.1.1.4 ! root      214:        return crcbytes((byte *)s, strlen(s), (word32)0);
1.1.1.2   root      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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.