857 lines
17 KiB
C
857 lines
17 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these librararies and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* $XConsortium: msgcat.c /main/3 1996/06/19 17:16:22 drk $ */
|
|
/* 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
|
|
|
|
/* 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(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;
|
|
}
|
|
|
|
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(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;
|
|
}
|
|
|
|
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':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
c -= '0';
|
|
d = getc(fp);
|
|
if (d >= '0' && d <= '7') {
|
|
c = c*8 + d - '0';
|
|
d = getc(fp);
|
|
if (d >= '0' && d <= '7')
|
|
c = c*8 + d - '0';
|
|
else if (d != EOF)
|
|
ungetc(d,fp);
|
|
}
|
|
else if (d != EOF)
|
|
ungetc(d, fp);
|
|
if (c == '\0')
|
|
continue; /* XXX */
|
|
break;
|
|
default:
|
|
/* Ignore the quote. */
|
|
break;
|
|
}
|
|
}
|
|
if (i >= read_buf_len) {
|
|
if (!read_buf)
|
|
read_buf = malloc(read_buf_len = 40);
|
|
else
|
|
read_buf = realloc(read_buf, read_buf_len *= 2);
|
|
if (!read_buf) {
|
|
cat_errno = E_NOMEM;
|
|
return 0;
|
|
}
|
|
}
|
|
read_buf[i++] = c;
|
|
}
|
|
p = malloc(i + 1);
|
|
if (!p) {
|
|
cat_errno = E_NOMEM;
|
|
return 0;
|
|
}
|
|
memcpy(p, read_buf, i);
|
|
p[i] = '\0';
|
|
return p;
|
|
}
|
|
|
|
/* 0 success, -1 error */
|
|
|
|
static
|
|
int parse_command(fp, table, setnump, quotep)
|
|
FILE *fp;
|
|
struct message **table;
|
|
unsigned *setnump;
|
|
int *quotep;
|
|
{
|
|
char buf[128];
|
|
if (fgets(buf, 128, fp) == NULL) {
|
|
cat_errno = ferror(fp) ? E_INPUT : E_EOF;
|
|
return -1;
|
|
}
|
|
if (buf[0] == ' ' || buf[0] == '\t' || buf[0] == '\n')
|
|
/* a comment */;
|
|
else if (strncmp(buf, "set", 3) == 0) {
|
|
if (sscanf(buf + 3, "%u", setnump) != 1) {
|
|
cat_errno = E_BADARG;
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
else if (strncmp(buf, "delset", 6) == 0) {
|
|
unsigned num;
|
|
if (sscanf(buf + 6, "%u", &num) != 1) {
|
|
cat_errno = E_BADARG;
|
|
return -1;
|
|
}
|
|
delete_set(table, num);
|
|
*setnump = NL_SETD;
|
|
}
|
|
else if (strncmp(buf, "quote", 5) == 0) {
|
|
char *p = buf + 5;
|
|
while (*p == ' ' || *p == '\t')
|
|
p++;
|
|
/* XXX should \ be allowed as the quote character? */
|
|
if (*p == '\0' || *p == '\n')
|
|
*quotep = -1;
|
|
else
|
|
*quotep = *p;
|
|
}
|
|
else {
|
|
cat_errno = E_NOSUCHCOMMAND;
|
|
return -1;
|
|
}
|
|
if (strchr(buf, '\n') == 0) {
|
|
int c;
|
|
while ((c = getc(fp)) != '\n' && c != EOF)
|
|
;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static
|
|
VOID delete_set(table, setnum)
|
|
struct message **table;
|
|
unsigned setnum;
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < HASH_TAB_SIZE; i++) {
|
|
struct message *p, *nextp;
|
|
for (p = table[i], table[i] = 0; p; p = nextp) {
|
|
nextp = p->next;
|
|
if (p->setnum == setnum)
|
|
free((char *)p);
|
|
else {
|
|
p->next = table[i];
|
|
table[i] = p;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static
|
|
VOID delete_message(table, setnum, msgnum)
|
|
struct message **table;
|
|
unsigned setnum, msgnum;
|
|
{
|
|
struct message **pp;
|
|
|
|
for (pp = &table[hash(setnum, msgnum)]; *pp; pp = &(*pp)->next)
|
|
if ((*pp)->setnum == setnum && (*pp)->msgnum == msgnum) {
|
|
struct message *p = *pp;
|
|
*pp = p->next;
|
|
free(p->text);
|
|
free((char *)p);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* 0 success, -1 error. On error cat_errno is set to the error number. */
|
|
|
|
static
|
|
int read_catalog(fp, table)
|
|
FILE *fp;
|
|
struct message **table;
|
|
{
|
|
int c;
|
|
unsigned setnum = NL_SETD;
|
|
int quote_char = -1;
|
|
|
|
for (;;) {
|
|
/* start of line */
|
|
c = getc(fp);
|
|
if (c == EOF)
|
|
break;
|
|
++current_lineno;
|
|
if (isdigit(c)) {
|
|
if (parse_message(c, fp, table, setnum, quote_char) < 0)
|
|
return -1;
|
|
}
|
|
else if (c == '$') {
|
|
if (parse_command(fp, table, &setnum, "e_char) < 0)
|
|
return -1;
|
|
}
|
|
else if (c != '\n') {
|
|
while ((c = getc(fp)) != '\n' && c != EOF)
|
|
if (c != ' ' && c != '\t') {
|
|
cat_errno = E_BADLINE;
|
|
return -1;
|
|
}
|
|
if (c == EOF)
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int hash(setnum, msgnum)
|
|
unsigned setnum, msgnum;
|
|
{
|
|
return ((setnum << 8) + msgnum) % HASH_TAB_SIZE;
|
|
}
|
|
|
|
#ifdef GENCAT
|
|
|
|
static char *program_name;
|
|
|
|
static int message_compare P((UNIV, UNIV));
|
|
static void print_text P((char *, FILE *));
|
|
static void usage P((void));
|
|
|
|
#ifdef VARARGS
|
|
static void fatal();
|
|
#else
|
|
static void fatal P((char *,...));
|
|
#endif
|
|
|
|
int main(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
FILE *fp;
|
|
int i, j, nmessages;
|
|
struct message **list;
|
|
unsigned setnum;
|
|
struct message *table[HASH_TAB_SIZE];
|
|
|
|
program_name = argv[0];
|
|
|
|
if (argc < 3)
|
|
usage();
|
|
|
|
for (i = 0; i < HASH_TAB_SIZE; i++)
|
|
table[i] = 0;
|
|
for (i = 1; i < argc; i++) {
|
|
errno = 0;
|
|
fp = fopen(argv[i], "r");
|
|
if (!fp) {
|
|
if (i > 1)
|
|
fatal("can't open `%s': %s", argv[i], strerror(errno));
|
|
}
|
|
else {
|
|
current_lineno = 0;
|
|
cat_errno = E_ZERO;
|
|
if (read_catalog(fp, table) < 0) {
|
|
assert(cat_errno != E_ZERO);
|
|
assert(cat_errno
|
|
< sizeof(cat_errlist)/sizeof(cat_errlist[0]));
|
|
fatal("%s:%d: %s", argv[i], current_lineno,
|
|
cat_errlist[cat_errno]);
|
|
}
|
|
fclose(fp);
|
|
}
|
|
}
|
|
|
|
errno = 0;
|
|
fp = fopen(argv[1], "w");
|
|
if (!fp)
|
|
fatal("can't open `%s' for output: %s", argv[1], strerror(errno));
|
|
nmessages = 0;
|
|
for (i = 0; i < HASH_TAB_SIZE; i++) {
|
|
struct message *p;
|
|
for (p = table[i]; p; p = p->next)
|
|
nmessages++;
|
|
}
|
|
list = (struct message **)malloc(nmessages*sizeof(struct message *));
|
|
if (!list)
|
|
fatal("out of memory");
|
|
j = 0;
|
|
for (i = 0; i < HASH_TAB_SIZE; i++) {
|
|
struct message *p;
|
|
for (p = table[i]; p; p = p->next)
|
|
list[j++] = p;
|
|
}
|
|
assert(j == nmessages);
|
|
|
|
qsort((UNIV)list, nmessages, sizeof(struct message *), message_compare);
|
|
|
|
setnum = NL_SETD;
|
|
for (i = 0; i < nmessages; i++) {
|
|
struct message *p = list[i];
|
|
if (p->setnum != setnum) {
|
|
setnum = p->setnum;
|
|
fprintf(fp, "$set %u\n", setnum);
|
|
}
|
|
fprintf(fp, "%u ", p->msgnum);
|
|
print_text(p->text, fp);
|
|
putc('\n', fp);
|
|
}
|
|
if (fclose(fp) == EOF)
|
|
fatal("error closing `%s'", argv[1]);
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
VOID usage()
|
|
{
|
|
fprintf(stderr, "usage: %s catfile msgfile...\n", program_name);
|
|
exit(1);
|
|
}
|
|
|
|
static
|
|
#ifdef VARARGS
|
|
VOID fatal(va_alist) va_dcl
|
|
#else /* not VARARGS */
|
|
VOID fatal(char *message,...)
|
|
#endif /* not VARARGS */
|
|
{
|
|
va_list ap;
|
|
|
|
#ifdef VARARGS
|
|
char *message;
|
|
va_start(ap);
|
|
message = va_arg(ap, char *);
|
|
#else /* not VARARGS */
|
|
va_start(ap, message);
|
|
#endif /* not VARARGS */
|
|
|
|
fprintf(stderr, "%s: ", program_name);
|
|
vfprintf(stderr, message, ap);
|
|
putc('\n', stderr);
|
|
va_end(ap);
|
|
exit(1);
|
|
}
|
|
|
|
static
|
|
int message_compare(p1, p2)
|
|
UNIV p1, UNIV p2;
|
|
{
|
|
struct message *m1 = *(struct message **)p1;
|
|
struct message *m2 = *(struct message **)p2;
|
|
|
|
if (m1->setnum < m2->setnum)
|
|
return -1;
|
|
if (m1->setnum > m2->setnum)
|
|
return 1;
|
|
if (m1->msgnum < m2->msgnum)
|
|
return -1;
|
|
if (m1->msgnum > m2->msgnum)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
VOID print_text(s, fp)
|
|
char *s;
|
|
FILE *fp;
|
|
{
|
|
for (; *s; s++) {
|
|
if (*s == '\\')
|
|
fputs("\\\\", fp);
|
|
else if (ISASCII(*s) && isprint((UNCH)*s))
|
|
putc(*s, fp);
|
|
else {
|
|
switch (*s) {
|
|
case '\n':
|
|
fputs("\\n", fp);
|
|
break;
|
|
case '\b':
|
|
fputs("\\b", fp);
|
|
break;
|
|
case '\f':
|
|
fputs("\\f", fp);
|
|
break;
|
|
case '\t':
|
|
fputs("\\t", fp);
|
|
break;
|
|
case '\v':
|
|
fputs("\\v", fp);
|
|
break;
|
|
case '\r':
|
|
fputs("\\r", fp);
|
|
break;
|
|
default:
|
|
fprintf(fp, "\\%03o", (unsigned char)*s);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif /* GENCAT */
|
|
|
|
#ifdef TEST
|
|
|
|
int main(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
nl_catd catd;
|
|
int msgnum, setnum;
|
|
|
|
if (argc != 2) {
|
|
fprintf(stderr, "usage: %s catalogue\n", argv[0]);
|
|
exit(1);
|
|
}
|
|
catd = catopen(argv[1], 0);
|
|
fprintf(stderr, "Enter set number, message number pairs:\n");
|
|
fflush(stderr);
|
|
while (scanf("%d %d", &setnum, &msgnum) == 2) {
|
|
char *msg = catgets(catd, setnum, msgnum, "<default>");
|
|
fprintf(stderr, "Returned \"%s\"\n", msg);
|
|
fflush(stderr);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endif /* TEST */
|
|
|
|
#endif /* not HAVE_CAT */
|
|
/*
|
|
Local Variables:
|
|
c-indent-level: 5
|
|
c-continued-statement-offset: 5
|
|
c-brace-offset: -5
|
|
c-argdecl-indent: 0
|
|
c-label-offset: -5
|
|
End:
|
|
*/
|