xref: /onnv-gate/usr/src/cmd/gencat/gencat.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright (c) 1990, 1991, 1994, Sun Microsystems, Inc.
24*0Sstevel@tonic-gate  * All rights reserved.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <nl_types.h>
30*0Sstevel@tonic-gate #include <ctype.h>
31*0Sstevel@tonic-gate #include <errno.h>
32*0Sstevel@tonic-gate #include <fcntl.h>
33*0Sstevel@tonic-gate #include <limits.h>
34*0Sstevel@tonic-gate #include <memory.h>
35*0Sstevel@tonic-gate #include <stdio.h>
36*0Sstevel@tonic-gate #include <stdlib.h>
37*0Sstevel@tonic-gate #include <string.h>
38*0Sstevel@tonic-gate #include <unistd.h>
39*0Sstevel@tonic-gate #include <locale.h>
40*0Sstevel@tonic-gate #include <libintl.h>
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate #ifndef NL_MSGMAX
43*0Sstevel@tonic-gate #define	NL_MSGMAX 32767
44*0Sstevel@tonic-gate #endif
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate #ifndef NL_SETMAX
47*0Sstevel@tonic-gate #define	NL_SETMAX 255
48*0Sstevel@tonic-gate #endif
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate #ifndef NL_TEXTMAX
51*0Sstevel@tonic-gate #define	NL_TEXTMAX 2048
52*0Sstevel@tonic-gate #endif
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate #define	BS		'\b'
55*0Sstevel@tonic-gate #define	CR		'\r'
56*0Sstevel@tonic-gate #define	DOLLAR	'$'
57*0Sstevel@tonic-gate #define	FF		'\f'
58*0Sstevel@tonic-gate #define	NEWLINE	'\n'
59*0Sstevel@tonic-gate #define	NUL		'\000'
60*0Sstevel@tonic-gate #define	REVERSE_SOLIDUS '\\'
61*0Sstevel@tonic-gate #define	SPACE	' '
62*0Sstevel@tonic-gate #define	TAB		'\t'
63*0Sstevel@tonic-gate #define	VTAB	'\v'
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate #define	FPRINTF			(void) fprintf
66*0Sstevel@tonic-gate #define	FREE(x)			free((char *)(x))
67*0Sstevel@tonic-gate #define	MALLOC(n)		malloc((unsigned)(n))
68*0Sstevel@tonic-gate #define	MEMCPY(dst, src, n) \
69*0Sstevel@tonic-gate 		(void) memcpy((char *)(dst), (char *)(src), (int)(n))
70*0Sstevel@tonic-gate #define	MEMSET(s, c, n)	(void) memset((char *)(s), (int)(c), (int)(n));
71*0Sstevel@tonic-gate #define	MSG(n)			gettext(MSG ## n)
72*0Sstevel@tonic-gate #define	READ(fd, p, n)	read((int)(fd), (char *)(p), (unsigned)(n))
73*0Sstevel@tonic-gate #define	REALLOC(x, n)	realloc((char *)(x), (unsigned)(n))
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate /* double linked list */
76*0Sstevel@tonic-gate struct cat_set {
77*0Sstevel@tonic-gate 	struct cat_set	*prev;
78*0Sstevel@tonic-gate 	struct cat_set	*next;
79*0Sstevel@tonic-gate 	int				set_no;
80*0Sstevel@tonic-gate 	struct cat_msg	*first_msg;
81*0Sstevel@tonic-gate };
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate /* double linked list */
84*0Sstevel@tonic-gate struct cat_msg {
85*0Sstevel@tonic-gate 	struct cat_msg	*prev;
86*0Sstevel@tonic-gate 	struct cat_msg	*next;
87*0Sstevel@tonic-gate 	int				msg_no;
88*0Sstevel@tonic-gate 	int				msg_len;
89*0Sstevel@tonic-gate 	char			s[1];
90*0Sstevel@tonic-gate };
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate int		catfd;		/* File descriptor of catalog file */
93*0Sstevel@tonic-gate char	*catfname;	/* Catalog file name */
94*0Sstevel@tonic-gate char	*msgfname;	/* message source file name */
95*0Sstevel@tonic-gate int		ateof;		/* boolean indicating END-OF-FILE */
96*0Sstevel@tonic-gate int		lineno;		/* the line number of message source file */
97*0Sstevel@tonic-gate int		quoting;	/* boolean indicating quotes is used */
98*0Sstevel@tonic-gate int		quote;		/* the current quote */
99*0Sstevel@tonic-gate int		text_len;	/* message text length */
100*0Sstevel@tonic-gate int		text_size;	/* the size of allocated text memory */
101*0Sstevel@tonic-gate char	*text;		/* messsge text */
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate struct _cat_hdr	hdr;
104*0Sstevel@tonic-gate int				current_set_no;	/* the current set number */
105*0Sstevel@tonic-gate struct cat_set	*first_set;	/* the pointer to the first set */
106*0Sstevel@tonic-gate struct cat_set	*current_set;	/* the pointer to the current set */
107*0Sstevel@tonic-gate struct cat_msg	*current_msg;	/* the pointer to the first message */
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate /* Error message */
111*0Sstevel@tonic-gate /* 0 */
112*0Sstevel@tonic-gate #define	MSG0	""
113*0Sstevel@tonic-gate /* 1 */
114*0Sstevel@tonic-gate #define	MSG1	"usage: gencat catfile msgfile ...\n"
115*0Sstevel@tonic-gate /* 2 */
116*0Sstevel@tonic-gate #define	MSG2	"gencat: cannot open \"%s\"\n"
117*0Sstevel@tonic-gate /* 3 */
118*0Sstevel@tonic-gate #define	MSG3	"gencat: read error on \"%s\"\n"
119*0Sstevel@tonic-gate /* 4 */
120*0Sstevel@tonic-gate #define	MSG4	"gencat: bad magic number (%#lx)\n"
121*0Sstevel@tonic-gate /* 5 */
122*0Sstevel@tonic-gate #define	MSG5	"gencat: corrupt catalogue file \"%s\"\n"
123*0Sstevel@tonic-gate /* 6 */
124*0Sstevel@tonic-gate #define	MSG6	"gencat: memory limit exceeded\n"
125*0Sstevel@tonic-gate /* 7 */
126*0Sstevel@tonic-gate #define	MSG7	"gencat: seek error on \"%s\"\n"
127*0Sstevel@tonic-gate /* 8 */
128*0Sstevel@tonic-gate #define	MSG8	"gencat: write error on \"%s\"\n"
129*0Sstevel@tonic-gate /* 9 */
130*0Sstevel@tonic-gate #define	MSG9	"gencat: \"%s\", line %d: number too large (%s)\n"
131*0Sstevel@tonic-gate /* 10 */
132*0Sstevel@tonic-gate #define	MSG10	"gencat: \"%s\", line %d: 0 is not a permissible " \
133*0Sstevel@tonic-gate 				"message number\n"
134*0Sstevel@tonic-gate /* 11 */
135*0Sstevel@tonic-gate #define	MSG11	"gencat: \"%s\", line %d: warning, message number %d " \
136*0Sstevel@tonic-gate 				"exceeds limit (%d)\n"
137*0Sstevel@tonic-gate /* 12 */
138*0Sstevel@tonic-gate #define	MSG12	"gencat: \"%s\", line %d: missing quote (%wc)\n"
139*0Sstevel@tonic-gate /* 13 */
140*0Sstevel@tonic-gate #define	MSG13	"gencat: \"%s\", line %d: character value too large ('\\%o')\n"
141*0Sstevel@tonic-gate /* 14 */
142*0Sstevel@tonic-gate #define	MSG14	"gencat: \"%s\", line %d: extra characters following " \
143*0Sstevel@tonic-gate 				"message text\n"
144*0Sstevel@tonic-gate /* 15 */
145*0Sstevel@tonic-gate #define	MSG15	"gencat: \"%s\", line %d: extra characters following " \
146*0Sstevel@tonic-gate 				"$quote directive\n"
147*0Sstevel@tonic-gate /* 16 */
148*0Sstevel@tonic-gate #define	MSG16	"gencat: \"%s\", line %d: no set number specified in " \
149*0Sstevel@tonic-gate 				"$set directive\n"
150*0Sstevel@tonic-gate /* 17 */
151*0Sstevel@tonic-gate #define	MSG17	"getcat: \"%s\", line %d: 0 is not a permissible set number\n"
152*0Sstevel@tonic-gate /* 18 */
153*0Sstevel@tonic-gate #define	MSG18	"gencat: \"%s\", line %d: warning, set number %d " \
154*0Sstevel@tonic-gate 				"exceeds limit (%d)\n"
155*0Sstevel@tonic-gate /* 19 */
156*0Sstevel@tonic-gate #define	MSG19	"gencat: \"%s\", line %d: unknown directive %s\n"
157*0Sstevel@tonic-gate /* 20 */
158*0Sstevel@tonic-gate #define	MSG20	"gencat: \"%s\", line %d: no set number specified in " \
159*0Sstevel@tonic-gate 				"$delset directive\n"
160*0Sstevel@tonic-gate /* 21 */
161*0Sstevel@tonic-gate #define	MSG21	"stdin"
162*0Sstevel@tonic-gate /* 22 */
163*0Sstevel@tonic-gate #define	MSG22	"gencat: \"%s\", line %d: number or $ expected\n"
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate struct cat_set *
new_set(n)166*0Sstevel@tonic-gate new_set(n)
167*0Sstevel@tonic-gate 	int		n;
168*0Sstevel@tonic-gate {
169*0Sstevel@tonic-gate 	struct cat_set *p;
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 	p = (struct cat_set *) MALLOC(sizeof (struct cat_set));
172*0Sstevel@tonic-gate 	if (p == NULL) {
173*0Sstevel@tonic-gate 		FPRINTF(stderr, MSG(6));
174*0Sstevel@tonic-gate 		exit(1);
175*0Sstevel@tonic-gate 	}
176*0Sstevel@tonic-gate 	p->next = NULL;
177*0Sstevel@tonic-gate 	p->prev = NULL;
178*0Sstevel@tonic-gate 	p->set_no = n;
179*0Sstevel@tonic-gate 	p->first_msg = NULL;
180*0Sstevel@tonic-gate 	return (p);
181*0Sstevel@tonic-gate }
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate void
find_set(no)184*0Sstevel@tonic-gate find_set(no)
185*0Sstevel@tonic-gate 	int		no;
186*0Sstevel@tonic-gate {
187*0Sstevel@tonic-gate 	struct cat_set	*prev, *next;
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	if (current_set && current_set->set_no == no) {
190*0Sstevel@tonic-gate 		return;
191*0Sstevel@tonic-gate 	}
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	current_set_no = no;
194*0Sstevel@tonic-gate 	current_msg = NULL;
195*0Sstevel@tonic-gate 	/* if no set exists, create a new set */
196*0Sstevel@tonic-gate 	if (current_set == NULL) {
197*0Sstevel@tonic-gate 		if (first_set == NULL) {
198*0Sstevel@tonic-gate 			current_set = first_set = new_set(no);
199*0Sstevel@tonic-gate 			return;
200*0Sstevel@tonic-gate 		}
201*0Sstevel@tonic-gate 		current_set = first_set;
202*0Sstevel@tonic-gate 		if (current_set->set_no == no)
203*0Sstevel@tonic-gate 			return;
204*0Sstevel@tonic-gate 	}
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	if (current_set->set_no > no) {
207*0Sstevel@tonic-gate 		if (first_set->set_no > no) {
208*0Sstevel@tonic-gate 			/* prepend a new set */
209*0Sstevel@tonic-gate 			current_set = new_set(no);
210*0Sstevel@tonic-gate 			current_set->next = first_set;
211*0Sstevel@tonic-gate 			first_set->prev = current_set;
212*0Sstevel@tonic-gate 			first_set = current_set;
213*0Sstevel@tonic-gate 			return;
214*0Sstevel@tonic-gate 		}
215*0Sstevel@tonic-gate 		current_set = first_set;
216*0Sstevel@tonic-gate 		if (current_set->set_no == no)
217*0Sstevel@tonic-gate 			return;
218*0Sstevel@tonic-gate 	}
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	/* search for the set number 'no' */
221*0Sstevel@tonic-gate 	while (current_set->next && current_set->next->set_no < no)
222*0Sstevel@tonic-gate 		current_set = current_set->next;
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	if (current_set->next && current_set->next->set_no == no) {
225*0Sstevel@tonic-gate 		/* set number 'no' found */
226*0Sstevel@tonic-gate 		current_set = current_set->next;
227*0Sstevel@tonic-gate 		return;
228*0Sstevel@tonic-gate 	}
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	/* If set number is not found, insert a new set in the middle */
231*0Sstevel@tonic-gate 	prev = current_set;
232*0Sstevel@tonic-gate 	next = current_set->next;
233*0Sstevel@tonic-gate 	current_set = new_set(no);
234*0Sstevel@tonic-gate 	current_set->prev = prev;
235*0Sstevel@tonic-gate 	current_set->next = next;
236*0Sstevel@tonic-gate 	if (prev)
237*0Sstevel@tonic-gate 		prev->next = current_set;
238*0Sstevel@tonic-gate 	else
239*0Sstevel@tonic-gate 		first_set = current_set;
240*0Sstevel@tonic-gate 	if (next)
241*0Sstevel@tonic-gate 		next->prev = current_set;
242*0Sstevel@tonic-gate }
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate void
delete_set(no)245*0Sstevel@tonic-gate delete_set(no)
246*0Sstevel@tonic-gate 	int		no;
247*0Sstevel@tonic-gate {
248*0Sstevel@tonic-gate 	struct cat_set	*prev, *next, *setp;
249*0Sstevel@tonic-gate 	struct cat_msg	*p, *q;
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	for (setp = first_set; setp && setp->set_no < no; setp = setp->next)
252*0Sstevel@tonic-gate 		continue;
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	if (setp == NULL || setp->set_no != no)	/* set not found */
255*0Sstevel@tonic-gate 		return;
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 	if (setp == current_set) {
258*0Sstevel@tonic-gate 		current_set = NULL;
259*0Sstevel@tonic-gate 		current_msg = NULL;
260*0Sstevel@tonic-gate 	}
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	/* free all messages in the set */
263*0Sstevel@tonic-gate 	for (p = setp->first_msg; p; p) {
264*0Sstevel@tonic-gate 		q = p->next;
265*0Sstevel@tonic-gate 		FREE(p);
266*0Sstevel@tonic-gate 		p = q;
267*0Sstevel@tonic-gate 	}
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 	/* do the link operation to delete the set */
270*0Sstevel@tonic-gate 	prev = setp->prev;
271*0Sstevel@tonic-gate 	next = setp->next;
272*0Sstevel@tonic-gate 	FREE(setp);
273*0Sstevel@tonic-gate 	if (prev)
274*0Sstevel@tonic-gate 		prev->next = next;
275*0Sstevel@tonic-gate 	else
276*0Sstevel@tonic-gate 		first_set = next;
277*0Sstevel@tonic-gate 	if (next)
278*0Sstevel@tonic-gate 		next->prev = prev;
279*0Sstevel@tonic-gate }
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate struct cat_msg *
new_msg(no,len,text)282*0Sstevel@tonic-gate new_msg(no, len, text)
283*0Sstevel@tonic-gate 	int		no;
284*0Sstevel@tonic-gate 	int		len;
285*0Sstevel@tonic-gate 	char	*text;
286*0Sstevel@tonic-gate {
287*0Sstevel@tonic-gate 	struct cat_msg	*p;
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 	p = (struct cat_msg *) MALLOC(sizeof (struct cat_msg) + len);
290*0Sstevel@tonic-gate 	if (p == NULL) {
291*0Sstevel@tonic-gate 		FPRINTF(stderr, MSG(6));
292*0Sstevel@tonic-gate 		exit(1);
293*0Sstevel@tonic-gate 	}
294*0Sstevel@tonic-gate 	p->next = NULL;
295*0Sstevel@tonic-gate 	p->prev = NULL;
296*0Sstevel@tonic-gate 	p->msg_no = no;
297*0Sstevel@tonic-gate 	p->msg_len = len;
298*0Sstevel@tonic-gate 	MEMCPY(p->s, text, len);
299*0Sstevel@tonic-gate 	return (p);
300*0Sstevel@tonic-gate }
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate void
insert_msg(no,len,text)304*0Sstevel@tonic-gate insert_msg(no, len, text)
305*0Sstevel@tonic-gate 	int		no;
306*0Sstevel@tonic-gate 	int		len;
307*0Sstevel@tonic-gate 	char	*text;
308*0Sstevel@tonic-gate {
309*0Sstevel@tonic-gate 	struct cat_msg	*prev, *next;
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 	if (current_msg == NULL) {
312*0Sstevel@tonic-gate 		if (current_set == NULL)
313*0Sstevel@tonic-gate 			find_set(current_set_no);
314*0Sstevel@tonic-gate 		current_msg = current_set->first_msg;
315*0Sstevel@tonic-gate 		if (current_msg == NULL) {
316*0Sstevel@tonic-gate 			current_msg = new_msg(no, len, text);
317*0Sstevel@tonic-gate 			current_set->first_msg = current_msg;
318*0Sstevel@tonic-gate 			return;
319*0Sstevel@tonic-gate 		}
320*0Sstevel@tonic-gate 	}
321*0Sstevel@tonic-gate 	if (current_msg->msg_no >= no) {
322*0Sstevel@tonic-gate 		current_msg = current_set->first_msg;
323*0Sstevel@tonic-gate 		if (current_msg->msg_no > no) {
324*0Sstevel@tonic-gate 			current_msg = new_msg(no, len, text);
325*0Sstevel@tonic-gate 			current_msg->next = current_set->first_msg;
326*0Sstevel@tonic-gate 			current_set->first_msg->prev = current_msg;
327*0Sstevel@tonic-gate 			current_set->first_msg = current_msg;
328*0Sstevel@tonic-gate 			return;
329*0Sstevel@tonic-gate 		}
330*0Sstevel@tonic-gate 		if (current_msg->msg_no == no) {
331*0Sstevel@tonic-gate 			current_msg = new_msg(no, len, text);
332*0Sstevel@tonic-gate 			current_msg->next = current_set->first_msg->next;
333*0Sstevel@tonic-gate 			if (current_set->first_msg->next)
334*0Sstevel@tonic-gate 				current_set->first_msg->next->prev =
335*0Sstevel@tonic-gate 					current_msg;
336*0Sstevel@tonic-gate 			FREE(current_set->first_msg);
337*0Sstevel@tonic-gate 			current_set->first_msg = current_msg;
338*0Sstevel@tonic-gate 			return;
339*0Sstevel@tonic-gate 		}
340*0Sstevel@tonic-gate 	}
341*0Sstevel@tonic-gate 	while (current_msg->next && current_msg->next->msg_no < no)
342*0Sstevel@tonic-gate 		current_msg = current_msg->next;
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate 	/*
345*0Sstevel@tonic-gate 	 * if the same msg number is found, then delte the message and
346*0Sstevel@tonic-gate 	 * insert the new message. This is same as replacing message.
347*0Sstevel@tonic-gate 	 */
348*0Sstevel@tonic-gate 	if (current_msg->next && current_msg->next->msg_no == no) {
349*0Sstevel@tonic-gate 		current_msg = current_msg->next;
350*0Sstevel@tonic-gate 		prev = current_msg->prev;
351*0Sstevel@tonic-gate 		next = current_msg->next;
352*0Sstevel@tonic-gate 		FREE(current_msg);
353*0Sstevel@tonic-gate 	} else {
354*0Sstevel@tonic-gate 		prev = current_msg;
355*0Sstevel@tonic-gate 		next = current_msg->next;
356*0Sstevel@tonic-gate 	}
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 	current_msg = new_msg(no, len, text);
359*0Sstevel@tonic-gate 	current_msg->prev = prev;
360*0Sstevel@tonic-gate 	current_msg->next = next;
361*0Sstevel@tonic-gate 	if (prev)
362*0Sstevel@tonic-gate 		prev->next = current_msg;
363*0Sstevel@tonic-gate 	else
364*0Sstevel@tonic-gate 		current_set->first_msg = current_msg;
365*0Sstevel@tonic-gate 	if (next)
366*0Sstevel@tonic-gate 		next->prev = current_msg;
367*0Sstevel@tonic-gate }
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate void
delete_msg(no)370*0Sstevel@tonic-gate delete_msg(no)
371*0Sstevel@tonic-gate 	int		no;
372*0Sstevel@tonic-gate {
373*0Sstevel@tonic-gate 	struct cat_set	*p = current_set;
374*0Sstevel@tonic-gate 	struct cat_msg	*prev, *next;
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 	if (current_msg == NULL) {
377*0Sstevel@tonic-gate 		if (current_set == NULL)
378*0Sstevel@tonic-gate 			for (p = first_set; p && p->set_no < current_set_no;
379*0Sstevel@tonic-gate 							p = p->next)
380*0Sstevel@tonic-gate 				continue;
381*0Sstevel@tonic-gate 		if (p == NULL || p->set_no != current_set_no)
382*0Sstevel@tonic-gate 			return;
383*0Sstevel@tonic-gate 		current_set = p;
384*0Sstevel@tonic-gate 		current_msg = current_set->first_msg;
385*0Sstevel@tonic-gate 		if (current_msg == NULL)
386*0Sstevel@tonic-gate 			return;
387*0Sstevel@tonic-gate 	}
388*0Sstevel@tonic-gate 	if (current_msg->msg_no > no)
389*0Sstevel@tonic-gate 		current_msg = current_set->first_msg;
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 	while (current_msg && current_msg->msg_no != no)
392*0Sstevel@tonic-gate 		current_msg = current_msg->next;
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 	if (current_msg && current_msg->msg_no == no) {
395*0Sstevel@tonic-gate 		prev = current_msg->prev;
396*0Sstevel@tonic-gate 		next = current_msg->next;
397*0Sstevel@tonic-gate 		FREE(current_msg);
398*0Sstevel@tonic-gate 		if (prev) {
399*0Sstevel@tonic-gate 			current_msg = prev;
400*0Sstevel@tonic-gate 			prev->next = next;
401*0Sstevel@tonic-gate 		} else {
402*0Sstevel@tonic-gate 			current_set->first_msg = next;
403*0Sstevel@tonic-gate 			current_msg = next;
404*0Sstevel@tonic-gate 		}
405*0Sstevel@tonic-gate 		if (next)
406*0Sstevel@tonic-gate 			next->prev = prev;
407*0Sstevel@tonic-gate 	}
408*0Sstevel@tonic-gate }
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate int
read_block(fd,p,n,pathname)411*0Sstevel@tonic-gate read_block(fd, p, n, pathname)
412*0Sstevel@tonic-gate 	int		fd;
413*0Sstevel@tonic-gate 	char	*p;
414*0Sstevel@tonic-gate 	int		n;
415*0Sstevel@tonic-gate 	char	*pathname;
416*0Sstevel@tonic-gate {
417*0Sstevel@tonic-gate 	int		nbytes, bytes_read;
418*0Sstevel@tonic-gate 
419*0Sstevel@tonic-gate 	if (n == 0)
420*0Sstevel@tonic-gate 		return (0);
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 	nbytes = 0;
423*0Sstevel@tonic-gate 	while (nbytes < n) {
424*0Sstevel@tonic-gate 		bytes_read = READ(fd, p + nbytes, n - nbytes);
425*0Sstevel@tonic-gate 		if (bytes_read < 0) {
426*0Sstevel@tonic-gate 			if (errno != EINTR) {
427*0Sstevel@tonic-gate 				FPRINTF(stderr, MSG(3), pathname);
428*0Sstevel@tonic-gate 				perror("");
429*0Sstevel@tonic-gate 				exit(1);
430*0Sstevel@tonic-gate 			}
431*0Sstevel@tonic-gate 		} else if (bytes_read == 0)
432*0Sstevel@tonic-gate 			break;
433*0Sstevel@tonic-gate 		else
434*0Sstevel@tonic-gate 			nbytes += bytes_read;
435*0Sstevel@tonic-gate 	}
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	return (nbytes);
438*0Sstevel@tonic-gate }
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate /*
441*0Sstevel@tonic-gate  * Check if catalog file read is valid
442*0Sstevel@tonic-gate  *
443*0Sstevel@tonic-gate  */
444*0Sstevel@tonic-gate int
cat_ok(cat)445*0Sstevel@tonic-gate cat_ok(cat)
446*0Sstevel@tonic-gate 	char	*cat;
447*0Sstevel@tonic-gate {
448*0Sstevel@tonic-gate 	int		i, j;
449*0Sstevel@tonic-gate 	int		nmsgs;
450*0Sstevel@tonic-gate 	int		msg_no;
451*0Sstevel@tonic-gate 	struct	_cat_msg_hdr	*msg;
452*0Sstevel@tonic-gate 	int		set_no;
453*0Sstevel@tonic-gate 	int		first_msg_hdr;
454*0Sstevel@tonic-gate 	struct	_cat_set_hdr	*set;
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 	set = (struct _cat_set_hdr *) cat;
457*0Sstevel@tonic-gate 	set_no = 0;
458*0Sstevel@tonic-gate 	for (i = 0; i < hdr.__nsets; ++set, ++i) {
459*0Sstevel@tonic-gate 		if (set->__set_no < set_no)
460*0Sstevel@tonic-gate 			return (0);
461*0Sstevel@tonic-gate 		set_no = set->__set_no;
462*0Sstevel@tonic-gate 		nmsgs = set->__nmsgs;
463*0Sstevel@tonic-gate 		if (nmsgs < 0)
464*0Sstevel@tonic-gate 			return (0);
465*0Sstevel@tonic-gate 		if (nmsgs == 0)
466*0Sstevel@tonic-gate 			continue;
467*0Sstevel@tonic-gate 		first_msg_hdr = set->__first_msg_hdr;
468*0Sstevel@tonic-gate 		if (first_msg_hdr < 0)
469*0Sstevel@tonic-gate 			return (0);
470*0Sstevel@tonic-gate 		if (hdr.__msg_hdr_offset + (first_msg_hdr + nmsgs) *
471*0Sstevel@tonic-gate 					_CAT_MSG_HDR_SIZE > hdr.__mem)
472*0Sstevel@tonic-gate 			return (0);
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 		msg = (struct _cat_msg_hdr *) (cat + hdr.__msg_hdr_offset) +
475*0Sstevel@tonic-gate 						first_msg_hdr;
476*0Sstevel@tonic-gate 		msg_no = 0;
477*0Sstevel@tonic-gate 		for (j = 0; j < nmsgs; ++msg, ++j) {
478*0Sstevel@tonic-gate 			if (msg->__msg_no < msg_no)
479*0Sstevel@tonic-gate 				return (0);
480*0Sstevel@tonic-gate 			msg_no = msg->__msg_no;
481*0Sstevel@tonic-gate 			if (msg->__msg_offset < 0)
482*0Sstevel@tonic-gate 				return (0);
483*0Sstevel@tonic-gate 			if (hdr.__msg_text_offset + msg->__msg_offset +
484*0Sstevel@tonic-gate 						msg->__msg_len > hdr.__mem)
485*0Sstevel@tonic-gate 				return (0);
486*0Sstevel@tonic-gate 		}
487*0Sstevel@tonic-gate 	}
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 	return (1);
490*0Sstevel@tonic-gate }
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate /*
493*0Sstevel@tonic-gate  * convert a chunk of catalog file into double linked list format
494*0Sstevel@tonic-gate  */
495*0Sstevel@tonic-gate void
initcat(cat)496*0Sstevel@tonic-gate initcat(cat)
497*0Sstevel@tonic-gate 	char	*cat;
498*0Sstevel@tonic-gate {
499*0Sstevel@tonic-gate 	int		i, j;
500*0Sstevel@tonic-gate 	int		nmsgs;
501*0Sstevel@tonic-gate 	struct	_cat_set_hdr	*set;
502*0Sstevel@tonic-gate 	struct	_cat_msg_hdr	*msg;
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 	set = (struct _cat_set_hdr *) cat;
505*0Sstevel@tonic-gate 	for (i = 0; i < hdr.__nsets; ++set, ++i) {
506*0Sstevel@tonic-gate 		nmsgs = set->__nmsgs;
507*0Sstevel@tonic-gate 		if (nmsgs == 0)
508*0Sstevel@tonic-gate 			continue;
509*0Sstevel@tonic-gate 		find_set(set->__set_no);
510*0Sstevel@tonic-gate 		msg = (struct _cat_msg_hdr *) (cat + hdr.__msg_hdr_offset)
511*0Sstevel@tonic-gate 			+ set->__first_msg_hdr;
512*0Sstevel@tonic-gate 		current_msg = current_set->first_msg;
513*0Sstevel@tonic-gate 		for (j = 0; j < nmsgs; ++msg, ++j) {
514*0Sstevel@tonic-gate 			insert_msg(msg->__msg_no, msg->__msg_len,
515*0Sstevel@tonic-gate 			    cat + hdr.__msg_text_offset + msg->__msg_offset);
516*0Sstevel@tonic-gate 		}
517*0Sstevel@tonic-gate 	}
518*0Sstevel@tonic-gate }
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate /*
521*0Sstevel@tonic-gate  * read a catalog file in a chunk and convert it to double linked list.
522*0Sstevel@tonic-gate  */
523*0Sstevel@tonic-gate void
readcat(fd,pathname)524*0Sstevel@tonic-gate readcat(fd, pathname)
525*0Sstevel@tonic-gate 	int		fd;
526*0Sstevel@tonic-gate 	char	*pathname;
527*0Sstevel@tonic-gate {
528*0Sstevel@tonic-gate 	int		i;
529*0Sstevel@tonic-gate 	char	*cat;
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate 	i = read_block(fd, (char *) &hdr, _CAT_HDR_SIZE, pathname);
532*0Sstevel@tonic-gate 	if (i == 0)
533*0Sstevel@tonic-gate 		return;
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate 	if (i >= 4 && hdr.__hdr_magic != _CAT_MAGIC) {
536*0Sstevel@tonic-gate 		FPRINTF(stderr, MSG(4), hdr.__hdr_magic);
537*0Sstevel@tonic-gate 		exit(1);
538*0Sstevel@tonic-gate 	}
539*0Sstevel@tonic-gate 	if (i < _CAT_HDR_SIZE || hdr.__nsets < 0) {
540*0Sstevel@tonic-gate 		FPRINTF(stderr, MSG(5), pathname);
541*0Sstevel@tonic-gate 		exit(1);
542*0Sstevel@tonic-gate 	}
543*0Sstevel@tonic-gate 	if (hdr.__nsets == 0)
544*0Sstevel@tonic-gate 		return;
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 	if (hdr.__mem < 0 ||
547*0Sstevel@tonic-gate 	    hdr.__msg_hdr_offset < 0 ||
548*0Sstevel@tonic-gate 	    hdr.__msg_text_offset < 0 ||
549*0Sstevel@tonic-gate 	    hdr.__mem < hdr.__nsets * _CAT_SET_HDR_SIZE ||
550*0Sstevel@tonic-gate 	    hdr.__mem < hdr.__msg_hdr_offset ||
551*0Sstevel@tonic-gate 	    hdr.__mem < hdr.__msg_text_offset) {
552*0Sstevel@tonic-gate 		FPRINTF(stderr, MSG(5), pathname);
553*0Sstevel@tonic-gate 		exit(1);
554*0Sstevel@tonic-gate 	}
555*0Sstevel@tonic-gate 	cat = MALLOC(hdr.__mem);
556*0Sstevel@tonic-gate 	if (cat == NULL) {
557*0Sstevel@tonic-gate 		FPRINTF(stderr, MSG(6));
558*0Sstevel@tonic-gate 		exit(1);
559*0Sstevel@tonic-gate 	}
560*0Sstevel@tonic-gate 	i = read_block(fd, cat, hdr.__mem, pathname);
561*0Sstevel@tonic-gate 	if (i < hdr.__mem || !cat_ok(cat)) {
562*0Sstevel@tonic-gate 		FPRINTF(stderr, MSG(5), pathname);
563*0Sstevel@tonic-gate 		exit(1);
564*0Sstevel@tonic-gate 	}
565*0Sstevel@tonic-gate 	initcat(cat);
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 	FREE(cat);
568*0Sstevel@tonic-gate }
569*0Sstevel@tonic-gate 
570*0Sstevel@tonic-gate /*
571*0Sstevel@tonic-gate  * Extend the memory in 1000 byte chunks whenever runs out of text space.
572*0Sstevel@tonic-gate  */
573*0Sstevel@tonic-gate void
extend_text()574*0Sstevel@tonic-gate extend_text()
575*0Sstevel@tonic-gate {
576*0Sstevel@tonic-gate 	text_size += 1000;
577*0Sstevel@tonic-gate 	if (text)
578*0Sstevel@tonic-gate 		text = REALLOC(text, text_size);
579*0Sstevel@tonic-gate 	else
580*0Sstevel@tonic-gate 		text = MALLOC(text_size);
581*0Sstevel@tonic-gate 	if (text == NULL) {
582*0Sstevel@tonic-gate 		FPRINTF(stderr, MSG(6));
583*0Sstevel@tonic-gate 		exit(1);
584*0Sstevel@tonic-gate 	}
585*0Sstevel@tonic-gate }
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate int
get_number(fp,c)588*0Sstevel@tonic-gate get_number(fp, c)
589*0Sstevel@tonic-gate 	FILE	*fp;
590*0Sstevel@tonic-gate 	int		c;
591*0Sstevel@tonic-gate {
592*0Sstevel@tonic-gate 	int		i, n;
593*0Sstevel@tonic-gate 	char	*s, *t;
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 	i = 0;
596*0Sstevel@tonic-gate 	do {
597*0Sstevel@tonic-gate 		while (i >= text_size)
598*0Sstevel@tonic-gate 			extend_text();
599*0Sstevel@tonic-gate 		text[i] = c;
600*0Sstevel@tonic-gate 		++i;
601*0Sstevel@tonic-gate 		c = getc(fp);
602*0Sstevel@tonic-gate 	}
603*0Sstevel@tonic-gate 	while (isdigit(c));
604*0Sstevel@tonic-gate 	(void) ungetc(c, fp);
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 	while (i >= text_size)
607*0Sstevel@tonic-gate 		extend_text();
608*0Sstevel@tonic-gate 	text[i] = NUL;
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 	for (s = text; *s == '0'; ++s)
611*0Sstevel@tonic-gate 		continue;
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate 	n = 0;
614*0Sstevel@tonic-gate 	for (t = s; isdigit(*t); ++t) {
615*0Sstevel@tonic-gate 		if (n > INT_MAX / 10 ||
616*0Sstevel@tonic-gate 			(n == INT_MAX / 10 && *t > '0' + INT_MAX % 10)) {
617*0Sstevel@tonic-gate 			FPRINTF(stderr, MSG(9), msgfname, lineno, s);
618*0Sstevel@tonic-gate 			exit(1);
619*0Sstevel@tonic-gate 		}
620*0Sstevel@tonic-gate 		n = 10 * n + (*t - '0');
621*0Sstevel@tonic-gate 	}
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate 	return (n);
624*0Sstevel@tonic-gate }
625*0Sstevel@tonic-gate 
626*0Sstevel@tonic-gate void
get_text(fp)627*0Sstevel@tonic-gate get_text(fp)
628*0Sstevel@tonic-gate 	FILE	*fp;
629*0Sstevel@tonic-gate {
630*0Sstevel@tonic-gate 	int		c;
631*0Sstevel@tonic-gate 	int		n;
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	text_len = 0;
634*0Sstevel@tonic-gate 	c = fgetwc(fp);
635*0Sstevel@tonic-gate 	if (quoting && c == quote) {	/* quote is used */
636*0Sstevel@tonic-gate 		c = fgetwc(fp);
637*0Sstevel@tonic-gate 		while (c != quote) {
638*0Sstevel@tonic-gate 			if (c == NEWLINE || c == EOF) {
639*0Sstevel@tonic-gate 				FPRINTF(stderr, MSG(12), msgfname, lineno,
640*0Sstevel@tonic-gate 								quote);
641*0Sstevel@tonic-gate 				exit(1);
642*0Sstevel@tonic-gate 			}
643*0Sstevel@tonic-gate 			if (c == REVERSE_SOLIDUS) {
644*0Sstevel@tonic-gate 				c = fgetwc(fp);
645*0Sstevel@tonic-gate 				switch (c) {
646*0Sstevel@tonic-gate 				case EOF:
647*0Sstevel@tonic-gate 					FPRINTF(stderr, MSG(12), msgfname,
648*0Sstevel@tonic-gate 						lineno, quote);
649*0Sstevel@tonic-gate 					exit(1);
650*0Sstevel@tonic-gate 					break;
651*0Sstevel@tonic-gate 				case NEWLINE:
652*0Sstevel@tonic-gate 					++lineno;
653*0Sstevel@tonic-gate 					c = fgetwc(fp);
654*0Sstevel@tonic-gate 					continue;
655*0Sstevel@tonic-gate 					/* NOTREACHED */
656*0Sstevel@tonic-gate 					break;
657*0Sstevel@tonic-gate 				case '0':
658*0Sstevel@tonic-gate 				case '1':
659*0Sstevel@tonic-gate 				case '2':
660*0Sstevel@tonic-gate 				case '3':
661*0Sstevel@tonic-gate 				case '4':
662*0Sstevel@tonic-gate 				case '5':
663*0Sstevel@tonic-gate 				case '6':
664*0Sstevel@tonic-gate 				case '7':
665*0Sstevel@tonic-gate 					n = (c - '0');
666*0Sstevel@tonic-gate 					c = fgetwc(fp);
667*0Sstevel@tonic-gate 					if (c >= '0' && c <= '7') {
668*0Sstevel@tonic-gate 						n = 8 * n + (c - '0');
669*0Sstevel@tonic-gate 						c = fgetwc(fp);
670*0Sstevel@tonic-gate 						if (c >= '0' && c <= '7')
671*0Sstevel@tonic-gate 							n = 8 * n + (c - '0');
672*0Sstevel@tonic-gate 						else
673*0Sstevel@tonic-gate 							(void) ungetwc(c, fp);
674*0Sstevel@tonic-gate 					} else
675*0Sstevel@tonic-gate 						(void) ungetwc(c, fp);
676*0Sstevel@tonic-gate 					if (n > UCHAR_MAX) {
677*0Sstevel@tonic-gate 						FPRINTF(stderr, MSG(13),
678*0Sstevel@tonic-gate 							msgfname, lineno, n);
679*0Sstevel@tonic-gate 						exit(1);
680*0Sstevel@tonic-gate 					}
681*0Sstevel@tonic-gate 					c = n;
682*0Sstevel@tonic-gate 					break;
683*0Sstevel@tonic-gate 
684*0Sstevel@tonic-gate 				case 'n':
685*0Sstevel@tonic-gate 					c = NEWLINE;
686*0Sstevel@tonic-gate 					break;
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate 				case 't':
689*0Sstevel@tonic-gate 					c = TAB;
690*0Sstevel@tonic-gate 					break;
691*0Sstevel@tonic-gate 
692*0Sstevel@tonic-gate 				case 'v':
693*0Sstevel@tonic-gate 					c = VTAB;
694*0Sstevel@tonic-gate 					break;
695*0Sstevel@tonic-gate 
696*0Sstevel@tonic-gate 				case 'b':
697*0Sstevel@tonic-gate 					c = BS;
698*0Sstevel@tonic-gate 					break;
699*0Sstevel@tonic-gate 
700*0Sstevel@tonic-gate 				case 'r':
701*0Sstevel@tonic-gate 					c = CR;
702*0Sstevel@tonic-gate 					break;
703*0Sstevel@tonic-gate 
704*0Sstevel@tonic-gate 				case 'f':
705*0Sstevel@tonic-gate 					c = FF;
706*0Sstevel@tonic-gate 					break;
707*0Sstevel@tonic-gate 				}
708*0Sstevel@tonic-gate 			}
709*0Sstevel@tonic-gate 			while ((text_len + (int)MB_CUR_MAX + 1) >= text_size)
710*0Sstevel@tonic-gate 				extend_text();
711*0Sstevel@tonic-gate 			if ((n = wctomb(&text[text_len], c)) > 0)
712*0Sstevel@tonic-gate 				text_len += n;
713*0Sstevel@tonic-gate 			c = fgetwc(fp);
714*0Sstevel@tonic-gate 		}
715*0Sstevel@tonic-gate 
716*0Sstevel@tonic-gate 		while ((text_len + 1) >= text_size)
717*0Sstevel@tonic-gate 			extend_text();
718*0Sstevel@tonic-gate 		text[text_len] = '\0';
719*0Sstevel@tonic-gate 		++text_len;
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate 		do {
722*0Sstevel@tonic-gate 			c = getc(fp);
723*0Sstevel@tonic-gate 		} while (c == SPACE || c == TAB);
724*0Sstevel@tonic-gate 		if (c == NEWLINE) {
725*0Sstevel@tonic-gate 			++lineno;
726*0Sstevel@tonic-gate 			return;
727*0Sstevel@tonic-gate 		}
728*0Sstevel@tonic-gate 		if (c == EOF) {
729*0Sstevel@tonic-gate 			ateof = 1;
730*0Sstevel@tonic-gate 			return;
731*0Sstevel@tonic-gate 		}
732*0Sstevel@tonic-gate 		FPRINTF(stderr, MSG(14), msgfname, lineno);
733*0Sstevel@tonic-gate 		exit(1);
734*0Sstevel@tonic-gate 	}
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate 	while (c != NEWLINE && c != EOF) {	/* quote is not used */
737*0Sstevel@tonic-gate 		if (c == REVERSE_SOLIDUS) {
738*0Sstevel@tonic-gate 			c = fgetwc(fp);
739*0Sstevel@tonic-gate 			switch (c) {
740*0Sstevel@tonic-gate 			case EOF:
741*0Sstevel@tonic-gate 				return;
742*0Sstevel@tonic-gate 
743*0Sstevel@tonic-gate 			case NEWLINE:
744*0Sstevel@tonic-gate 				++lineno;
745*0Sstevel@tonic-gate 				c = fgetwc(fp);
746*0Sstevel@tonic-gate 				continue;
747*0Sstevel@tonic-gate 
748*0Sstevel@tonic-gate 			case '0':
749*0Sstevel@tonic-gate 			case '1':
750*0Sstevel@tonic-gate 			case '2':
751*0Sstevel@tonic-gate 			case '3':
752*0Sstevel@tonic-gate 			case '4':
753*0Sstevel@tonic-gate 			case '5':
754*0Sstevel@tonic-gate 			case '6':
755*0Sstevel@tonic-gate 			case '7':
756*0Sstevel@tonic-gate 				n = (c - '0');
757*0Sstevel@tonic-gate 				c = fgetwc(fp);
758*0Sstevel@tonic-gate 				if (c >= '0' && c <= '7') {
759*0Sstevel@tonic-gate 					n = 8 * n + (c - '0');
760*0Sstevel@tonic-gate 					c = fgetwc(fp);
761*0Sstevel@tonic-gate 					if (c >= '0' && c <= '7')
762*0Sstevel@tonic-gate 						n = 8 * n + (c - '0');
763*0Sstevel@tonic-gate 					else
764*0Sstevel@tonic-gate 						(void) ungetwc(c, fp);
765*0Sstevel@tonic-gate 				} else
766*0Sstevel@tonic-gate 					(void) ungetwc(c, fp);
767*0Sstevel@tonic-gate 				if (n > UCHAR_MAX) {
768*0Sstevel@tonic-gate 					FPRINTF(stderr, MSG(13), msgfname,
769*0Sstevel@tonic-gate 							lineno, n);
770*0Sstevel@tonic-gate 					exit(1);
771*0Sstevel@tonic-gate 				}
772*0Sstevel@tonic-gate 				c = n;
773*0Sstevel@tonic-gate 				break;
774*0Sstevel@tonic-gate 
775*0Sstevel@tonic-gate 			case 'n':
776*0Sstevel@tonic-gate 				c = NEWLINE;
777*0Sstevel@tonic-gate 				break;
778*0Sstevel@tonic-gate 
779*0Sstevel@tonic-gate 			case 't':
780*0Sstevel@tonic-gate 				c = TAB;
781*0Sstevel@tonic-gate 				break;
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate 			case 'v':
784*0Sstevel@tonic-gate 				c = VTAB;
785*0Sstevel@tonic-gate 				break;
786*0Sstevel@tonic-gate 
787*0Sstevel@tonic-gate 			case 'b':
788*0Sstevel@tonic-gate 				c = BS;
789*0Sstevel@tonic-gate 				break;
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate 			case 'r':
792*0Sstevel@tonic-gate 				c = CR;
793*0Sstevel@tonic-gate 				break;
794*0Sstevel@tonic-gate 
795*0Sstevel@tonic-gate 			case 'f':
796*0Sstevel@tonic-gate 				c = FF;
797*0Sstevel@tonic-gate 				break;
798*0Sstevel@tonic-gate 			}
799*0Sstevel@tonic-gate 		}
800*0Sstevel@tonic-gate 		while ((text_len + (int)MB_CUR_MAX + 1) >= text_size)
801*0Sstevel@tonic-gate 			extend_text();
802*0Sstevel@tonic-gate 		if ((n = wctomb(&text[text_len], c)) > 0)
803*0Sstevel@tonic-gate 			text_len += n;
804*0Sstevel@tonic-gate 		c = fgetwc(fp);
805*0Sstevel@tonic-gate 	}
806*0Sstevel@tonic-gate 
807*0Sstevel@tonic-gate 	while ((text_len + 1) >= text_size)
808*0Sstevel@tonic-gate 		extend_text();
809*0Sstevel@tonic-gate 	text[text_len] = '\0';
810*0Sstevel@tonic-gate 	++text_len;
811*0Sstevel@tonic-gate 
812*0Sstevel@tonic-gate 	if (c == NEWLINE)
813*0Sstevel@tonic-gate 		++lineno;
814*0Sstevel@tonic-gate 	else
815*0Sstevel@tonic-gate 		ateof = 1;
816*0Sstevel@tonic-gate }
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate /*
819*0Sstevel@tonic-gate  * This routine handles $ <comment>, $set, $delset, $quote
820*0Sstevel@tonic-gate  */
821*0Sstevel@tonic-gate void
directive(fp)822*0Sstevel@tonic-gate directive(fp)
823*0Sstevel@tonic-gate 	FILE	*fp;
824*0Sstevel@tonic-gate {
825*0Sstevel@tonic-gate 	int		c;
826*0Sstevel@tonic-gate 	int		n;
827*0Sstevel@tonic-gate 
828*0Sstevel@tonic-gate 	c = fgetwc(fp);
829*0Sstevel@tonic-gate 	if (c == SPACE || c == TAB) {	/* $ <comment */
830*0Sstevel@tonic-gate 		do {
831*0Sstevel@tonic-gate 			c = fgetwc(fp);
832*0Sstevel@tonic-gate 		} while (c != NEWLINE && c != EOF);
833*0Sstevel@tonic-gate 	}
834*0Sstevel@tonic-gate 	if (c == NEWLINE) {
835*0Sstevel@tonic-gate 		++lineno;
836*0Sstevel@tonic-gate 		return;
837*0Sstevel@tonic-gate 	}
838*0Sstevel@tonic-gate 	if (c == EOF) {
839*0Sstevel@tonic-gate 		ateof = 1;
840*0Sstevel@tonic-gate 		return;
841*0Sstevel@tonic-gate 	}
842*0Sstevel@tonic-gate 	text_len = 1;
843*0Sstevel@tonic-gate 	while (text_len >= text_size)
844*0Sstevel@tonic-gate 		extend_text();
845*0Sstevel@tonic-gate 	text[0] = DOLLAR;
846*0Sstevel@tonic-gate 	while (isascii(c) && isalpha(c)) {
847*0Sstevel@tonic-gate 		while ((text_len + 1) >= text_size)
848*0Sstevel@tonic-gate 			extend_text();
849*0Sstevel@tonic-gate 		text[text_len] = c;
850*0Sstevel@tonic-gate 		++text_len;
851*0Sstevel@tonic-gate 		c = fgetwc(fp);
852*0Sstevel@tonic-gate 	}
853*0Sstevel@tonic-gate 
854*0Sstevel@tonic-gate 	while ((text_len + 1) >= text_size)
855*0Sstevel@tonic-gate 		extend_text();
856*0Sstevel@tonic-gate 	text[text_len] = NUL;
857*0Sstevel@tonic-gate 
858*0Sstevel@tonic-gate 	if (strcmp(text, "$set") == 0) {
859*0Sstevel@tonic-gate 		while (c == SPACE || c == TAB)
860*0Sstevel@tonic-gate 			c = fgetwc(fp);
861*0Sstevel@tonic-gate 		if (!isascii(c) || !isdigit(c)) {
862*0Sstevel@tonic-gate 			FPRINTF(stderr, MSG(16), msgfname, lineno);
863*0Sstevel@tonic-gate 			exit(1);
864*0Sstevel@tonic-gate 		}
865*0Sstevel@tonic-gate 		n = get_number(fp, c);
866*0Sstevel@tonic-gate 		if (n == 0) {
867*0Sstevel@tonic-gate 			FPRINTF(stderr, MSG(17), msgfname, lineno);
868*0Sstevel@tonic-gate 			exit(1);
869*0Sstevel@tonic-gate 		}
870*0Sstevel@tonic-gate 		if (n > NL_SETMAX) {
871*0Sstevel@tonic-gate 			FPRINTF(stderr, MSG(18), msgfname, lineno,
872*0Sstevel@tonic-gate 						n, NL_SETMAX);
873*0Sstevel@tonic-gate 		}
874*0Sstevel@tonic-gate 		find_set(n);
875*0Sstevel@tonic-gate 		do {	/* skip comment */
876*0Sstevel@tonic-gate 			c = getc(fp);
877*0Sstevel@tonic-gate 		} while (c != NEWLINE && c != EOF);
878*0Sstevel@tonic-gate 		if (c == NEWLINE)
879*0Sstevel@tonic-gate 			++lineno;
880*0Sstevel@tonic-gate 		else
881*0Sstevel@tonic-gate 			ateof = 1;
882*0Sstevel@tonic-gate 		return;
883*0Sstevel@tonic-gate 	} else if (strcmp(text, "$delset") == 0) {
884*0Sstevel@tonic-gate 		while (c == SPACE || c == TAB)
885*0Sstevel@tonic-gate 			c = fgetwc(fp);
886*0Sstevel@tonic-gate 		if (!isascii(c) || !isdigit(c)) {
887*0Sstevel@tonic-gate 			FPRINTF(stderr, MSG(20), msgfname, lineno);
888*0Sstevel@tonic-gate 			exit(1);
889*0Sstevel@tonic-gate 		}
890*0Sstevel@tonic-gate 		n = get_number(fp, c);
891*0Sstevel@tonic-gate 		if (n == 0) {
892*0Sstevel@tonic-gate 			FPRINTF(stderr, MSG(17), msgfname, lineno);
893*0Sstevel@tonic-gate 			exit(1);
894*0Sstevel@tonic-gate 		}
895*0Sstevel@tonic-gate 		if (n > NL_SETMAX) {
896*0Sstevel@tonic-gate 			FPRINTF(stderr, MSG(18), msgfname, lineno,
897*0Sstevel@tonic-gate 						n, NL_SETMAX);
898*0Sstevel@tonic-gate 		}
899*0Sstevel@tonic-gate 		delete_set(n);
900*0Sstevel@tonic-gate 		do {	/* skip comment */
901*0Sstevel@tonic-gate 			c = getc(fp);
902*0Sstevel@tonic-gate 		} while (c != NEWLINE && c != EOF);
903*0Sstevel@tonic-gate 		if (c == NEWLINE)
904*0Sstevel@tonic-gate 			++lineno;
905*0Sstevel@tonic-gate 		else
906*0Sstevel@tonic-gate 			ateof = 1;
907*0Sstevel@tonic-gate 		return;
908*0Sstevel@tonic-gate 	} else if (strcmp(text, "$quote") == 0) {
909*0Sstevel@tonic-gate 		if (c == NEWLINE) {
910*0Sstevel@tonic-gate 			quoting = 0;
911*0Sstevel@tonic-gate 			++lineno;
912*0Sstevel@tonic-gate 			return;
913*0Sstevel@tonic-gate 		}
914*0Sstevel@tonic-gate 		if (c == EOF) {
915*0Sstevel@tonic-gate 			quoting = 0;
916*0Sstevel@tonic-gate 			ateof = 1;
917*0Sstevel@tonic-gate 			return;
918*0Sstevel@tonic-gate 		}
919*0Sstevel@tonic-gate 		if (c == SPACE || c == TAB)
920*0Sstevel@tonic-gate 			c = fgetwc(fp);
921*0Sstevel@tonic-gate 		if (c == NEWLINE) {
922*0Sstevel@tonic-gate 			quoting = 0;
923*0Sstevel@tonic-gate 			++lineno;
924*0Sstevel@tonic-gate 			return;
925*0Sstevel@tonic-gate 		}
926*0Sstevel@tonic-gate 		if (c == EOF) {
927*0Sstevel@tonic-gate 			quoting = 0;
928*0Sstevel@tonic-gate 			ateof = 1;
929*0Sstevel@tonic-gate 			return;
930*0Sstevel@tonic-gate 		}
931*0Sstevel@tonic-gate 		quoting = 1;
932*0Sstevel@tonic-gate 		quote = c;
933*0Sstevel@tonic-gate 		do {	/* skip comment */
934*0Sstevel@tonic-gate 			c = getc(fp);
935*0Sstevel@tonic-gate 		} while (c == SPACE || c == TAB);
936*0Sstevel@tonic-gate 		if (c == NEWLINE) {
937*0Sstevel@tonic-gate 			++lineno;
938*0Sstevel@tonic-gate 			return;
939*0Sstevel@tonic-gate 		}
940*0Sstevel@tonic-gate 		if (c == EOF) {
941*0Sstevel@tonic-gate 			ateof = 1;
942*0Sstevel@tonic-gate 			return;
943*0Sstevel@tonic-gate 		}
944*0Sstevel@tonic-gate 		FPRINTF(stderr, MSG(15), msgfname, lineno);
945*0Sstevel@tonic-gate 		exit(1);
946*0Sstevel@tonic-gate 	} else {
947*0Sstevel@tonic-gate 		FPRINTF(stderr, MSG(19), msgfname, lineno, text);
948*0Sstevel@tonic-gate 		exit(1);
949*0Sstevel@tonic-gate 	}
950*0Sstevel@tonic-gate }
951*0Sstevel@tonic-gate 
952*0Sstevel@tonic-gate /*
953*0Sstevel@tonic-gate  * Read message source file and update double linked list message catalog.
954*0Sstevel@tonic-gate  */
955*0Sstevel@tonic-gate void
read_msgfile(fp,pathname)956*0Sstevel@tonic-gate read_msgfile(fp, pathname)
957*0Sstevel@tonic-gate 	FILE	*fp;
958*0Sstevel@tonic-gate 	char	*pathname;
959*0Sstevel@tonic-gate {
960*0Sstevel@tonic-gate 	int		c;
961*0Sstevel@tonic-gate 	int		no;
962*0Sstevel@tonic-gate 
963*0Sstevel@tonic-gate 	ateof = 0;
964*0Sstevel@tonic-gate 	msgfname = pathname;
965*0Sstevel@tonic-gate 	lineno = 1;
966*0Sstevel@tonic-gate 	quoting = 0;
967*0Sstevel@tonic-gate 	current_set_no = NL_SETD;
968*0Sstevel@tonic-gate 	current_set = NULL;
969*0Sstevel@tonic-gate 	current_msg = NULL;
970*0Sstevel@tonic-gate 
971*0Sstevel@tonic-gate 	for (;;) {
972*0Sstevel@tonic-gate 		if (ateof)
973*0Sstevel@tonic-gate 			return;
974*0Sstevel@tonic-gate 		do {
975*0Sstevel@tonic-gate 			c = fgetwc(fp);
976*0Sstevel@tonic-gate 		} while (c == SPACE || c == TAB);
977*0Sstevel@tonic-gate 		if (c == DOLLAR) {
978*0Sstevel@tonic-gate 			directive(fp);
979*0Sstevel@tonic-gate 			continue;
980*0Sstevel@tonic-gate 		}
981*0Sstevel@tonic-gate 
982*0Sstevel@tonic-gate 		if (isascii(c) && isdigit(c)) {
983*0Sstevel@tonic-gate 			no = get_number(fp, c);
984*0Sstevel@tonic-gate 			if (no == 0) {
985*0Sstevel@tonic-gate 				FPRINTF(stderr, MSG(10), msgfname, lineno);
986*0Sstevel@tonic-gate 				exit(1);
987*0Sstevel@tonic-gate 			}
988*0Sstevel@tonic-gate 			if (no > NL_MSGMAX) {
989*0Sstevel@tonic-gate 				FPRINTF(stderr, MSG(11), msgfname,
990*0Sstevel@tonic-gate 					lineno, no, NL_MSGMAX);
991*0Sstevel@tonic-gate 			}
992*0Sstevel@tonic-gate 			c = fgetwc(fp);
993*0Sstevel@tonic-gate 			if (c == NEWLINE || c == EOF) {
994*0Sstevel@tonic-gate 				delete_msg(no);
995*0Sstevel@tonic-gate 				if (c == NEWLINE)
996*0Sstevel@tonic-gate 					++lineno;
997*0Sstevel@tonic-gate 				else
998*0Sstevel@tonic-gate 					return;
999*0Sstevel@tonic-gate 				continue;
1000*0Sstevel@tonic-gate 			} else {
1001*0Sstevel@tonic-gate 				if (c != SPACE && c != TAB)
1002*0Sstevel@tonic-gate 					(void) ungetwc(c, fp);
1003*0Sstevel@tonic-gate 				get_text(fp);
1004*0Sstevel@tonic-gate 				insert_msg(no, text_len, text);
1005*0Sstevel@tonic-gate 				continue;
1006*0Sstevel@tonic-gate 			}
1007*0Sstevel@tonic-gate 		}
1008*0Sstevel@tonic-gate 
1009*0Sstevel@tonic-gate 		if (c == NEWLINE) {
1010*0Sstevel@tonic-gate 			++lineno;
1011*0Sstevel@tonic-gate 			continue;
1012*0Sstevel@tonic-gate 		}
1013*0Sstevel@tonic-gate 		if (c == EOF)
1014*0Sstevel@tonic-gate 			return;
1015*0Sstevel@tonic-gate 
1016*0Sstevel@tonic-gate 		FPRINTF(stderr, MSG(22), msgfname, lineno);
1017*0Sstevel@tonic-gate 		exit(1);
1018*0Sstevel@tonic-gate 	}
1019*0Sstevel@tonic-gate }
1020*0Sstevel@tonic-gate 
1021*0Sstevel@tonic-gate /*
1022*0Sstevel@tonic-gate  * Write double linked list to the file.
1023*0Sstevel@tonic-gate  * It first converts a linked list to one chunk of memory and
1024*0Sstevel@tonic-gate  * write it to file.
1025*0Sstevel@tonic-gate  */
1026*0Sstevel@tonic-gate void
writecat(fd,pathname)1027*0Sstevel@tonic-gate writecat(fd, pathname)
1028*0Sstevel@tonic-gate 	int		fd;
1029*0Sstevel@tonic-gate 	char	*pathname;
1030*0Sstevel@tonic-gate {
1031*0Sstevel@tonic-gate 	int		i, n;
1032*0Sstevel@tonic-gate 	int		nsets;
1033*0Sstevel@tonic-gate 	int		mem;
1034*0Sstevel@tonic-gate 	int		nmsgs;
1035*0Sstevel@tonic-gate 	int		text_size;
1036*0Sstevel@tonic-gate 	int		first_msg_hdr;
1037*0Sstevel@tonic-gate 	int		msg_offset;
1038*0Sstevel@tonic-gate 	unsigned	nbytes;
1039*0Sstevel@tonic-gate 	char	*cat;
1040*0Sstevel@tonic-gate 	struct	_cat_hdr	*hdrp;
1041*0Sstevel@tonic-gate 	struct	cat_set		*setp;
1042*0Sstevel@tonic-gate 	struct	cat_msg		*msgp;
1043*0Sstevel@tonic-gate 	struct	_cat_set_hdr	*set;
1044*0Sstevel@tonic-gate 	struct	_cat_msg_hdr	*msg;
1045*0Sstevel@tonic-gate 	char	*text;
1046*0Sstevel@tonic-gate 
1047*0Sstevel@tonic-gate 	/* compute number of sets, number of messages, the total text size */
1048*0Sstevel@tonic-gate 	nsets = 0;
1049*0Sstevel@tonic-gate 	nmsgs = 0;
1050*0Sstevel@tonic-gate 	text_size = 0;
1051*0Sstevel@tonic-gate 	for (setp = first_set; setp; setp = setp->next) {
1052*0Sstevel@tonic-gate 		++nsets;
1053*0Sstevel@tonic-gate 		for (msgp = setp->first_msg; msgp; msgp = msgp->next) {
1054*0Sstevel@tonic-gate 			++nmsgs;
1055*0Sstevel@tonic-gate 			text_size += msgp->msg_len;
1056*0Sstevel@tonic-gate 		}
1057*0Sstevel@tonic-gate 	}
1058*0Sstevel@tonic-gate 
1059*0Sstevel@tonic-gate 	mem = nsets * _CAT_SET_HDR_SIZE + nmsgs * _CAT_MSG_HDR_SIZE + text_size;
1060*0Sstevel@tonic-gate 	n = _CAT_HDR_SIZE + mem;
1061*0Sstevel@tonic-gate 	cat = MALLOC(n);
1062*0Sstevel@tonic-gate 	if (cat == 0) {
1063*0Sstevel@tonic-gate 		FPRINTF(stderr, MSG(6));
1064*0Sstevel@tonic-gate 		exit(1);
1065*0Sstevel@tonic-gate 	}
1066*0Sstevel@tonic-gate 	MEMSET(cat, 0, n);
1067*0Sstevel@tonic-gate 
1068*0Sstevel@tonic-gate 	hdrp = (struct _cat_hdr *) cat;
1069*0Sstevel@tonic-gate 	hdrp->__hdr_magic = _CAT_MAGIC;
1070*0Sstevel@tonic-gate 	hdrp->__nsets = nsets;
1071*0Sstevel@tonic-gate 	hdrp->__mem = mem;
1072*0Sstevel@tonic-gate 	hdrp->__msg_hdr_offset = nsets * _CAT_SET_HDR_SIZE;
1073*0Sstevel@tonic-gate 	hdrp->__msg_text_offset = nsets * _CAT_SET_HDR_SIZE +
1074*0Sstevel@tonic-gate 				nmsgs * _CAT_MSG_HDR_SIZE;
1075*0Sstevel@tonic-gate 
1076*0Sstevel@tonic-gate 	set = (struct _cat_set_hdr *) (cat + _CAT_HDR_SIZE);
1077*0Sstevel@tonic-gate 	msg = (struct _cat_msg_hdr *) (set + nsets);
1078*0Sstevel@tonic-gate 	text = (char *) (msg + nmsgs);
1079*0Sstevel@tonic-gate 
1080*0Sstevel@tonic-gate 	/* convert linked list to one chunk of memory */
1081*0Sstevel@tonic-gate 	first_msg_hdr = 0;
1082*0Sstevel@tonic-gate 	msg_offset = 0;
1083*0Sstevel@tonic-gate 	for (setp = first_set; setp; ++set, setp = setp->next) {
1084*0Sstevel@tonic-gate 		set->__set_no = setp->set_no;
1085*0Sstevel@tonic-gate 		set->__first_msg_hdr = first_msg_hdr;
1086*0Sstevel@tonic-gate 		nmsgs = 0;
1087*0Sstevel@tonic-gate 		for (msgp = setp->first_msg; msgp; ++msg, msgp = msgp->next) {
1088*0Sstevel@tonic-gate 			++nmsgs;
1089*0Sstevel@tonic-gate 			msg->__msg_no = msgp->msg_no;
1090*0Sstevel@tonic-gate 			msg->__msg_len = msgp->msg_len;
1091*0Sstevel@tonic-gate 			msg->__msg_offset = msg_offset;
1092*0Sstevel@tonic-gate 			if (msgp->msg_len > 0) {
1093*0Sstevel@tonic-gate 				MEMCPY(text, msgp->s, msgp->msg_len);
1094*0Sstevel@tonic-gate 				text += msgp->msg_len;
1095*0Sstevel@tonic-gate 				msg_offset += msgp->msg_len;
1096*0Sstevel@tonic-gate 			}
1097*0Sstevel@tonic-gate 		}
1098*0Sstevel@tonic-gate 		set->__nmsgs = nmsgs;
1099*0Sstevel@tonic-gate 		first_msg_hdr += nmsgs;
1100*0Sstevel@tonic-gate 	}
1101*0Sstevel@tonic-gate 
1102*0Sstevel@tonic-gate 	/* write one chunk of memory to file */
1103*0Sstevel@tonic-gate 	nbytes = 0;
1104*0Sstevel@tonic-gate 	while (nbytes < n) {
1105*0Sstevel@tonic-gate 		i = write(fd, cat + nbytes, n - nbytes);
1106*0Sstevel@tonic-gate 		if (i < 0) {
1107*0Sstevel@tonic-gate 			if (errno != EINTR) {
1108*0Sstevel@tonic-gate 				FPRINTF(stderr, MSG(8), pathname);
1109*0Sstevel@tonic-gate 				perror("");
1110*0Sstevel@tonic-gate 				exit(1);
1111*0Sstevel@tonic-gate 			}
1112*0Sstevel@tonic-gate 		} else {
1113*0Sstevel@tonic-gate 			nbytes += n;
1114*0Sstevel@tonic-gate 		}
1115*0Sstevel@tonic-gate 	}
1116*0Sstevel@tonic-gate 
1117*0Sstevel@tonic-gate 	free(cat);
1118*0Sstevel@tonic-gate }
1119*0Sstevel@tonic-gate 
1120*0Sstevel@tonic-gate int
main(argc,argv)1121*0Sstevel@tonic-gate main(argc, argv)
1122*0Sstevel@tonic-gate 	int		argc;
1123*0Sstevel@tonic-gate 	char	*argv[];
1124*0Sstevel@tonic-gate {
1125*0Sstevel@tonic-gate 	int		i;
1126*0Sstevel@tonic-gate 	int		cat_exists;
1127*0Sstevel@tonic-gate 
1128*0Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1129*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
1130*0Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
1131*0Sstevel@tonic-gate #endif
1132*0Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1133*0Sstevel@tonic-gate 
1134*0Sstevel@tonic-gate 	if (argc < 3) {
1135*0Sstevel@tonic-gate 		FPRINTF(stderr, MSG(1));
1136*0Sstevel@tonic-gate 		exit(1);
1137*0Sstevel@tonic-gate 	}
1138*0Sstevel@tonic-gate 	catfname = argv[1];
1139*0Sstevel@tonic-gate 	cat_exists = 0;
1140*0Sstevel@tonic-gate 	if ((*catfname == '-') && (*(catfname + 1) == '\0')) {
1141*0Sstevel@tonic-gate 		catfd = 1;				/* Use stdout */
1142*0Sstevel@tonic-gate 	} else {
1143*0Sstevel@tonic-gate 		catfd = open(catfname, O_WRONLY | O_CREAT | O_EXCL, 0666);
1144*0Sstevel@tonic-gate 		if (catfd < 0) {	/* file exists */
1145*0Sstevel@tonic-gate 			if (errno != EEXIST ||
1146*0Sstevel@tonic-gate 			    (catfd = open(catfname, O_RDWR)) < 0) {
1147*0Sstevel@tonic-gate 				/* cannot open file */
1148*0Sstevel@tonic-gate 				FPRINTF(stderr, MSG(2), catfname);
1149*0Sstevel@tonic-gate 				perror("");
1150*0Sstevel@tonic-gate 				exit(1);
1151*0Sstevel@tonic-gate 			}
1152*0Sstevel@tonic-gate 			cat_exists = 1;
1153*0Sstevel@tonic-gate 			/* read catalog file into memory */
1154*0Sstevel@tonic-gate 			readcat(catfd, catfname);
1155*0Sstevel@tonic-gate 			if (lseek(catfd, 0L, 0) < 0) {
1156*0Sstevel@tonic-gate 				FPRINTF(stderr, MSG(7), catfname);
1157*0Sstevel@tonic-gate 				perror("");
1158*0Sstevel@tonic-gate 				exit(1);
1159*0Sstevel@tonic-gate 			}
1160*0Sstevel@tonic-gate 		}
1161*0Sstevel@tonic-gate 	}
1162*0Sstevel@tonic-gate 
1163*0Sstevel@tonic-gate 	/* process all message source files */
1164*0Sstevel@tonic-gate 	if ((**(argv + 2) == '-') && (*(*(argv + 2) + 1) == '\0')) {
1165*0Sstevel@tonic-gate 		if (argc != 3) {
1166*0Sstevel@tonic-gate 			FPRINTF(stderr, MSG(1));
1167*0Sstevel@tonic-gate 			exit(1);
1168*0Sstevel@tonic-gate 		} else {
1169*0Sstevel@tonic-gate 			read_msgfile(stdin, MSG(21));
1170*0Sstevel@tonic-gate 		}
1171*0Sstevel@tonic-gate 	} else {
1172*0Sstevel@tonic-gate 		for (i = 2; i < argc; ++i) {
1173*0Sstevel@tonic-gate 			FILE	*fp;
1174*0Sstevel@tonic-gate 			fp = fopen(*(argv + i), "r");
1175*0Sstevel@tonic-gate 			if (fp == NULL) {
1176*0Sstevel@tonic-gate 				FPRINTF(stderr, MSG(2), *(argv + i));
1177*0Sstevel@tonic-gate 				perror("");
1178*0Sstevel@tonic-gate 				exit(1);
1179*0Sstevel@tonic-gate 			}
1180*0Sstevel@tonic-gate 			read_msgfile(fp, *(argv + i));
1181*0Sstevel@tonic-gate 			(void) fclose(fp);
1182*0Sstevel@tonic-gate 		}
1183*0Sstevel@tonic-gate 	}
1184*0Sstevel@tonic-gate 
1185*0Sstevel@tonic-gate 	if (cat_exists)
1186*0Sstevel@tonic-gate 		(void) ftruncate(catfd, 0L);
1187*0Sstevel@tonic-gate 
1188*0Sstevel@tonic-gate 	/* write catalog to file */
1189*0Sstevel@tonic-gate 	writecat(catfd, catfname);
1190*0Sstevel@tonic-gate 	return (0);
1191*0Sstevel@tonic-gate }
1192