|
|
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 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.