📄 msgcat.c
字号:
/* 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 themessage text source file format (see pp 42-43 of the X/OpenPortability Guide, Issue 3, Volume 3.) This means that you don't haveto use the gencat utility, but it is still useful for checking andmerging 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 251struct 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 GENCATstatic void load_catalog P((struct cat *));static FILE *find_catalog P((char *, char **));#endifstatic 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 GENCATnl_catd catopen(name, oflag)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(catd)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(catd, setnum, msgnum, dflt)nl_catd catd;int setnum, 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;}staticVOID 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);}staticFILE *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 */staticint parse_message(c, fp, table, setnum, quote)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;}staticchar *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':
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -