/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 2000-2011 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* Glenn Fowler
* AT&T Research
*/
static const char usage[] =
"[-?\n@(#)$Id: msggen (AT&T Research) 2002-03-11 $\n]"
"[+NAME?msggen - generate a machine independent formatted message catalog]"
"[+DESCRIPTION?\bmsggen\b merges the message text source files \amsgfile\a"
" into a machine independent formatted message catalog \acatfile\a."
" The file \acatfile\a will be created if it does not already exist."
" If \acatfile\a does exist, its messages will be included in the new"
" \acatfile\a. If set and message numbers collide, the new message"
" text defined in \amsgfile\a will replace the old message text"
" currently contained in \acatfile\a. Non-ASCII characters must be"
"[f:format?List the \bprintf\b(3) format signature for each message in"
" \acatfile\a. A format signature is one line containing one character"
" per format specification:]{"
" [c?char]"
" [d?double]"
" [D?long double]"
" [f?float]"
" [h?short]"
" [i?int]"
" [j?long long]"
" [l?long]"
" [p?void*]"
" [s?string]"
" [t?ptrdiff_t]"
" [z?size_t]"
" [???unknown]"
"}"
"[l:list?List \acatfile\a in UTF-8 \amsgfile\a form.]"
"[s:set?Convert the \acatfile\a operand to a message set number and"
" print the number on the standard output.]"
"[+EXTENDED DESCRIPTION?Message text source files are in \bgencat\b(1)"
" format, defined as follows. Note that the fields of a message text"
" source line are separated by a single blank character. Any other"
" blank characters are considered as being part of the subsequent"
" field. The \bNL_*\b constants are defined in one or both of"
" \b<limits.h>\b and \b<nl_types.h>\b.]{"
" [+$ \acomment\a?A line beginning with \b$\b followed by a"
" blank character is treated as a comment.]"
" [+$delset \an\a \acomment\a?This line deletes message set"
" \an\a from an existing message catalog. \an\a"
" denotes the set number [1, \bNL_SETMAX\b]]. Any"
" text following the set number is treated as a"
" comment.]"
" [+$quote \ac\a?This line specifies an optional quote"
" character \ac\a, which can be used to surround"
" \amessage-text\a so that trailing spaces or"
" empty messages are visible in a message source"
" line. By default, or if an empty \b$quote\b"
" directive is supplied, no quoting of \amessage-text\a"
" will be recognized.]"
" [+$set \an\a \acomment\a?This line specifies the set"
" identifier of the following messages until the next"
" \b$set\b or end-of-file appears. \an\a denotes the set"
" identifier, which is defined as a number in the range"
" [1, \bNL_SETMAX\b]]. Set numbers need not be"
" contiguous. Any text following the set identifier is"
" treated as a comment. If no \b$set\b directive is"
" specified in a message text source file, all messages"
" will be located in message set \b1\b.]"
" [+$translation \aidentification\a \aYYYY-MM-DD\a[,...]]?Append"
" translation info to the message catalog header. Only"
" the newest date for a given \aidentification\a"
" is retained in the catalog. Multiple translation lines"
" are combined into a single \b,\b separated list.]"
" [+\am\a \amessage-text\a?\am\a denotes the message identifier,"
" which is defined as a number in the range"
" [1, \bNL_MSGMAX\b]]. The message-text is stored in the"
" message catalogue with the set identifier specified by"
" the last \b$set\b directive, and with message"
" identifier \am\a. If the \amessage-text\a is empty,"
" and a blank character field separator is present, an"
" empty string is stored in the message catalogue. If a"
" message source line has a message number, but neither"
" a field separator nor \amessage-text\a, the existing"
" message with that number (if any) is deleted from the"
" catalogue. Message identifiers need not be contiguous."
" There are no \amessage-text\a length restrictions.]"
"}"
"\n"
"\ncatfile [ msgfile ]\n"
"\n"
"[+SEE ALSO?\bgencat\b(1), \biconv\b(1), \bmsgcc\b(1), \btranslate\b(1),"
" \bfmtfmt\b(3)]"
;
#include <ast.h>
#include <ctype.h>
#include <ccode.h>
#include <error.h>
#include <mc.h>
typedef struct Xl_s
{
char* date;
} Xl_t;
/*
* append s to the translation list
*/
static Xl_t*
{
register char* t;
char* d;
char* e;
do
{
for (; isspace(*s); s++);
for (d = e = 0, t = s; *t; t++)
if (*t == ',')
{
e = t;
*e++ = 0;
break;
}
else if (isspace(*t))
d = t;
if (d)
{
*d++ = 0;
{
{
}
break;
}
if (!px)
{
}
}
} while (s = e);
return xp;
}
/*
* sfprintf() with ccmaps(from,to)
*/
static int
{
char* s;
int n;
{
sfstrclose(tp);
}
else
n = -1;
return n;
}
int
{
register char* s;
register char* t;
register int c;
register int q;
register int i;
int num;
char* b;
char* e;
char* catfile;
char* msgfile;
int format = 0;
int list = 0;
int set = 0;
for (;;)
{
{
case 'f':
continue;
case 'l':
list = 1;
continue;
case 's':
set = 1;
continue;
case '?':
continue;
case ':':
continue;
}
break;
}
/*
* set and list only need catfile
*/
if (set)
{
return error_info.errors != 0;
}
else if (list)
{
if (format)
{
{
}
}
else
{
if (*mc->translation)
{
}
{
{
while (c = *s++)
{
/*INDENT...*/
switch (c)
{
case 0x22: /* " */
case 0x5C: /* \ */
break;
case 0x07: /* \a */
c = 0x61;
break;
case 0x08: /* \b */
c = 0x62;
break;
case 0x0A: /* \n */
c = 0x6E;
break;
case 0x0B: /* \v */
c = 0x76;
break;
case 0x0C: /* \f */
c = 0x66;
break;
case 0x0D: /* \r */
c = 0x72;
break;
}
/*...UNDENT*/
}
}
}
}
return error_info.errors != 0;
}
/*
* open the files and handles
*/
if (sp)
/*
* read the message file
*/
q = 0;
set = 1;
{
error_info.line++;
if (!*s)
continue;
if (*s == '$')
{
if (!*++s || isspace(*s))
continue;
for (t = s; *s && !isspace(*s); s++);
if (*s)
*s++ = 0;
if (streq(t, "delset"))
{
while (isspace(*s))
s++;
}
else if (streq(t, "quote"))
q = *s ? *s : 0;
else if (streq(t, "set"))
{
while (isspace(*s))
s++;
if (e != s)
else
}
else if (streq(t, "translation"))
}
else
{
if (e != s)
{
s = e;
if (!*s)
{
}
else if (isspace(*s++))
{
if (t > (s + 1) && *(t -= 2) == '\\')
{
{
error_info.line++;
if (t <= (s + 1) || *(t -= 2) != '\\')
break;
}
}
if (q)
{
if (*s++ != q)
{
continue;
}
b = t = s;
while (c = *s++)
{
if (c == '\\')
{
c = chresc(s - 1, &e);
s = e;
if (c)
*t++ = c;
else
}
else if (c == q)
break;
else
*t++ = c;
}
if (*s)
{
continue;
}
*t = 0;
s = b;
}
}
else
}
else
}
}
error_info.file = 0;
error_info.line = 0;
/*
* fix up the translation record
*/
if (xp)
{
t = "";
for (;;)
{
if (!bp)
break;
t = ", ";
}
}
/*
* dump the catalog to a local temporary
* rename if no errors
*/
{
remove(s);
}
return error_info.errors != 0;
}