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