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

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

unix.superglobalmegacorp.com

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