home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 10
/
Fresh_Fish_10_2352.bin
/
new
/
dev
/
lang
/
sgmls
/
src
/
msgcat.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-07-10
|
16KB
|
841 lines
/* msgcat.c -
X/Open message catalogue functions and gencat utility.
Written by James Clark (jjc@jclark.com).
*/
#include "config.h"
#ifndef HAVE_CAT
/* In this implementation the message catalogue format is the same as the
message text source file format (see pp 42-43 of the X/Open
Portability Guide, Issue 3, Volume 3.) This means that you don't have
to use the gencat utility, but it is still useful for checking and
merging catalogues. */
/* Compile this with -DGENCAT to get the gencat utility. */
#include "std.h"
#include "msgcat.h"
#ifdef USE_PROTOTYPES
#define P(parms) parms
#else
#define P(parms) ()
#endif
#ifdef USE_ISASCII
#define ISASCII(c) isascii(c)
#else
#define ISASCII(c) (1)
#endif
/* Default message set. */
#define NL_SETD 1
#ifndef PATH_FILE_SEP
#define PATH_FILE_SEP ':'
#endif
#ifndef DEFAULT_NLSPATH
#define DEFAULT_NLSPATH ""
#endif
#ifndef DEFAULT_LANG
#define DEFAULT_LANG "default"
#endif
#define HASH_TAB_SIZE 251
struct message {
struct message *next;
unsigned msgnum;
unsigned setnum;
char *text;
};
struct cat {
char *name;
int loaded;
int bad;
struct message *table[HASH_TAB_SIZE];
};
static char *read_buf = 0;
static unsigned read_buf_len = 0;
/* Errors that can be generated by read_catalog. */
enum cat_err {
E_ZERO, /* not an error */
E_BADARG,
E_NOMEM,
E_NOSUCHCOMMAND,
E_INPUT,
E_EOF,
E_BADSEP,
E_BADLINE
};
#ifdef GENCAT
/* These must match enum cat_err. */
static char *cat_errlist[] = {
"Error 0",
"Invalid argument to command",
"Out of memory",
"Unrecognized command",
"Input error",
"Unexpected end of file",
"Space or tab expected after message number",
"Invalid line",
};
#endif /* GENCAT */
#ifndef GENCAT
/* The value of NLSPATH. */
static char *nlspath = 0;
/* The value of LANG. */
static char *lang = 0;
#endif /* not GENCAT */
static int current_lineno = -1;
static enum cat_err cat_errno = E_ZERO;
#ifndef GENCAT
static void load_catalog P((struct cat *));
static FILE *find_catalog P((char *, char **));
#endif
static int read_catalog P((FILE *, struct message **));
static void delete_set P((struct message **, unsigned));
static void delete_message P((struct message **, unsigned, unsigned));
static int hash P((unsigned setnum, unsigned msgnum));
static char *parse_text P((FILE *, int));
#ifndef GENCAT
nl_catd catopen(char *name, int oflag)
{
struct cat *catp;
int i;
if (!name)
return 0;
catp = (struct cat *)malloc(sizeof *catp);
if (!catp)
return 0;
for (i = 0; i < HASH_TAB_SIZE; i++)
catp->table[i] = 0;
catp->name = malloc(strlen(name) + 1);
catp->loaded = 0;
catp->bad = 0;
strcpy(catp->name, name);
return (nl_catd)catp;
}
int catclose(nl_catd catd)
{
int i;
struct cat *catp = (struct cat *)catd;
if (!catp)
return 0;
for (i = 0; i < HASH_TAB_SIZE; i++) {
struct message *p, *nextp;
for (p = catp->table[i]; p; p = nextp) {
nextp = p->next;
free(p->text);
free((char *)p);
}
}
if (catp->name)
free(catp->name);
free((char *)catp);
return 0;
}
char *catgets(nl_catd catd, int setnum, int msgnum, char *dflt)
{
struct message *p;
struct cat *catp;
/* setnum and msgnum are required to be >= 1. */
if (!catd || setnum <= 0 || msgnum <= 0)
return dflt;
catp = (struct cat *)catd;
if (!catp->loaded)
load_catalog(catp);
if (catp->bad)
return dflt;
for (p = catp->table[hash(setnum, msgnum)]; p; p = p->next)
if (p->msgnum == msgnum && p->setnum == setnum)
break;
if (!p)
return dflt;
return p->text;
}
static
VOID load_catalog(catp)
struct cat *catp;
{
FILE *fp;
char *path;
catp->loaded = 1;
fp = find_catalog(catp->name, &path);
if (!fp) {
catp->bad = 1;
return;
}
current_lineno = 0;
if (read_catalog(fp, catp->table) < 0)
catp->bad = 1;
fclose(fp);
if (read_buf) {
free(read_buf);
read_buf = 0;
}
read_buf_len = 0;
free(path);
}
static
FILE *find_catalog(name, pathp)
char *name;
char **pathp;
{
char *path;
if (!name)
return 0;
if (!nlspath) {
nlspath = getenv("NLSPATH");
if (!nlspath)
nlspath = DEFAULT_NLSPATH;
}
if (!lang) {
lang = getenv("LANG");
if (!lang)
lang = DEFAULT_LANG;
}
path = nlspath;
for (;;) {
char *p;
unsigned len = 0;
for (p = path; *p != '\0' && *p != PATH_FILE_SEP; p++) {
if (*p == '%') {
if (p[1] == 'N') {
p++;
len += strlen(name);
}
else if (p[1] == 'L') {
p++;
len += strlen(lang);
}
else if (p[1] == '%') {
p++;
len++;
}
else
len++;
}
else
len++;
}
if (len > 0) {
char *s, *try;
FILE *fp;
s = try = malloc(len + 1);
if (!s)
return 0;
for (p = path; *p != '\0' && *p != PATH_FILE_SEP; p++) {
if (*p == '%') {
if (p[1] == 'N') {
p++;
strcpy(s, name);
s += strlen(name);
}
else if (p[1] == 'L') {
p++;
strcpy(s, lang);
s += strlen(lang);
}
else if (p[1] == '%') {
p++;
*s++ = '%';
}
else
*s++ = *p;
}
else
*s++ = *p;
}
*s++ = '\0';
fp = fopen(try, "r");
if (fp) {
*pathp = try;
return fp;
}
free(try);
}
if (*p == '\0')
break;
path = ++p;
}
return 0;
}
#endif /* not GENCAT */
/* 0 success, -1 error */
static
int parse_message(int c, FILE *fp, struct message **table, unsigned setnum, int quote)
{
unsigned msgnum;
struct message *msgp;
char *text;
int hc;
msgnum = c - '0';
for (;;) {
c = getc(fp);
if (!isdigit(c))
break;
msgnum = msgnum*10 + (c - '0');
}
if (c == '\n') {
delete_message(table, setnum, msgnum);
return 0;
}
if (c != ' ' && c != '\t') {
cat_errno = E_BADSEP;
return -1;
}
text = parse_text(fp, quote);
if (!text)
return -1;
hc = hash(setnum, msgnum);
for (msgp = table[hc]; msgp; msgp = msgp->next)
if (msgp->setnum == setnum && msgp->msgnum == msgnum)
break;
if (msgp)
free(msgp->text);
else {
msgp = (struct message *)malloc(sizeof *msgp);
if (!msgp) {
cat_errno = E_NOMEM;
return -1;
}
msgp->next = table[hc];
table[hc] = msgp;
msgp->msgnum = msgnum;
msgp->setnum = setnum;
}
msgp->text = text;
return 0;
}
static
char *parse_text(fp, quote)
FILE *fp;
int quote;
{
unsigned i = 0;
char *p;
int c;
int quoted;
c = getc(fp);
if (c == quote) {
quoted = 1;
c = getc(fp);
}
else
quoted = 0;
for (;; c = getc(fp)) {
if (c == EOF) {
if (ferror(fp)) {
cat_errno = E_INPUT;
return 0;
}
break;
}
if (c == '\n')
break;
/* XXX
Can quotes be used in quoted message text if protected by \ ?
Is it illegal to omit the closing quote if there's an opening
quote?
Is it illegal to have anything after a closing quote?
*/
if (quoted && c == quote) {
/* Skip the rest of the line. */
while ((c = getc(fp)) != '\n')
if (c == EOF) {
if (ferror(fp)) {
cat_errno = E_INPUT;
return 0;
}
break;
}
break;
}
if (c == '\\') {
int d;
c = getc(fp);
if (c == EOF)
break;
switch (c) {
case '\n':
current_lineno++;
continue;
case 'n':
c = '\n';
break;
case 'b':
c = '\b';
break;
case 'f':
c = '\f';
break;
case 't':
c = '\t';
break;
case 'v':
c = '\v';
break;
case 'r':
c = '\r';
break;
case '\\':
c = '\\';
break;
case '0':
case '1':
case '2':