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