home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1998 #6
/
amigamamagazinepolishissue1998.iso
/
varia
/
pgp
/
pgpamiga
/
source
/
language.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-11-08
|
9KB
|
418 lines
/*
* language.c - Foreign language translation for PGP
* Finds foreign language "subtitles" for English phrases
* in external foriegn language text file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "usuals.h"
#include "fileio.h"
#include "language.h"
#include "pgp.h"
#include "charset.h"
#include "armor.h"
#define SUBTITLES_FILE "language.txt"
#define LANG_INDEXFILE "language.idx"
#define STRBUFSIZE 2048
char language[16] = "en"; /* The language code, defaults to English */
static char *strbuf;
static char lang[16]; /* readstr sets this to the language id of the msg it last read */
static int subtitles_available = 0;
static int line = 0;
/* subtitles_available is used to determine if we know whether the special
subtitles_file exists. subtitles_available has the following values:
0 = first time thru, we don't yet know if subtitles_file exists.
1 = we have already determined that subtitles_file exists.
-1 = we have already determined that subtitles_file does not exist.
*/
#define NEWLINE 0
#define COMMENT 1
#define INSTRING 2
#define ESCAPE 3
#define IDENT 4
#define DONE 5
#define ERROR 6
#define ERR1 7
/* Look for and return a quoted string from the file.
* If nlabort is true, return failure if we find a blank line
* before we find the opening quote.
*/
static char *
readstr (FILE *f, char *buf, int nlabort)
{ int c, d;
char *p = buf;
int state = NEWLINE;
int i = 0;
while ((c = getc(f)) != EOF)
{
if (c == '\r')
continue;
/* line numbers are only incremented when creating index file */
if (line && c == '\n')
++line;
switch (state)
{
case NEWLINE:
switch(c)
{
case '#': state = COMMENT; break;
case '"': state = INSTRING; break;
case '\n':
if (nlabort)
{ *buf = '\0';
return(buf);
}
default:
if (i == 0 && isalnum(c))
{
state = IDENT;
lang[i++] = c;
break;
}
if (!isspace(c))
{
fprintf(stderr, "language.txt:%d: syntax error\n", line);
state = ERROR;
}
}
break;
case COMMENT:
if (c == '\n')
state = NEWLINE;
break;
case INSTRING:
switch(c)
{
case '\\': state = ESCAPE; break;
case '"': state = DONE; break;
default: *p++ = c;
}
break;
case ESCAPE:
switch (c)
{
case 'n': *p++ = '\n'; break;
case 'r': *p++ = '\r'; break;
case 't': *p++ = '\t'; break;
case 'e': *p++ = '\033'; break;
case 'a': *p++ = '\007'; break;
case '#':
case '"':
case '\\': *p++ = c; break;
case '\n': break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
d = c - '0';
while ((c = fgetc(f)) >= '0' && c <= '7')
d = 8 * d + c - '0';
*p++ = d;
ungetc(c, f);
break;
default:
fprintf(stderr, "language.txt:%d: illegal escape sequence: '\\%c'\n", line, c);
break;
}
state = INSTRING;
break;
case IDENT: /* language identifier */
if (c == ':') {
state = NEWLINE;
break;
}
if (c == '\n' && strncmp(lang, "No translation", 14) == 0)
{
i = 0;
state = NEWLINE;
break;
}
lang[i++] = c;
if (i == 15 || !isalnum(c) && !isspace(c))
{
lang[i] = '\0';
fprintf(stderr, "language.txt:%d: bad language identifier: '%s'\n", line, lang);
state = ERROR;
i = 0;
}
break;
case DONE:
if (c == '\n')
{
lang[i] = '\0';
*p = '\0';
return(buf);
}
if (!isspace(c))
{
fprintf(stderr, "language.txt:%d: extra characters after '\"'\n", line);
state = ERROR;
}
break;
case ERROR:
if (c == '\n')
state = ERR1;
break;
case ERR1:
state = (c == '\n' ? NEWLINE : ERROR);
break;
}
}
if (state != NEWLINE)
fprintf(stderr, "language.txt: unexpected EOF\n");
return(NULL);
}
#ifdef TEST
main()
{
char buf[2048];
line = 1;
while (readstr(stdin, buf, 0)) {
printf("\nen: <%s>\n", buf);
while (readstr(stdin, buf, 1) && *buf != '\0')
printf("%s: <%s>\n", lang, buf);
}
exit(0);
}
#else
static struct indx_ent {
word32 crc;
long offset;
} *indx_tbl = NULL;
static int max_msgs = 0;
static int nmsg = 0;
static FILE *langf;
static void init_lang(void);
static int make_indexfile(char *);
/*
* uses 24-bit CRC function from armor.c
*/
static word32
message_crc(char *s)
{
return crcbytes((byte *)s, strlen(s), (word32)0);
}
/*
* lookup file offset in indx_tbl
*/
static long
lookup_offset(word32 crc)
{
int i;
for (i = 0; i < nmsg; ++i)
if (indx_tbl[i].crc == crc)
return(indx_tbl[i].offset);
return(-1);
}
/*
* return foreign translation of s
*/
char *
PSTR (char *s)
{
long filepos;
if (subtitles_available == 0)
init_lang();
if (subtitles_available < 0)
return(s);
filepos = lookup_offset(message_crc(s));
if (filepos == -1)
return(s);
else
{
fseek(langf, filepos, SEEK_SET);
readstr(langf, strbuf, 1);
}
if (strbuf[0] == '\0')
return(s);
for (s = strbuf; *s; ++s)
*s = EXT_C(*s);
return(strbuf);
}
static struct {
long lang_fsize; /* size of language.txt */
char lang[16]; /* language identifier */
int nmsg; /* number of messages */
} indx_hdr;
/*
* initialize the index table: read it from language.idx or create
* a new one and write it to the index file. A new index file is
* created if the language set in config.pgp doesn't match the one
* in language.idx or if the size of language.txt has changed.
*/
static void
init_lang()
{
char indexfile[MAX_PATH];
char subtitles_file[MAX_PATH];
FILE *indexf;
if (strcmp(language, "en") == 0)
{ subtitles_available = -1;
return; /* use default messages */
}
buildfilename (subtitles_file, SUBTITLES_FILE);
if ((langf = fopen(subtitles_file, FOPRTXT)) == NULL)
{
subtitles_available = -1;
return;
}
init_crc();
if ((strbuf = (char *) malloc(STRBUFSIZE)) == NULL)
{
fprintf(stderr, "Not enough memory for foreign subtitles\n");
fclose(langf);
subtitles_available = -1;
return;
}
buildfilename(indexfile, LANG_INDEXFILE);
if ((indexf = fopen(indexfile, FOPRBIN)) != NULL)
{
if (fread(&indx_hdr, 1, sizeof(indx_hdr), indexf) == sizeof(indx_hdr) &&
indx_hdr.lang_fsize == fsize(langf) &&
strcmp(indx_hdr.lang, language) == 0)
{
nmsg = indx_hdr.nmsg;
indx_tbl = (struct indx_ent *) malloc(nmsg * sizeof(struct indx_ent));
if (indx_tbl == NULL)
{
fprintf(stderr, "Not enough memory for foreign subtitles\n");
fclose(indexf);
fclose(langf);
subtitles_available = -1;
return;
}
if (fread(indx_tbl, sizeof(struct indx_ent), nmsg, indexf) != nmsg)
{
free(indx_tbl); /* create a new one */
indx_tbl = NULL;
}
}
fclose(indexf);
}
if (indx_tbl == NULL && make_indexfile(indexfile) < 0)
{
fclose(langf);
subtitles_available = -1;
}
else
subtitles_available = 1;
}
static int
make_indexfile(char *indexfile)
{
FILE *indexf;
long filepos;
int total_msgs = 0;
char *res;
if (verbose) /* must be set in config.pgp */
fprintf(stderr, "Creating language index file '%s' for language \"%s\"\n",
indexfile, language);
rewind(langf);
indx_hdr.lang_fsize = fsize(langf);
strncpy(indx_hdr.lang, language, 15);
init_crc();
line = 1;
nmsg = 0;
while (readstr(langf, strbuf, 0))
{
if (nmsg == max_msgs)
{
if (max_msgs)
{ max_msgs *= 2;
indx_tbl = (struct indx_ent *) realloc(indx_tbl, max_msgs *
sizeof(struct indx_ent));
}
else
{ max_msgs = 400;
indx_tbl = (struct indx_ent *) malloc(max_msgs *
sizeof(struct indx_ent));
}
if (indx_tbl == NULL)
{
fprintf(stderr, "Not enough memory for foreign subtitles\n");
return(-1);
}
}
++total_msgs;
indx_tbl[nmsg].crc = message_crc(strbuf);
if (lookup_offset(indx_tbl[nmsg].crc) != -1)
fprintf(stderr, "language.txt:%d: Message CRC not unique: \"%s\"\n",
line, strbuf);
do
{
filepos = ftell(langf);
res = readstr (langf, strbuf, 1); /* Abort if find newline first */
} while (res && strbuf[0] != '\0' && strcmp(language, lang) != 0);
if (res == NULL)
break;
if (strbuf[0] == '\0') /* No translation */
continue;
indx_tbl[nmsg].offset = filepos;
++nmsg;
do
res = readstr (langf, strbuf, 1); /* Abort if find newline first */
while (res && strbuf[0] != '\0');
}
line = 0;
indx_hdr.nmsg = nmsg;
if (nmsg == 0)
{ fprintf(stderr, "No translations available for language \"%s\"\n\n",
language);
return(-1);
}
if (verbose || total_msgs != nmsg)
fprintf(stderr, "%d messages, %d translations\n\n", total_msgs, nmsg);
if ((indexf = fopen(indexfile, FOPWBIN)) == NULL)
fprintf(stderr, "Cannot create %s\n", indexfile);
else
{
fwrite(&indx_hdr, 1, sizeof(indx_hdr), indexf);
fwrite(indx_tbl, sizeof(struct indx_ent), nmsg, indexf);
if (ferror(indexf) || fclose(indexf))
fprintf(stderr, "error writing %s\n", indexfile);
}
return(0);
}
#endif /* TEST */