1*b30d1939SAndy Fiddaman /***********************************************************************
2*b30d1939SAndy Fiddaman *                                                                      *
3*b30d1939SAndy Fiddaman *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 2000-2011 AT&T Intellectual Property          *
5*b30d1939SAndy Fiddaman *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
7*b30d1939SAndy Fiddaman *                    by AT&T Intellectual Property                     *
8*b30d1939SAndy Fiddaman *                                                                      *
9*b30d1939SAndy Fiddaman *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*b30d1939SAndy Fiddaman *                                                                      *
13*b30d1939SAndy Fiddaman *              Information and Software Systems Research               *
14*b30d1939SAndy Fiddaman *                            AT&T Research                             *
15*b30d1939SAndy Fiddaman *                           Florham Park NJ                            *
16*b30d1939SAndy Fiddaman *                                                                      *
17*b30d1939SAndy Fiddaman *                 Glenn Fowler <gsf@research.att.com>                  *
18*b30d1939SAndy Fiddaman *                                                                      *
19*b30d1939SAndy Fiddaman ***********************************************************************/
20*b30d1939SAndy Fiddaman #pragma prototyped
21*b30d1939SAndy Fiddaman /*
22*b30d1939SAndy Fiddaman  * Glenn Fowler
23*b30d1939SAndy Fiddaman  * AT&T Research
24*b30d1939SAndy Fiddaman  */
25*b30d1939SAndy Fiddaman 
26*b30d1939SAndy Fiddaman static const char usage[] =
27*b30d1939SAndy Fiddaman "[-?\n@(#)$Id: msggen (AT&T Research) 2002-03-11 $\n]"
28*b30d1939SAndy Fiddaman USAGE_LICENSE
29*b30d1939SAndy Fiddaman "[+NAME?msggen - generate a machine independent formatted message catalog]"
30*b30d1939SAndy Fiddaman "[+DESCRIPTION?\bmsggen\b merges the message text source files \amsgfile\a"
31*b30d1939SAndy Fiddaman "	into a machine independent formatted message catalog \acatfile\a."
32*b30d1939SAndy Fiddaman "	The file \acatfile\a will be created if it does not already exist."
33*b30d1939SAndy Fiddaman "	If \acatfile\a does exist, its messages will be included in the new"
34*b30d1939SAndy Fiddaman "	\acatfile\a. If set and message numbers collide, the new message"
35*b30d1939SAndy Fiddaman "	text defined in \amsgfile\a will replace the old message text"
36*b30d1939SAndy Fiddaman "	currently contained in \acatfile\a. Non-ASCII characters must be"
37*b30d1939SAndy Fiddaman "	UTF-8 encoded. \biconv\b(1) can be used to convert to/from UTF-8.]"
38*b30d1939SAndy Fiddaman "[f:format?List the \bprintf\b(3) format signature for each message in"
39*b30d1939SAndy Fiddaman "	\acatfile\a. A format signature is one line containing one character"
40*b30d1939SAndy Fiddaman "	per format specification:]{"
41*b30d1939SAndy Fiddaman "		[c?char]"
42*b30d1939SAndy Fiddaman "		[d?double]"
43*b30d1939SAndy Fiddaman "		[D?long double]"
44*b30d1939SAndy Fiddaman "		[f?float]"
45*b30d1939SAndy Fiddaman "		[h?short]"
46*b30d1939SAndy Fiddaman "		[i?int]"
47*b30d1939SAndy Fiddaman "		[j?long long]"
48*b30d1939SAndy Fiddaman "		[l?long]"
49*b30d1939SAndy Fiddaman "		[p?void*]"
50*b30d1939SAndy Fiddaman "		[s?string]"
51*b30d1939SAndy Fiddaman "		[t?ptrdiff_t]"
52*b30d1939SAndy Fiddaman "		[z?size_t]"
53*b30d1939SAndy Fiddaman "		[???unknown]"
54*b30d1939SAndy Fiddaman "}"
55*b30d1939SAndy Fiddaman "[l:list?List \acatfile\a in UTF-8 \amsgfile\a form.]"
56*b30d1939SAndy Fiddaman "[s:set?Convert the \acatfile\a operand to a message set number and"
57*b30d1939SAndy Fiddaman "	print the number on the standard output.]"
58*b30d1939SAndy Fiddaman "[+EXTENDED DESCRIPTION?Message text source files are in \bgencat\b(1)"
59*b30d1939SAndy Fiddaman "	format, defined as follows. Note that the fields of a message text"
60*b30d1939SAndy Fiddaman "	source line are separated by a single blank character. Any other"
61*b30d1939SAndy Fiddaman "	blank characters are considered as being part of the subsequent"
62*b30d1939SAndy Fiddaman "	field. The \bNL_*\b constants are defined in one or both of"
63*b30d1939SAndy Fiddaman "	\b<limits.h>\b and \b<nl_types.h>\b.]{"
64*b30d1939SAndy Fiddaman "		[+$ \acomment\a?A line beginning with \b$\b followed by a"
65*b30d1939SAndy Fiddaman "			blank character is treated as a comment.]"
66*b30d1939SAndy Fiddaman "		[+$delset \an\a \acomment\a?This line deletes message set"
67*b30d1939SAndy Fiddaman "			\an\a from an existing message catalog. \an\a"
68*b30d1939SAndy Fiddaman "			denotes the set number [1, \bNL_SETMAX\b]]. Any"
69*b30d1939SAndy Fiddaman "			text following the set number is treated as a"
70*b30d1939SAndy Fiddaman "			comment.]"
71*b30d1939SAndy Fiddaman "		[+$quote \ac\a?This line specifies an optional quote"
72*b30d1939SAndy Fiddaman "			character \ac\a, which can be used to surround"
73*b30d1939SAndy Fiddaman "			\amessage-text\a so that trailing spaces or"
74*b30d1939SAndy Fiddaman "			empty messages are visible in a message source"
75*b30d1939SAndy Fiddaman "			line. By default, or if an empty \b$quote\b"
76*b30d1939SAndy Fiddaman "			directive is supplied, no quoting of \amessage-text\a"
77*b30d1939SAndy Fiddaman "			will be recognized.]"
78*b30d1939SAndy Fiddaman "		[+$set \an\a \acomment\a?This line specifies the set"
79*b30d1939SAndy Fiddaman "			identifier of the following messages until the next"
80*b30d1939SAndy Fiddaman "			\b$set\b or end-of-file appears. \an\a denotes the set"
81*b30d1939SAndy Fiddaman "			identifier, which is defined as a number in the range"
82*b30d1939SAndy Fiddaman "			[1, \bNL_SETMAX\b]]. Set numbers need not be"
83*b30d1939SAndy Fiddaman "			contiguous. Any text following the set identifier is"
84*b30d1939SAndy Fiddaman "			treated as a comment. If no \b$set\b directive is"
85*b30d1939SAndy Fiddaman "			specified in a 	message text source file, all messages"
86*b30d1939SAndy Fiddaman "			will be located in message set \b1\b.]"
87*b30d1939SAndy Fiddaman "		[+$translation \aidentification\a \aYYYY-MM-DD\a[,...]]?Append"
88*b30d1939SAndy Fiddaman "			translation info to the message catalog header. Only"
89*b30d1939SAndy Fiddaman "			the newest date for a given \aidentification\a"
90*b30d1939SAndy Fiddaman "			is retained in the catalog. Multiple translation lines"
91*b30d1939SAndy Fiddaman "			are combined into a single \b,\b separated list.]"
92*b30d1939SAndy Fiddaman "		[+\am\a \amessage-text\a?\am\a denotes the message identifier,"
93*b30d1939SAndy Fiddaman "			which is defined as a number in the range"
94*b30d1939SAndy Fiddaman "			[1, \bNL_MSGMAX\b]]. The message-text is stored in the"
95*b30d1939SAndy Fiddaman "			message catalogue with the set identifier specified by"
96*b30d1939SAndy Fiddaman "			the last \b$set\b directive, and with message"
97*b30d1939SAndy Fiddaman "			identifier \am\a. If the \amessage-text\a is empty,"
98*b30d1939SAndy Fiddaman "			and a blank character field separator is present, an"
99*b30d1939SAndy Fiddaman "			empty string is stored in the message catalogue. If a"
100*b30d1939SAndy Fiddaman "			message source line has a message number, but neither"
101*b30d1939SAndy Fiddaman "			a field separator nor \amessage-text\a, the existing"
102*b30d1939SAndy Fiddaman "			message with that number (if any) is deleted from the"
103*b30d1939SAndy Fiddaman "			catalogue. Message identifiers need not be contiguous."
104*b30d1939SAndy Fiddaman "			There are no \amessage-text\a length restrictions.]"
105*b30d1939SAndy Fiddaman "}"
106*b30d1939SAndy Fiddaman 
107*b30d1939SAndy Fiddaman "\n"
108*b30d1939SAndy Fiddaman "\ncatfile [ msgfile ]\n"
109*b30d1939SAndy Fiddaman "\n"
110*b30d1939SAndy Fiddaman 
111*b30d1939SAndy Fiddaman "[+SEE ALSO?\bgencat\b(1), \biconv\b(1), \bmsgcc\b(1), \btranslate\b(1),"
112*b30d1939SAndy Fiddaman "	\bfmtfmt\b(3)]"
113*b30d1939SAndy Fiddaman ;
114*b30d1939SAndy Fiddaman 
115*b30d1939SAndy Fiddaman #include <ast.h>
116*b30d1939SAndy Fiddaman #include <ctype.h>
117*b30d1939SAndy Fiddaman #include <ccode.h>
118*b30d1939SAndy Fiddaman #include <error.h>
119*b30d1939SAndy Fiddaman #include <mc.h>
120*b30d1939SAndy Fiddaman 
121*b30d1939SAndy Fiddaman typedef struct Xl_s
122*b30d1939SAndy Fiddaman {
123*b30d1939SAndy Fiddaman 	struct Xl_s*	next;
124*b30d1939SAndy Fiddaman 	char*		date;
125*b30d1939SAndy Fiddaman 	char		name[1];
126*b30d1939SAndy Fiddaman } Xl_t;
127*b30d1939SAndy Fiddaman 
128*b30d1939SAndy Fiddaman /*
129*b30d1939SAndy Fiddaman  * append s to the translation list
130*b30d1939SAndy Fiddaman  */
131*b30d1939SAndy Fiddaman 
132*b30d1939SAndy Fiddaman static Xl_t*
translation(Xl_t * xp,register char * s)133*b30d1939SAndy Fiddaman translation(Xl_t* xp, register char* s)
134*b30d1939SAndy Fiddaman {
135*b30d1939SAndy Fiddaman 	register Xl_t*	px;
136*b30d1939SAndy Fiddaman 	register char*	t;
137*b30d1939SAndy Fiddaman 	char*		d;
138*b30d1939SAndy Fiddaman 	char*		e;
139*b30d1939SAndy Fiddaman 
140*b30d1939SAndy Fiddaman 	do
141*b30d1939SAndy Fiddaman 	{
142*b30d1939SAndy Fiddaman 		for (; isspace(*s); s++);
143*b30d1939SAndy Fiddaman 		for (d = e = 0, t = s; *t; t++)
144*b30d1939SAndy Fiddaman 			if (*t == ',')
145*b30d1939SAndy Fiddaman 			{
146*b30d1939SAndy Fiddaman 				e = t;
147*b30d1939SAndy Fiddaman 				*e++ = 0;
148*b30d1939SAndy Fiddaman 				break;
149*b30d1939SAndy Fiddaman 			}
150*b30d1939SAndy Fiddaman 			else if (isspace(*t))
151*b30d1939SAndy Fiddaman 				d = t;
152*b30d1939SAndy Fiddaman 		if (d)
153*b30d1939SAndy Fiddaman 		{
154*b30d1939SAndy Fiddaman 			*d++ = 0;
155*b30d1939SAndy Fiddaman 			for (px = xp; px; px = px->next)
156*b30d1939SAndy Fiddaman 				if (streq(px->name, s))
157*b30d1939SAndy Fiddaman 				{
158*b30d1939SAndy Fiddaman 					if (strcoll(px->date, d) < 0)
159*b30d1939SAndy Fiddaman 					{
160*b30d1939SAndy Fiddaman 						free(px->date);
161*b30d1939SAndy Fiddaman 						if (!(px->date = strdup(d)))
162*b30d1939SAndy Fiddaman 							error(ERROR_SYSTEM|3, "out of space [translation]");
163*b30d1939SAndy Fiddaman 					}
164*b30d1939SAndy Fiddaman 					break;
165*b30d1939SAndy Fiddaman 				}
166*b30d1939SAndy Fiddaman 			if (!px)
167*b30d1939SAndy Fiddaman 			{
168*b30d1939SAndy Fiddaman 				if (!(px = newof(0, Xl_t, 1, strlen(s))) || !(px->date = strdup(d)))
169*b30d1939SAndy Fiddaman 					error(ERROR_SYSTEM|3, "out of space [translation]");
170*b30d1939SAndy Fiddaman 				strcpy(px->name, s);
171*b30d1939SAndy Fiddaman 				px->next = xp;
172*b30d1939SAndy Fiddaman 				xp = px;
173*b30d1939SAndy Fiddaman 			}
174*b30d1939SAndy Fiddaman 		}
175*b30d1939SAndy Fiddaman 	} while (s = e);
176*b30d1939SAndy Fiddaman 	return xp;
177*b30d1939SAndy Fiddaman }
178*b30d1939SAndy Fiddaman 
179*b30d1939SAndy Fiddaman /*
180*b30d1939SAndy Fiddaman  * sfprintf() with ccmaps(from,to)
181*b30d1939SAndy Fiddaman  */
182*b30d1939SAndy Fiddaman 
183*b30d1939SAndy Fiddaman static int
ccsfprintf(int from,int to,Sfio_t * sp,const char * format,...)184*b30d1939SAndy Fiddaman ccsfprintf(int from, int to, Sfio_t* sp, const char* format, ...)
185*b30d1939SAndy Fiddaman {
186*b30d1939SAndy Fiddaman 	va_list		ap;
187*b30d1939SAndy Fiddaman 	Sfio_t*		tp;
188*b30d1939SAndy Fiddaman 	char*		s;
189*b30d1939SAndy Fiddaman 	int		n;
190*b30d1939SAndy Fiddaman 
191*b30d1939SAndy Fiddaman 	va_start(ap, format);
192*b30d1939SAndy Fiddaman 	if (from == to)
193*b30d1939SAndy Fiddaman 		n = sfvprintf(sp, format, ap);
194*b30d1939SAndy Fiddaman 	else if (tp = sfstropen())
195*b30d1939SAndy Fiddaman 	{
196*b30d1939SAndy Fiddaman 		n = sfvprintf(tp, format, ap);
197*b30d1939SAndy Fiddaman 		s = sfstrbase(tp);
198*b30d1939SAndy Fiddaman 		ccmaps(s, n, from, to);
199*b30d1939SAndy Fiddaman 		n = sfwrite(sp, s, n);
200*b30d1939SAndy Fiddaman 		sfstrclose(tp);
201*b30d1939SAndy Fiddaman 	}
202*b30d1939SAndy Fiddaman 	else
203*b30d1939SAndy Fiddaman 		n = -1;
204*b30d1939SAndy Fiddaman 	return n;
205*b30d1939SAndy Fiddaman }
206*b30d1939SAndy Fiddaman 
207*b30d1939SAndy Fiddaman int
main(int argc,char ** argv)208*b30d1939SAndy Fiddaman main(int argc, char** argv)
209*b30d1939SAndy Fiddaman {
210*b30d1939SAndy Fiddaman 	register Mc_t*	mc;
211*b30d1939SAndy Fiddaman 	register char*	s;
212*b30d1939SAndy Fiddaman 	register char*	t;
213*b30d1939SAndy Fiddaman 	register int	c;
214*b30d1939SAndy Fiddaman 	register int	q;
215*b30d1939SAndy Fiddaman 	register int	i;
216*b30d1939SAndy Fiddaman 	int		num;
217*b30d1939SAndy Fiddaman 	char*		b;
218*b30d1939SAndy Fiddaman 	char*		e;
219*b30d1939SAndy Fiddaman 	char*		catfile;
220*b30d1939SAndy Fiddaman 	char*		msgfile;
221*b30d1939SAndy Fiddaman 	Sfio_t*		sp;
222*b30d1939SAndy Fiddaman 	Sfio_t*		mp;
223*b30d1939SAndy Fiddaman 	Sfio_t*		tp;
224*b30d1939SAndy Fiddaman 	Xl_t*		px;
225*b30d1939SAndy Fiddaman 	Xl_t*		bp;
226*b30d1939SAndy Fiddaman 
227*b30d1939SAndy Fiddaman 	Xl_t*		xp = 0;
228*b30d1939SAndy Fiddaman 	int		format = 0;
229*b30d1939SAndy Fiddaman 	int		list = 0;
230*b30d1939SAndy Fiddaman 	int		set = 0;
231*b30d1939SAndy Fiddaman 
232*b30d1939SAndy Fiddaman 	NoP(argc);
233*b30d1939SAndy Fiddaman 	error_info.id = "msggen";
234*b30d1939SAndy Fiddaman 	for (;;)
235*b30d1939SAndy Fiddaman 	{
236*b30d1939SAndy Fiddaman 		switch (optget(argv, usage))
237*b30d1939SAndy Fiddaman 		{
238*b30d1939SAndy Fiddaman 		case 'f':
239*b30d1939SAndy Fiddaman 			format = list = 1;
240*b30d1939SAndy Fiddaman 			continue;
241*b30d1939SAndy Fiddaman 		case 'l':
242*b30d1939SAndy Fiddaman 			list = 1;
243*b30d1939SAndy Fiddaman 			continue;
244*b30d1939SAndy Fiddaman 		case 's':
245*b30d1939SAndy Fiddaman 			set = 1;
246*b30d1939SAndy Fiddaman 			continue;
247*b30d1939SAndy Fiddaman 		case '?':
248*b30d1939SAndy Fiddaman 			error(ERROR_USAGE|4, "%s", opt_info.arg);
249*b30d1939SAndy Fiddaman 			continue;
250*b30d1939SAndy Fiddaman 		case ':':
251*b30d1939SAndy Fiddaman 			error(2, "%s", opt_info.arg);
252*b30d1939SAndy Fiddaman 			continue;
253*b30d1939SAndy Fiddaman 		}
254*b30d1939SAndy Fiddaman 		break;
255*b30d1939SAndy Fiddaman 	}
256*b30d1939SAndy Fiddaman 	argv += opt_info.index;
257*b30d1939SAndy Fiddaman 	if (error_info.errors || !(catfile = *argv++))
258*b30d1939SAndy Fiddaman 		error(ERROR_USAGE|4, "%s", optusage(NiL));
259*b30d1939SAndy Fiddaman 
260*b30d1939SAndy Fiddaman 	/*
261*b30d1939SAndy Fiddaman 	 * set and list only need catfile
262*b30d1939SAndy Fiddaman 	 */
263*b30d1939SAndy Fiddaman 
264*b30d1939SAndy Fiddaman 	if (set)
265*b30d1939SAndy Fiddaman 	{
266*b30d1939SAndy Fiddaman 		sfprintf(sfstdout, "%d\n", mcindex(catfile, NiL, NiL, NiL));
267*b30d1939SAndy Fiddaman 		return error_info.errors != 0;
268*b30d1939SAndy Fiddaman 	}
269*b30d1939SAndy Fiddaman 	else if (list)
270*b30d1939SAndy Fiddaman 	{
271*b30d1939SAndy Fiddaman 		if (!(sp = sfopen(NiL, catfile, "r")))
272*b30d1939SAndy Fiddaman 			error(ERROR_SYSTEM|3, "%s: cannot read catalog", catfile);
273*b30d1939SAndy Fiddaman 		if (!(mc = mcopen(sp)))
274*b30d1939SAndy Fiddaman 			error(ERROR_SYSTEM|3, "%s: catalog content error", catfile);
275*b30d1939SAndy Fiddaman 		sfclose(sp);
276*b30d1939SAndy Fiddaman 		if (format)
277*b30d1939SAndy Fiddaman 		{
278*b30d1939SAndy Fiddaman 			for (set = 1; set <= mc->num; set++)
279*b30d1939SAndy Fiddaman 				if (mc->set[set].num)
280*b30d1939SAndy Fiddaman 				{
281*b30d1939SAndy Fiddaman 					sfprintf(sfstdout, "$set %d\n", set);
282*b30d1939SAndy Fiddaman 					for (num = 1; num <= mc->set[set].num; num++)
283*b30d1939SAndy Fiddaman 						if (s = mc->set[set].msg[num])
284*b30d1939SAndy Fiddaman 							sfprintf(sfstdout, "%d \"%s\"\n", num, fmtfmt(s));
285*b30d1939SAndy Fiddaman 				}
286*b30d1939SAndy Fiddaman 		}
287*b30d1939SAndy Fiddaman 		else
288*b30d1939SAndy Fiddaman 		{
289*b30d1939SAndy Fiddaman 			if (*mc->translation)
290*b30d1939SAndy Fiddaman 			{
291*b30d1939SAndy Fiddaman 				ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "$translation ");
292*b30d1939SAndy Fiddaman 				sfprintf(sfstdout, "%s", mc->translation);
293*b30d1939SAndy Fiddaman 				ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "\n");
294*b30d1939SAndy Fiddaman 			}
295*b30d1939SAndy Fiddaman 			ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "$quote \"\n");
296*b30d1939SAndy Fiddaman 			for (set = 1; set <= mc->num; set++)
297*b30d1939SAndy Fiddaman 				if (mc->set[set].num)
298*b30d1939SAndy Fiddaman 				{
299*b30d1939SAndy Fiddaman 					ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "$set %d\n", set);
300*b30d1939SAndy Fiddaman 					for (num = 1; num <= mc->set[set].num; num++)
301*b30d1939SAndy Fiddaman 						if (s = mc->set[set].msg[num])
302*b30d1939SAndy Fiddaman 						{
303*b30d1939SAndy Fiddaman 							ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "%d \"", num);
304*b30d1939SAndy Fiddaman 							while (c = *s++)
305*b30d1939SAndy Fiddaman 							{
306*b30d1939SAndy Fiddaman 								/*INDENT...*/
307*b30d1939SAndy Fiddaman 
308*b30d1939SAndy Fiddaman 			switch (c)
309*b30d1939SAndy Fiddaman 			{
310*b30d1939SAndy Fiddaman 			case 0x22: /* " */
311*b30d1939SAndy Fiddaman 			case 0x5C: /* \ */
312*b30d1939SAndy Fiddaman 				sfputc(sfstdout, 0x5C);
313*b30d1939SAndy Fiddaman 				break;
314*b30d1939SAndy Fiddaman 			case 0x07: /* \a */
315*b30d1939SAndy Fiddaman 				c = 0x61;
316*b30d1939SAndy Fiddaman 				sfputc(sfstdout, 0x5C);
317*b30d1939SAndy Fiddaman 				break;
318*b30d1939SAndy Fiddaman 			case 0x08: /* \b */
319*b30d1939SAndy Fiddaman 				c = 0x62;
320*b30d1939SAndy Fiddaman 				sfputc(sfstdout, 0x5C);
321*b30d1939SAndy Fiddaman 				break;
322*b30d1939SAndy Fiddaman 			case 0x0A: /* \n */
323*b30d1939SAndy Fiddaman 				c = 0x6E;
324*b30d1939SAndy Fiddaman 				sfputc(sfstdout, 0x5C);
325*b30d1939SAndy Fiddaman 				break;
326*b30d1939SAndy Fiddaman 			case 0x0B: /* \v */
327*b30d1939SAndy Fiddaman 				c = 0x76;
328*b30d1939SAndy Fiddaman 				sfputc(sfstdout, 0x5C);
329*b30d1939SAndy Fiddaman 				break;
330*b30d1939SAndy Fiddaman 			case 0x0C: /* \f */
331*b30d1939SAndy Fiddaman 				c = 0x66;
332*b30d1939SAndy Fiddaman 				sfputc(sfstdout, 0x5C);
333*b30d1939SAndy Fiddaman 				break;
334*b30d1939SAndy Fiddaman 			case 0x0D: /* \r */
335*b30d1939SAndy Fiddaman 				c = 0x72;
336*b30d1939SAndy Fiddaman 				sfputc(sfstdout, 0x5C);
337*b30d1939SAndy Fiddaman 				break;
338*b30d1939SAndy Fiddaman 			}
339*b30d1939SAndy Fiddaman 
340*b30d1939SAndy Fiddaman 								/*...UNDENT*/
341*b30d1939SAndy Fiddaman 								sfputc(sfstdout, c);
342*b30d1939SAndy Fiddaman 							}
343*b30d1939SAndy Fiddaman 							ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "\"\n");
344*b30d1939SAndy Fiddaman 						}
345*b30d1939SAndy Fiddaman 				}
346*b30d1939SAndy Fiddaman 		}
347*b30d1939SAndy Fiddaman 		mcclose(mc);
348*b30d1939SAndy Fiddaman 		return error_info.errors != 0;
349*b30d1939SAndy Fiddaman 	}
350*b30d1939SAndy Fiddaman 	else if (!(msgfile = *argv++) || *argv)
351*b30d1939SAndy Fiddaman 		error(3, "exactly one message file must be specified");
352*b30d1939SAndy Fiddaman 
353*b30d1939SAndy Fiddaman 	/*
354*b30d1939SAndy Fiddaman 	 * open the files and handles
355*b30d1939SAndy Fiddaman 	 */
356*b30d1939SAndy Fiddaman 
357*b30d1939SAndy Fiddaman 	if (!(tp = sfstropen()))
358*b30d1939SAndy Fiddaman 		error(ERROR_SYSTEM|3, "out of space [string stream]");
359*b30d1939SAndy Fiddaman 	if (!(mp = sfopen(NiL, msgfile, "r")))
360*b30d1939SAndy Fiddaman 		error(ERROR_SYSTEM|3, "%s: cannot read message file", msgfile);
361*b30d1939SAndy Fiddaman 	sp = sfopen(NiL, catfile, "r");
362*b30d1939SAndy Fiddaman 	if (!(mc = mcopen(sp)))
363*b30d1939SAndy Fiddaman 		error(ERROR_SYSTEM|3, "%s: catalog content error", catfile);
364*b30d1939SAndy Fiddaman 	if (sp)
365*b30d1939SAndy Fiddaman 		sfclose(sp);
366*b30d1939SAndy Fiddaman 	xp = translation(xp, mc->translation);
367*b30d1939SAndy Fiddaman 
368*b30d1939SAndy Fiddaman 	/*
369*b30d1939SAndy Fiddaman 	 * read the message file
370*b30d1939SAndy Fiddaman 	 */
371*b30d1939SAndy Fiddaman 
372*b30d1939SAndy Fiddaman 	q = 0;
373*b30d1939SAndy Fiddaman 	set = 1;
374*b30d1939SAndy Fiddaman 	error_info.file = msgfile;
375*b30d1939SAndy Fiddaman 	while (s = sfgetr(mp, '\n', 1))
376*b30d1939SAndy Fiddaman 	{
377*b30d1939SAndy Fiddaman 		error_info.line++;
378*b30d1939SAndy Fiddaman 		if (!*s)
379*b30d1939SAndy Fiddaman 			continue;
380*b30d1939SAndy Fiddaman 		if (*s == '$')
381*b30d1939SAndy Fiddaman 		{
382*b30d1939SAndy Fiddaman 			if (!*++s || isspace(*s))
383*b30d1939SAndy Fiddaman 				continue;
384*b30d1939SAndy Fiddaman 			for (t = s; *s && !isspace(*s); s++);
385*b30d1939SAndy Fiddaman 			if (*s)
386*b30d1939SAndy Fiddaman 				*s++ = 0;
387*b30d1939SAndy Fiddaman 			if (streq(t, "delset"))
388*b30d1939SAndy Fiddaman 			{
389*b30d1939SAndy Fiddaman 				while (isspace(*s))
390*b30d1939SAndy Fiddaman 					s++;
391*b30d1939SAndy Fiddaman 				num = (int)strtol(s, NiL, 0);
392*b30d1939SAndy Fiddaman 				if (num < mc->num && mc->set[num].num)
393*b30d1939SAndy Fiddaman 					for (i = 1; i <= mc->set[num].num; i++)
394*b30d1939SAndy Fiddaman 						mcput(mc, num, i, NiL);
395*b30d1939SAndy Fiddaman 			}
396*b30d1939SAndy Fiddaman 			else if (streq(t, "quote"))
397*b30d1939SAndy Fiddaman 				q = *s ? *s : 0;
398*b30d1939SAndy Fiddaman 			else if (streq(t, "set"))
399*b30d1939SAndy Fiddaman 			{
400*b30d1939SAndy Fiddaman 				while (isspace(*s))
401*b30d1939SAndy Fiddaman 					s++;
402*b30d1939SAndy Fiddaman 				num = (int)strtol(s, &e, 0);
403*b30d1939SAndy Fiddaman 				if (e != s)
404*b30d1939SAndy Fiddaman 					set = num;
405*b30d1939SAndy Fiddaman 				else
406*b30d1939SAndy Fiddaman 					error(2, "set number expected");
407*b30d1939SAndy Fiddaman 			}
408*b30d1939SAndy Fiddaman 			else if (streq(t, "translation"))
409*b30d1939SAndy Fiddaman 				xp = translation(xp, s);
410*b30d1939SAndy Fiddaman 		}
411*b30d1939SAndy Fiddaman 		else
412*b30d1939SAndy Fiddaman 		{
413*b30d1939SAndy Fiddaman 			t = s + sfvalue(mp);
414*b30d1939SAndy Fiddaman 			num = (int)strtol(s, &e, 0);
415*b30d1939SAndy Fiddaman 			if (e != s)
416*b30d1939SAndy Fiddaman 			{
417*b30d1939SAndy Fiddaman 				s = e;
418*b30d1939SAndy Fiddaman 				if (!*s)
419*b30d1939SAndy Fiddaman 				{
420*b30d1939SAndy Fiddaman 					if (mcput(mc, set, num, NiL))
421*b30d1939SAndy Fiddaman 						error(2, "(%d,%d): cannot delete message", set, num);
422*b30d1939SAndy Fiddaman 				}
423*b30d1939SAndy Fiddaman 				else if (isspace(*s++))
424*b30d1939SAndy Fiddaman 				{
425*b30d1939SAndy Fiddaman 					if (t > (s + 1) && *(t -= 2) == '\\')
426*b30d1939SAndy Fiddaman 					{
427*b30d1939SAndy Fiddaman 						sfwrite(tp, s, t - s);
428*b30d1939SAndy Fiddaman 						while (s = sfgetr(mp, '\n', 0))
429*b30d1939SAndy Fiddaman 						{
430*b30d1939SAndy Fiddaman 							error_info.line++;
431*b30d1939SAndy Fiddaman 							t = s + sfvalue(mp);
432*b30d1939SAndy Fiddaman 							if (t <= (s + 1) || *(t -= 2) != '\\')
433*b30d1939SAndy Fiddaman 								break;
434*b30d1939SAndy Fiddaman 							sfwrite(tp, s, t - s);
435*b30d1939SAndy Fiddaman 						}
436*b30d1939SAndy Fiddaman 						if (!(s = sfstruse(tp)))
437*b30d1939SAndy Fiddaman 							error(ERROR_SYSTEM|3, "out of space");
438*b30d1939SAndy Fiddaman 					}
439*b30d1939SAndy Fiddaman 					if (q)
440*b30d1939SAndy Fiddaman 					{
441*b30d1939SAndy Fiddaman 						if (*s++ != q)
442*b30d1939SAndy Fiddaman 						{
443*b30d1939SAndy Fiddaman 							error(2, "(%d,%d): %c quote expected", set, num, q);
444*b30d1939SAndy Fiddaman 							continue;
445*b30d1939SAndy Fiddaman 						}
446*b30d1939SAndy Fiddaman 						b = t = s;
447*b30d1939SAndy Fiddaman 						while (c = *s++)
448*b30d1939SAndy Fiddaman 						{
449*b30d1939SAndy Fiddaman 							if (c == '\\')
450*b30d1939SAndy Fiddaman 							{
451*b30d1939SAndy Fiddaman 								c = chresc(s - 1, &e);
452*b30d1939SAndy Fiddaman 								s = e;
453*b30d1939SAndy Fiddaman 								if (c)
454*b30d1939SAndy Fiddaman 									*t++ = c;
455*b30d1939SAndy Fiddaman 								else
456*b30d1939SAndy Fiddaman 									error(1, "nul character ignored");
457*b30d1939SAndy Fiddaman 							}
458*b30d1939SAndy Fiddaman 							else if (c == q)
459*b30d1939SAndy Fiddaman 								break;
460*b30d1939SAndy Fiddaman 							else
461*b30d1939SAndy Fiddaman 								*t++ = c;
462*b30d1939SAndy Fiddaman 						}
463*b30d1939SAndy Fiddaman 						if (*s)
464*b30d1939SAndy Fiddaman 						{
465*b30d1939SAndy Fiddaman 							error(2, "(%d,%d): characters after quote not expected", set, num);
466*b30d1939SAndy Fiddaman 							continue;
467*b30d1939SAndy Fiddaman 						}
468*b30d1939SAndy Fiddaman 						*t = 0;
469*b30d1939SAndy Fiddaman 						s = b;
470*b30d1939SAndy Fiddaman 					}
471*b30d1939SAndy Fiddaman 					if (mcput(mc, set, num, s))
472*b30d1939SAndy Fiddaman 						error(2, "(%d,%d): cannot add message", set, num);
473*b30d1939SAndy Fiddaman 				}
474*b30d1939SAndy Fiddaman 				else
475*b30d1939SAndy Fiddaman 					error(2, "message text expected");
476*b30d1939SAndy Fiddaman 			}
477*b30d1939SAndy Fiddaman 			else
478*b30d1939SAndy Fiddaman 				error(2, "message number expected");
479*b30d1939SAndy Fiddaman 		}
480*b30d1939SAndy Fiddaman 	}
481*b30d1939SAndy Fiddaman 	error_info.file = 0;
482*b30d1939SAndy Fiddaman 	error_info.line = 0;
483*b30d1939SAndy Fiddaman 
484*b30d1939SAndy Fiddaman 	/*
485*b30d1939SAndy Fiddaman 	 * fix up the translation record
486*b30d1939SAndy Fiddaman 	 */
487*b30d1939SAndy Fiddaman 
488*b30d1939SAndy Fiddaman 	if (xp)
489*b30d1939SAndy Fiddaman 	{
490*b30d1939SAndy Fiddaman 		t = "";
491*b30d1939SAndy Fiddaman 		for (;;)
492*b30d1939SAndy Fiddaman 		{
493*b30d1939SAndy Fiddaman 			for (bp = 0, px = xp; px; px = px->next)
494*b30d1939SAndy Fiddaman 				if (px->date && (!bp || strcoll(bp->date, px->date) < 0))
495*b30d1939SAndy Fiddaman 					bp = px;
496*b30d1939SAndy Fiddaman 			if (!bp)
497*b30d1939SAndy Fiddaman 				break;
498*b30d1939SAndy Fiddaman 			sfprintf(tp, "%s%s %s", t, bp->name, bp->date);
499*b30d1939SAndy Fiddaman 			t = ", ";
500*b30d1939SAndy Fiddaman 			bp->date = 0;
501*b30d1939SAndy Fiddaman 		}
502*b30d1939SAndy Fiddaman 		if (!(mc->translation = sfstruse(tp)))
503*b30d1939SAndy Fiddaman 			error(ERROR_SYSTEM|3, "out of space");
504*b30d1939SAndy Fiddaman 	}
505*b30d1939SAndy Fiddaman 
506*b30d1939SAndy Fiddaman 	/*
507*b30d1939SAndy Fiddaman 	 * dump the catalog to a local temporary
508*b30d1939SAndy Fiddaman 	 * rename if no errors
509*b30d1939SAndy Fiddaman 	 */
510*b30d1939SAndy Fiddaman 
511*b30d1939SAndy Fiddaman 	if (!(s = pathtemp(NiL, 0, "", error_info.id, NiL)) || !(sp = sfopen(NiL, s, "w")))
512*b30d1939SAndy Fiddaman 		error(ERROR_SYSTEM|3, "%s: cannot write catalog file", catfile);
513*b30d1939SAndy Fiddaman 	if (mcdump(mc, sp) || mcclose(mc) || sfclose(sp))
514*b30d1939SAndy Fiddaman 	{
515*b30d1939SAndy Fiddaman 		remove(s);
516*b30d1939SAndy Fiddaman 		error(ERROR_SYSTEM|3, "%s: temporary catalog file write error", s);
517*b30d1939SAndy Fiddaman 	}
518*b30d1939SAndy Fiddaman 	remove(catfile);
519*b30d1939SAndy Fiddaman 	if (rename(s, catfile))
520*b30d1939SAndy Fiddaman 		error(ERROR_SYSTEM|3, "%s: cannot rename from temporary catalog file %s", catfile, s);
521*b30d1939SAndy Fiddaman 	return error_info.errors != 0;
522*b30d1939SAndy Fiddaman }
523