xref: /illumos-gate/usr/src/cmd/genmsg/util.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1995 by Sun Microsystems, Inc.
24*7c478bd9Sstevel@tonic-gate  */
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate #include <stdio.h>
29*7c478bd9Sstevel@tonic-gate #include <limits.h>
30*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
31*7c478bd9Sstevel@tonic-gate #include <string.h>
32*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
33*7c478bd9Sstevel@tonic-gate #include <libintl.h>
34*7c478bd9Sstevel@tonic-gate #include <locale.h>
35*7c478bd9Sstevel@tonic-gate #include <libgen.h>
36*7c478bd9Sstevel@tonic-gate #include <ctype.h>
37*7c478bd9Sstevel@tonic-gate #include <unistd.h>
38*7c478bd9Sstevel@tonic-gate #include <signal.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate #include "genmsg.h"
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate #define	SET_TOKEN	"$set"
45*7c478bd9Sstevel@tonic-gate #define	DELSET_TOKEN	"$delset"
46*7c478bd9Sstevel@tonic-gate #define	QUOTE_TOKEN	"$quote"
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate #define	SkipSpace(s)	while (*(s) == ' ' || *(s) == '\t') s++
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate extern char *program;		/* from main.c */
51*7c478bd9Sstevel@tonic-gate extern char *mctag;		/* from main.c */
52*7c478bd9Sstevel@tonic-gate extern char *sctag;		/* from main.c */
53*7c478bd9Sstevel@tonic-gate extern char *premsg;		/* from main.c */
54*7c478bd9Sstevel@tonic-gate extern char *sufmsg;		/* from main.c */
55*7c478bd9Sstevel@tonic-gate extern int suppress_error;	/* from main.c */
56*7c478bd9Sstevel@tonic-gate extern void warning(char *);	/* from genmsg.l */
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate typedef struct _SetID *SetID;
59*7c478bd9Sstevel@tonic-gate typedef struct _MsgID *MsgID;
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate typedef struct _SetID SetIDRec;
62*7c478bd9Sstevel@tonic-gate struct _SetID {
63*7c478bd9Sstevel@tonic-gate 	int id;
64*7c478bd9Sstevel@tonic-gate 	char *comment;
65*7c478bd9Sstevel@tonic-gate 	MsgID top;
66*7c478bd9Sstevel@tonic-gate 	SetID next;
67*7c478bd9Sstevel@tonic-gate };
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate typedef struct _MsgID MsgIDRec;
70*7c478bd9Sstevel@tonic-gate struct _MsgID {
71*7c478bd9Sstevel@tonic-gate 	int no_write;
72*7c478bd9Sstevel@tonic-gate 	int id;
73*7c478bd9Sstevel@tonic-gate 	char *msg;
74*7c478bd9Sstevel@tonic-gate 	int line;
75*7c478bd9Sstevel@tonic-gate 	char *file;
76*7c478bd9Sstevel@tonic-gate 	char *comment;
77*7c478bd9Sstevel@tonic-gate 	MsgID next;
78*7c478bd9Sstevel@tonic-gate };
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate /* Top pointer of the setid list. */
82*7c478bd9Sstevel@tonic-gate static SetID setid_top;
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate /* comment for messages. */
85*7c478bd9Sstevel@tonic-gate static char *msg_comment;
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate /* comment for set numbers. */
88*7c478bd9Sstevel@tonic-gate static char *set_comment;
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate /* List of set number's maximum message numbers. */
91*7c478bd9Sstevel@tonic-gate static int msgid_table[NL_SETMAX+1];
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate /* Quote character to surround messages. */
94*7c478bd9Sstevel@tonic-gate static char quote = QUOTE;
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate /* Internal functions. */
97*7c478bd9Sstevel@tonic-gate static void add_msgid(SetID, int, char *, char *, int, int);
98*7c478bd9Sstevel@tonic-gate static void add_setid(int, int, char *, char *, int, int);
99*7c478bd9Sstevel@tonic-gate static SetID lookup_setid(int);
100*7c478bd9Sstevel@tonic-gate static MsgID lookup_msgid(SetID, int, char *, char *, int);
101*7c478bd9Sstevel@tonic-gate static void print_prefix(FILE *, char *, int, char *);
102*7c478bd9Sstevel@tonic-gate static int is_bs_terminated(char *);
103*7c478bd9Sstevel@tonic-gate static char *ustrdup(char *);
104*7c478bd9Sstevel@tonic-gate static void cat_msg(char *, char *, int);
105*7c478bd9Sstevel@tonic-gate static void makeup_msg(char **);
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate void
108*7c478bd9Sstevel@tonic-gate add_msg(int setid, int msgid, char *msg, char *file, int line, int no_write)
109*7c478bd9Sstevel@tonic-gate {
110*7c478bd9Sstevel@tonic-gate 	SetID si;
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 	if (si = lookup_setid(setid)) {
113*7c478bd9Sstevel@tonic-gate 		if (lookup_msgid(si, msgid, msg, file, line)) {
114*7c478bd9Sstevel@tonic-gate 			return; /* we already have the one. */
115*7c478bd9Sstevel@tonic-gate 		} else {
116*7c478bd9Sstevel@tonic-gate 			add_msgid(si, msgid, msg, file, line, no_write);
117*7c478bd9Sstevel@tonic-gate 		}
118*7c478bd9Sstevel@tonic-gate 	} else {
119*7c478bd9Sstevel@tonic-gate 		add_setid(setid, msgid, msg, file, line, no_write);
120*7c478bd9Sstevel@tonic-gate 	}
121*7c478bd9Sstevel@tonic-gate }
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate int
124*7c478bd9Sstevel@tonic-gate is_writable(char *file)
125*7c478bd9Sstevel@tonic-gate {
126*7c478bd9Sstevel@tonic-gate 	struct stat buf;
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 	if (stat(file, &buf) == -1)
129*7c478bd9Sstevel@tonic-gate 		return (TRUE);
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 	if (access(file, W_OK) == 0)
132*7c478bd9Sstevel@tonic-gate 		return (TRUE);
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 	return (FALSE);
135*7c478bd9Sstevel@tonic-gate }
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate void
138*7c478bd9Sstevel@tonic-gate write_msgfile(char *file)
139*7c478bd9Sstevel@tonic-gate {
140*7c478bd9Sstevel@tonic-gate 	FILE *fp;
141*7c478bd9Sstevel@tonic-gate 	SetID si = setid_top;
142*7c478bd9Sstevel@tonic-gate 	char *mode = "w";
143*7c478bd9Sstevel@tonic-gate 	char pquote[2];
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 	if (is_writable(file) == FALSE) {
146*7c478bd9Sstevel@tonic-gate 		prg_err(gettext("cannot create \"%s\": permission denied"),
147*7c478bd9Sstevel@tonic-gate 			file);
148*7c478bd9Sstevel@tonic-gate 		return;
149*7c478bd9Sstevel@tonic-gate 	}
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate 	if (IsActiveMode(AppendMode)) {
152*7c478bd9Sstevel@tonic-gate 		mode = "a";
153*7c478bd9Sstevel@tonic-gate 	}
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(file, mode)) == NULL) {
156*7c478bd9Sstevel@tonic-gate 		prg_err(gettext("cannot create \"%s\""), file);
157*7c478bd9Sstevel@tonic-gate 		return;
158*7c478bd9Sstevel@tonic-gate 	}
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	if (quote) {
161*7c478bd9Sstevel@tonic-gate 		(void) sprintf(pquote, "%c", quote);
162*7c478bd9Sstevel@tonic-gate 	} else {
163*7c478bd9Sstevel@tonic-gate 		(void) sprintf(pquote, "");
164*7c478bd9Sstevel@tonic-gate 	}
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate 	/* AppendMode is already turned off if the file doesn't exist. */
167*7c478bd9Sstevel@tonic-gate 	if (!IsActiveMode(AppendMode)) {
168*7c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "\n$quote %s\n\n", pquote);
169*7c478bd9Sstevel@tonic-gate 	}
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	while (si) {
172*7c478bd9Sstevel@tonic-gate 		int is_set = FALSE;
173*7c478bd9Sstevel@tonic-gate 		MsgID mi = si->top;
174*7c478bd9Sstevel@tonic-gate 		while (mi) {
175*7c478bd9Sstevel@tonic-gate 			char msg[NL_TEXTMAX+32]; /* 32 is some other stuff. */
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 			if (mi->no_write) {
178*7c478bd9Sstevel@tonic-gate 				mi = mi->next;
179*7c478bd9Sstevel@tonic-gate 				continue;
180*7c478bd9Sstevel@tonic-gate 			}
181*7c478bd9Sstevel@tonic-gate 			if (is_set == FALSE) {
182*7c478bd9Sstevel@tonic-gate 				if (si->comment &&
183*7c478bd9Sstevel@tonic-gate 					!IsActiveMode(BackCommentMode)) {
184*7c478bd9Sstevel@tonic-gate 					(void) fprintf(fp, "\n");
185*7c478bd9Sstevel@tonic-gate 					print_prefix(fp, "$ ", TRUE,
186*7c478bd9Sstevel@tonic-gate 							si->comment);
187*7c478bd9Sstevel@tonic-gate 					(void) fprintf(fp, "$set\t%d\n",
188*7c478bd9Sstevel@tonic-gate 							si->id);
189*7c478bd9Sstevel@tonic-gate 				} else {
190*7c478bd9Sstevel@tonic-gate 					(void) fprintf(fp, "\n$set\t%d\n",
191*7c478bd9Sstevel@tonic-gate 							si->id);
192*7c478bd9Sstevel@tonic-gate 				}
193*7c478bd9Sstevel@tonic-gate 				if (si->comment &&
194*7c478bd9Sstevel@tonic-gate 					IsActiveMode(BackCommentMode)) {
195*7c478bd9Sstevel@tonic-gate 					print_prefix(fp, "$ ", TRUE,
196*7c478bd9Sstevel@tonic-gate 							si->comment);
197*7c478bd9Sstevel@tonic-gate 				}
198*7c478bd9Sstevel@tonic-gate 				(void) fprintf(fp, "\n");
199*7c478bd9Sstevel@tonic-gate 				is_set = TRUE;
200*7c478bd9Sstevel@tonic-gate 			}
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 			makeup_msg(&(mi->msg));
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 			(void) sprintf(msg, "%d\t%s%s%s\n",
205*7c478bd9Sstevel@tonic-gate 				mi->id, pquote, mi->msg, pquote);
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 			if (!IsActiveMode(BackCommentMode)) {
208*7c478bd9Sstevel@tonic-gate 				if (mi->line && mi->file &&
209*7c478bd9Sstevel@tonic-gate 					IsActiveMode(LineInfoMode)) {
210*7c478bd9Sstevel@tonic-gate 					(void) fprintf(fp,
211*7c478bd9Sstevel@tonic-gate 						"$ File:%s, line:%d\n",
212*7c478bd9Sstevel@tonic-gate 						basename(mi->file), mi->line);
213*7c478bd9Sstevel@tonic-gate 				}
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 				if (mi->comment) {
216*7c478bd9Sstevel@tonic-gate 					print_prefix(fp, "$ ", TRUE,
217*7c478bd9Sstevel@tonic-gate 						mi->comment);
218*7c478bd9Sstevel@tonic-gate 				}
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate 				if (IsActiveMode(DoubleLineMode)) {
221*7c478bd9Sstevel@tonic-gate 					print_prefix(fp, "$ ", FALSE, msg);
222*7c478bd9Sstevel@tonic-gate 				}
223*7c478bd9Sstevel@tonic-gate 			}
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 			(void) fprintf(fp, "%s", msg);
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 			if (IsActiveMode(BackCommentMode)) {
228*7c478bd9Sstevel@tonic-gate 				if (mi->line && mi->file &&
229*7c478bd9Sstevel@tonic-gate 					IsActiveMode(LineInfoMode)) {
230*7c478bd9Sstevel@tonic-gate 					(void) fprintf(fp,
231*7c478bd9Sstevel@tonic-gate 						"$ File:%s, line:%d\n",
232*7c478bd9Sstevel@tonic-gate 						basename(mi->file), mi->line);
233*7c478bd9Sstevel@tonic-gate 				}
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 				if (mi->comment) {
236*7c478bd9Sstevel@tonic-gate 					print_prefix(fp, "$ ", TRUE,
237*7c478bd9Sstevel@tonic-gate 						mi->comment);
238*7c478bd9Sstevel@tonic-gate 				}
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 				if (IsActiveMode(DoubleLineMode)) {
241*7c478bd9Sstevel@tonic-gate 					print_prefix(fp, "$ ", FALSE, msg);
242*7c478bd9Sstevel@tonic-gate 				}
243*7c478bd9Sstevel@tonic-gate 			}
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 			(void) fprintf(fp, "\n");
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 			mi = mi->next;
248*7c478bd9Sstevel@tonic-gate 		}
249*7c478bd9Sstevel@tonic-gate 		si = si->next;
250*7c478bd9Sstevel@tonic-gate 	}
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
253*7c478bd9Sstevel@tonic-gate }
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate static SetID
256*7c478bd9Sstevel@tonic-gate lookup_setid(int id)
257*7c478bd9Sstevel@tonic-gate {
258*7c478bd9Sstevel@tonic-gate 	SetID si = setid_top;
259*7c478bd9Sstevel@tonic-gate 	while (si) {
260*7c478bd9Sstevel@tonic-gate 		if (si->id == id) {
261*7c478bd9Sstevel@tonic-gate 			return (si);
262*7c478bd9Sstevel@tonic-gate 		}
263*7c478bd9Sstevel@tonic-gate 		si = si->next;
264*7c478bd9Sstevel@tonic-gate 	}
265*7c478bd9Sstevel@tonic-gate 	return (NULL);
266*7c478bd9Sstevel@tonic-gate }
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate static MsgID
269*7c478bd9Sstevel@tonic-gate lookup_msgid(SetID si, int msgid, char *msg, char *file, int line)
270*7c478bd9Sstevel@tonic-gate {
271*7c478bd9Sstevel@tonic-gate 	MsgID mi = si->top;
272*7c478bd9Sstevel@tonic-gate 	while (mi) {
273*7c478bd9Sstevel@tonic-gate 		if (mi->id == msgid) {
274*7c478bd9Sstevel@tonic-gate 			/* same setid & msgid, but different msg. */
275*7c478bd9Sstevel@tonic-gate 			if (strcmp(mi->msg, msg)) {
276*7c478bd9Sstevel@tonic-gate 			src_err(file, line,
277*7c478bd9Sstevel@tonic-gate 		gettext("multiple messages: set number %d, message number %d\n"
278*7c478bd9Sstevel@tonic-gate 			"	current : \"%s\"\n"
279*7c478bd9Sstevel@tonic-gate 			"	previous: \"%s\" : \"%s\", line %d"),
280*7c478bd9Sstevel@tonic-gate 				si->id, mi->id,
281*7c478bd9Sstevel@tonic-gate 				msg,
282*7c478bd9Sstevel@tonic-gate 				mi->msg, mi->file, mi->line);
283*7c478bd9Sstevel@tonic-gate 			}
284*7c478bd9Sstevel@tonic-gate 			return (mi);
285*7c478bd9Sstevel@tonic-gate 		}
286*7c478bd9Sstevel@tonic-gate 		mi = mi->next;
287*7c478bd9Sstevel@tonic-gate 	}
288*7c478bd9Sstevel@tonic-gate 	return (NULL);
289*7c478bd9Sstevel@tonic-gate }
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate static void
292*7c478bd9Sstevel@tonic-gate add_msgid(SetID si, int msgid, char *msg, char *file, int line, int no_write)
293*7c478bd9Sstevel@tonic-gate {
294*7c478bd9Sstevel@tonic-gate 	MsgID mi = si->top, newmi, prev = NULL;
295*7c478bd9Sstevel@tonic-gate 	int len = strlen(msg);
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 	if (msgid == 0) {
298*7c478bd9Sstevel@tonic-gate 		src_err(file, line, gettext("improper message number: %d"),
299*7c478bd9Sstevel@tonic-gate 			msgid);
300*7c478bd9Sstevel@tonic-gate 		return;
301*7c478bd9Sstevel@tonic-gate 	}
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	if (msgid > NL_MSGMAX) {
304*7c478bd9Sstevel@tonic-gate 		src_err(file, line, gettext("too large message number: %d"),
305*7c478bd9Sstevel@tonic-gate 			msgid);
306*7c478bd9Sstevel@tonic-gate 		return;
307*7c478bd9Sstevel@tonic-gate 	}
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 	if (len > NL_TEXTMAX) {
310*7c478bd9Sstevel@tonic-gate 		src_err(file, line, gettext("too long message text"));
311*7c478bd9Sstevel@tonic-gate 		return;
312*7c478bd9Sstevel@tonic-gate 	}
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 	while (mi) {
315*7c478bd9Sstevel@tonic-gate 		if (mi->id > msgid) {
316*7c478bd9Sstevel@tonic-gate 			break;
317*7c478bd9Sstevel@tonic-gate 		}
318*7c478bd9Sstevel@tonic-gate 		prev = mi;
319*7c478bd9Sstevel@tonic-gate 		mi = mi->next;
320*7c478bd9Sstevel@tonic-gate 	}
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	if ((newmi = (MsgID) malloc(sizeof (MsgIDRec))) == NULL) {
323*7c478bd9Sstevel@tonic-gate 		prg_err(gettext("fatal: out of memory"));
324*7c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
325*7c478bd9Sstevel@tonic-gate 	}
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	newmi->no_write = no_write;
328*7c478bd9Sstevel@tonic-gate 	newmi->id = msgid;
329*7c478bd9Sstevel@tonic-gate 	newmi->msg = (char *) ustrdup(msg);
330*7c478bd9Sstevel@tonic-gate 	newmi->file = (char *) ustrdup(file);
331*7c478bd9Sstevel@tonic-gate 	newmi->line = line;
332*7c478bd9Sstevel@tonic-gate 	newmi->next = mi;
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	if (msg_comment) {
335*7c478bd9Sstevel@tonic-gate 		newmi->comment = (char *) ustrdup(msg_comment);
336*7c478bd9Sstevel@tonic-gate 		free(msg_comment);
337*7c478bd9Sstevel@tonic-gate 		msg_comment = NULL;
338*7c478bd9Sstevel@tonic-gate 	} else {
339*7c478bd9Sstevel@tonic-gate 		newmi->comment = NULL;
340*7c478bd9Sstevel@tonic-gate 	}
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 	if (prev == NULL) {
343*7c478bd9Sstevel@tonic-gate 		si->top = newmi;
344*7c478bd9Sstevel@tonic-gate 	} else {
345*7c478bd9Sstevel@tonic-gate 		prev->next = newmi;
346*7c478bd9Sstevel@tonic-gate 	}
347*7c478bd9Sstevel@tonic-gate }
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate static void
350*7c478bd9Sstevel@tonic-gate add_setid(int setid, int msgid, char *msg, char *file, int line, int no_write)
351*7c478bd9Sstevel@tonic-gate {
352*7c478bd9Sstevel@tonic-gate 	SetID si = setid_top, newsi, prev = NULL;
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	while (si) {
355*7c478bd9Sstevel@tonic-gate 		if (si->id > setid) {
356*7c478bd9Sstevel@tonic-gate 			break;
357*7c478bd9Sstevel@tonic-gate 		}
358*7c478bd9Sstevel@tonic-gate 		prev = si;
359*7c478bd9Sstevel@tonic-gate 		si = si->next;
360*7c478bd9Sstevel@tonic-gate 	}
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	if ((newsi = (SetID) malloc(sizeof (SetIDRec))) == NULL) {
363*7c478bd9Sstevel@tonic-gate 		prg_err(gettext("fatal: out of memory"));
364*7c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
365*7c478bd9Sstevel@tonic-gate 	}
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 	newsi->id = setid;
368*7c478bd9Sstevel@tonic-gate 	newsi->top = NULL;
369*7c478bd9Sstevel@tonic-gate 	newsi->next = si;
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 	if (set_comment) {
372*7c478bd9Sstevel@tonic-gate 		newsi->comment = (char *) ustrdup(set_comment);
373*7c478bd9Sstevel@tonic-gate 		free(set_comment);
374*7c478bd9Sstevel@tonic-gate 		set_comment = NULL;
375*7c478bd9Sstevel@tonic-gate 	} else {
376*7c478bd9Sstevel@tonic-gate 		newsi->comment = NULL;
377*7c478bd9Sstevel@tonic-gate 	}
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	if (prev == NULL) {
380*7c478bd9Sstevel@tonic-gate 		setid_top = newsi;
381*7c478bd9Sstevel@tonic-gate 	} else {
382*7c478bd9Sstevel@tonic-gate 		prev->next = newsi;
383*7c478bd9Sstevel@tonic-gate 	}
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	add_msgid(newsi, msgid, msg, file, line, no_write);
386*7c478bd9Sstevel@tonic-gate }
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate static void
389*7c478bd9Sstevel@tonic-gate print_prefix(FILE *fp, char *prefix, int rm_blank, char *str)
390*7c478bd9Sstevel@tonic-gate {
391*7c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "%s", prefix);
392*7c478bd9Sstevel@tonic-gate 	while (*str) {
393*7c478bd9Sstevel@tonic-gate 		(void) fputc(*str, fp);
394*7c478bd9Sstevel@tonic-gate 		if (*str == '\n' && *(str+1) != '\0') {
395*7c478bd9Sstevel@tonic-gate 			(void) fprintf(fp, "%s", prefix);
396*7c478bd9Sstevel@tonic-gate 			if (rm_blank == TRUE) {
397*7c478bd9Sstevel@tonic-gate 				str++;
398*7c478bd9Sstevel@tonic-gate 				SkipSpace(str);
399*7c478bd9Sstevel@tonic-gate 				continue;
400*7c478bd9Sstevel@tonic-gate 			}
401*7c478bd9Sstevel@tonic-gate 		}
402*7c478bd9Sstevel@tonic-gate 		str++;
403*7c478bd9Sstevel@tonic-gate 	}
404*7c478bd9Sstevel@tonic-gate 	if (*(str-1) != '\n') {
405*7c478bd9Sstevel@tonic-gate 		(void) fputc('\n', fp);
406*7c478bd9Sstevel@tonic-gate 	}
407*7c478bd9Sstevel@tonic-gate }
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate int
410*7c478bd9Sstevel@tonic-gate read_projfile(char *file)
411*7c478bd9Sstevel@tonic-gate {
412*7c478bd9Sstevel@tonic-gate 	FILE *fp;
413*7c478bd9Sstevel@tonic-gate 	char line[LINE_MAX];
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 	if (!file) {
416*7c478bd9Sstevel@tonic-gate 		return (0);
417*7c478bd9Sstevel@tonic-gate 	}
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(file, "r")) == NULL) {
420*7c478bd9Sstevel@tonic-gate 		return (0);
421*7c478bd9Sstevel@tonic-gate 	}
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 	while (fgets(line, LINE_MAX, fp) != NULL) {
424*7c478bd9Sstevel@tonic-gate 		char *p = line;
425*7c478bd9Sstevel@tonic-gate 		int n, setid, msgid;
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 		SkipSpace(p);
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 		if (*p == '#' || *p == '\n') {
430*7c478bd9Sstevel@tonic-gate 			continue;
431*7c478bd9Sstevel@tonic-gate 		}
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 		n = sscanf(p, "%d %d", &setid, &msgid);
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 		if (n == 2) {
436*7c478bd9Sstevel@tonic-gate 			if (setid > NL_SETMAX) {
437*7c478bd9Sstevel@tonic-gate 			prg_err(gettext("%s: too large set number: %d"),
438*7c478bd9Sstevel@tonic-gate 					file, setid);
439*7c478bd9Sstevel@tonic-gate 				continue;
440*7c478bd9Sstevel@tonic-gate 			}
441*7c478bd9Sstevel@tonic-gate 			msgid_table[setid] = msgid;
442*7c478bd9Sstevel@tonic-gate 		} else {
443*7c478bd9Sstevel@tonic-gate 			prg_err(
444*7c478bd9Sstevel@tonic-gate 			/* for stupid cstyle */
445*7c478bd9Sstevel@tonic-gate 			gettext("warning: %s: missing or invalid entry"),
446*7c478bd9Sstevel@tonic-gate 				file);
447*7c478bd9Sstevel@tonic-gate 		}
448*7c478bd9Sstevel@tonic-gate 	}
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 	return (1);
453*7c478bd9Sstevel@tonic-gate }
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate void
456*7c478bd9Sstevel@tonic-gate write_projfile(char *file)
457*7c478bd9Sstevel@tonic-gate {
458*7c478bd9Sstevel@tonic-gate 	FILE *fp;
459*7c478bd9Sstevel@tonic-gate 	register int i;
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 	if (is_writable(file) == FALSE) {
462*7c478bd9Sstevel@tonic-gate 		prg_err(gettext("cannot create \"%s\": permission denied"),
463*7c478bd9Sstevel@tonic-gate 			file);
464*7c478bd9Sstevel@tonic-gate 		return;
465*7c478bd9Sstevel@tonic-gate 	}
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(file, "w")) == NULL) {
468*7c478bd9Sstevel@tonic-gate 		prg_err(gettext("cannot create \"%s\""), file);
469*7c478bd9Sstevel@tonic-gate 		return;
470*7c478bd9Sstevel@tonic-gate 	}
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 	for (i = 1; i <= NL_SETMAX; i++) {
473*7c478bd9Sstevel@tonic-gate 		if (msgid_table[i] > 0) {
474*7c478bd9Sstevel@tonic-gate 			SetID si;
475*7c478bd9Sstevel@tonic-gate 			char *com = NULL;
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 			if (IsActiveMode(SetCommentMode) &&
478*7c478bd9Sstevel@tonic-gate 				(si = lookup_setid(i)) && si->comment) {
479*7c478bd9Sstevel@tonic-gate 				com = si->comment;
480*7c478bd9Sstevel@tonic-gate 			}
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 			if (com && !IsActiveMode(BackCommentMode)) {
483*7c478bd9Sstevel@tonic-gate 				print_prefix(fp, "# ", TRUE, com);
484*7c478bd9Sstevel@tonic-gate 			}
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 			(void) fprintf(fp, "%d\t%d\n", i, msgid_table[i]);
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 			if (com && IsActiveMode(BackCommentMode)) {
489*7c478bd9Sstevel@tonic-gate 				print_prefix(fp, "# ", TRUE, com);
490*7c478bd9Sstevel@tonic-gate 			}
491*7c478bd9Sstevel@tonic-gate 		}
492*7c478bd9Sstevel@tonic-gate 	}
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
495*7c478bd9Sstevel@tonic-gate }
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate int
498*7c478bd9Sstevel@tonic-gate get_msgid(char *file, int line, int setid, char *str)
499*7c478bd9Sstevel@tonic-gate {
500*7c478bd9Sstevel@tonic-gate 	SetID si = setid_top;
501*7c478bd9Sstevel@tonic-gate 	int id = msgid_table[setid];
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate 	while (si) {
504*7c478bd9Sstevel@tonic-gate 		if (si->id == setid) {
505*7c478bd9Sstevel@tonic-gate 			MsgID mi = si->top;
506*7c478bd9Sstevel@tonic-gate 			while (mi) {
507*7c478bd9Sstevel@tonic-gate 				if (strcmp(mi->msg, str) == 0) {
508*7c478bd9Sstevel@tonic-gate 					return (mi->id);
509*7c478bd9Sstevel@tonic-gate 				}
510*7c478bd9Sstevel@tonic-gate 				mi = mi->next;
511*7c478bd9Sstevel@tonic-gate 			}
512*7c478bd9Sstevel@tonic-gate 		}
513*7c478bd9Sstevel@tonic-gate 		si = si->next;
514*7c478bd9Sstevel@tonic-gate 	}
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 	id++;
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 	if (id > NL_MSGMAX) {
519*7c478bd9Sstevel@tonic-gate 		src_err(file, line,
520*7c478bd9Sstevel@tonic-gate 			gettext("run out of message number in set number: %d"),
521*7c478bd9Sstevel@tonic-gate 			setid);
522*7c478bd9Sstevel@tonic-gate 		return (NOMSGID);
523*7c478bd9Sstevel@tonic-gate 	}
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate 	return (msgid_table[setid] = id);
526*7c478bd9Sstevel@tonic-gate }
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate void
529*7c478bd9Sstevel@tonic-gate set_msgid(int setid, int msgid)
530*7c478bd9Sstevel@tonic-gate {
531*7c478bd9Sstevel@tonic-gate 	if (msgid_table[setid] < msgid) {
532*7c478bd9Sstevel@tonic-gate 		msgid_table[setid] = msgid;
533*7c478bd9Sstevel@tonic-gate 	}
534*7c478bd9Sstevel@tonic-gate }
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate void
537*7c478bd9Sstevel@tonic-gate add_comment(Mode mode, char *str)
538*7c478bd9Sstevel@tonic-gate {
539*7c478bd9Sstevel@tonic-gate 	char *tag = (mode == MsgCommentMode) ? mctag : sctag;
540*7c478bd9Sstevel@tonic-gate 	char **comment = (mode == MsgCommentMode)
541*7c478bd9Sstevel@tonic-gate 				? &msg_comment : &set_comment;
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 	if (!strstr(str, tag)) {
544*7c478bd9Sstevel@tonic-gate 		return;
545*7c478bd9Sstevel@tonic-gate 	}
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 	if (*comment) {
548*7c478bd9Sstevel@tonic-gate 		free(*comment);
549*7c478bd9Sstevel@tonic-gate 	}
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 	*comment = (char *) ustrdup(str);
552*7c478bd9Sstevel@tonic-gate }
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate void
555*7c478bd9Sstevel@tonic-gate read_msgfile(char *file)
556*7c478bd9Sstevel@tonic-gate {
557*7c478bd9Sstevel@tonic-gate 	FILE *fp;
558*7c478bd9Sstevel@tonic-gate 	char c = 0;
559*7c478bd9Sstevel@tonic-gate 	int line = 0;
560*7c478bd9Sstevel@tonic-gate 	int inmsg = FALSE;
561*7c478bd9Sstevel@tonic-gate 	int setid = 0, unsetid = -1, msgid = 0;
562*7c478bd9Sstevel@tonic-gate 	struct stat buf;
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(file, "r")) == NULL) {
565*7c478bd9Sstevel@tonic-gate 		prg_err(gettext("cannot open \"%s\""), file);
566*7c478bd9Sstevel@tonic-gate 		ResetActiveMode(AppendMode);
567*7c478bd9Sstevel@tonic-gate 		return;
568*7c478bd9Sstevel@tonic-gate 	}
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 	if (stat(file, &buf) == -1 && buf.st_size == 0) {
571*7c478bd9Sstevel@tonic-gate 		ResetActiveMode(AppendMode);
572*7c478bd9Sstevel@tonic-gate 		return;
573*7c478bd9Sstevel@tonic-gate 	}
574*7c478bd9Sstevel@tonic-gate 
575*7c478bd9Sstevel@tonic-gate 	quote = c;
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 	/*CONSTCOND*/
578*7c478bd9Sstevel@tonic-gate 	while (1) {
579*7c478bd9Sstevel@tonic-gate 		char buf[LINE_MAX];
580*7c478bd9Sstevel@tonic-gate 		char *ptr;
581*7c478bd9Sstevel@tonic-gate 		char msg[NL_TEXTMAX];
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 		if (fgets(buf, sizeof (buf), fp) == NULL) {
584*7c478bd9Sstevel@tonic-gate 			break;
585*7c478bd9Sstevel@tonic-gate 		}
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 		line++;
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 		ptr = &buf[0];
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 		SkipSpace(ptr);
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate 		if ((*ptr == '$' && (*(ptr+1) == ' ' || *(ptr+1) == '\t')) ||
594*7c478bd9Sstevel@tonic-gate 			((*ptr == '\n') && inmsg == FALSE)) {
595*7c478bd9Sstevel@tonic-gate 			inmsg = FALSE;
596*7c478bd9Sstevel@tonic-gate 			continue;
597*7c478bd9Sstevel@tonic-gate 		}
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 		if (strncmp(ptr, SET_TOKEN, sizeof (SET_TOKEN) - 1) == 0) {
600*7c478bd9Sstevel@tonic-gate 			if (sscanf(ptr, "%*s %d", &setid) != 1) {
601*7c478bd9Sstevel@tonic-gate 				setid = 0;
602*7c478bd9Sstevel@tonic-gate 			}
603*7c478bd9Sstevel@tonic-gate 			inmsg = FALSE;
604*7c478bd9Sstevel@tonic-gate 			continue;
605*7c478bd9Sstevel@tonic-gate 		} else if (strncmp(ptr, DELSET_TOKEN,
606*7c478bd9Sstevel@tonic-gate 			sizeof (DELSET_TOKEN) - 1) == 0) {
607*7c478bd9Sstevel@tonic-gate 			if (sscanf(ptr, "%*s %d", &unsetid) != 1) {
608*7c478bd9Sstevel@tonic-gate 				unsetid = -1;
609*7c478bd9Sstevel@tonic-gate 			}
610*7c478bd9Sstevel@tonic-gate 			inmsg = FALSE;
611*7c478bd9Sstevel@tonic-gate 			continue;
612*7c478bd9Sstevel@tonic-gate 		} else if (strncmp(ptr, QUOTE_TOKEN,
613*7c478bd9Sstevel@tonic-gate 			sizeof (QUOTE_TOKEN) - 1) == 0) {
614*7c478bd9Sstevel@tonic-gate 			if (sscanf(ptr, "%*s %c", &c) != 1) {
615*7c478bd9Sstevel@tonic-gate 				c = 0;
616*7c478bd9Sstevel@tonic-gate 			}
617*7c478bd9Sstevel@tonic-gate 			quote = c;
618*7c478bd9Sstevel@tonic-gate 			inmsg = FALSE;
619*7c478bd9Sstevel@tonic-gate 			continue;
620*7c478bd9Sstevel@tonic-gate 		}
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate 		if (setid == unsetid) {
623*7c478bd9Sstevel@tonic-gate 			continue;
624*7c478bd9Sstevel@tonic-gate 		}
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate 		if (inmsg) {
627*7c478bd9Sstevel@tonic-gate 			if (is_bs_terminated(ptr)) {
628*7c478bd9Sstevel@tonic-gate 				(void) strcat(msg, ptr);
629*7c478bd9Sstevel@tonic-gate 				inmsg = TRUE;
630*7c478bd9Sstevel@tonic-gate 			} else {
631*7c478bd9Sstevel@tonic-gate 				int len = strlen(ptr);
632*7c478bd9Sstevel@tonic-gate 				*(ptr + len - 1) = '\0';
633*7c478bd9Sstevel@tonic-gate 				if (c && (*(ptr + len - 2) == c)) {
634*7c478bd9Sstevel@tonic-gate 					*(ptr + len - 2) = '\0';
635*7c478bd9Sstevel@tonic-gate 				}
636*7c478bd9Sstevel@tonic-gate 				(void) strcat(msg, ptr);
637*7c478bd9Sstevel@tonic-gate 				add_msg(setid, msgid, msg, file, line, TRUE);
638*7c478bd9Sstevel@tonic-gate 				inmsg = FALSE;
639*7c478bd9Sstevel@tonic-gate 			}
640*7c478bd9Sstevel@tonic-gate 			continue;
641*7c478bd9Sstevel@tonic-gate 		}
642*7c478bd9Sstevel@tonic-gate 
643*7c478bd9Sstevel@tonic-gate 		if (isdigit(*ptr)) {
644*7c478bd9Sstevel@tonic-gate 			char tmp[32];
645*7c478bd9Sstevel@tonic-gate 			int i = 0;
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 			SkipSpace(ptr);
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 			while (isdigit(*ptr)) {
650*7c478bd9Sstevel@tonic-gate 				tmp[i++] = *ptr++;
651*7c478bd9Sstevel@tonic-gate 			}
652*7c478bd9Sstevel@tonic-gate 			tmp[i] = '\0';
653*7c478bd9Sstevel@tonic-gate 			msgid = atoi(tmp);
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 			SkipSpace(ptr);
656*7c478bd9Sstevel@tonic-gate 
657*7c478bd9Sstevel@tonic-gate 			if (is_bs_terminated(ptr)) {
658*7c478bd9Sstevel@tonic-gate 				(void) memset(msg, 0, NL_TEXTMAX);
659*7c478bd9Sstevel@tonic-gate 				if (c && (*ptr == c)) {
660*7c478bd9Sstevel@tonic-gate 					ptr++;
661*7c478bd9Sstevel@tonic-gate 				}
662*7c478bd9Sstevel@tonic-gate 				(void) strcpy(msg, ptr);
663*7c478bd9Sstevel@tonic-gate 				inmsg = TRUE;
664*7c478bd9Sstevel@tonic-gate 			} else {
665*7c478bd9Sstevel@tonic-gate 				int len = strlen(ptr);
666*7c478bd9Sstevel@tonic-gate 				*(ptr + len - 1) = '\0';
667*7c478bd9Sstevel@tonic-gate 				if (c && ((*ptr == c) &&
668*7c478bd9Sstevel@tonic-gate 					(*(ptr + len - 2) == c))) {
669*7c478bd9Sstevel@tonic-gate 					*(ptr + len - 2) = '\0';
670*7c478bd9Sstevel@tonic-gate 					ptr++;
671*7c478bd9Sstevel@tonic-gate 				}
672*7c478bd9Sstevel@tonic-gate 				add_msg(setid, msgid, ptr, file, line, TRUE);
673*7c478bd9Sstevel@tonic-gate 				inmsg = FALSE;
674*7c478bd9Sstevel@tonic-gate 			}
675*7c478bd9Sstevel@tonic-gate 		}
676*7c478bd9Sstevel@tonic-gate 	}
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
679*7c478bd9Sstevel@tonic-gate }
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate static int
682*7c478bd9Sstevel@tonic-gate is_bs_terminated(char *msg)
683*7c478bd9Sstevel@tonic-gate {
684*7c478bd9Sstevel@tonic-gate 	int len = strlen(msg);
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate 	while (--len >= 0) {
687*7c478bd9Sstevel@tonic-gate 		if (msg[len] == ' ' || msg[len] == '\t' || msg[len] == '\n') {
688*7c478bd9Sstevel@tonic-gate 			continue;
689*7c478bd9Sstevel@tonic-gate 		} else if (msg[len] == '\\') {
690*7c478bd9Sstevel@tonic-gate 			len--;
691*7c478bd9Sstevel@tonic-gate 			if (len >= 0 && msg[len] == '\\')
692*7c478bd9Sstevel@tonic-gate 				return (0);
693*7c478bd9Sstevel@tonic-gate 			return (1);
694*7c478bd9Sstevel@tonic-gate 		} else {
695*7c478bd9Sstevel@tonic-gate 			return (0);
696*7c478bd9Sstevel@tonic-gate 		}
697*7c478bd9Sstevel@tonic-gate 	}
698*7c478bd9Sstevel@tonic-gate 	return (0);
699*7c478bd9Sstevel@tonic-gate }
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate static char *
702*7c478bd9Sstevel@tonic-gate ustrdup(char *str)
703*7c478bd9Sstevel@tonic-gate {
704*7c478bd9Sstevel@tonic-gate 	char *tmp = strdup(str);
705*7c478bd9Sstevel@tonic-gate 	if (!tmp) {
706*7c478bd9Sstevel@tonic-gate 		prg_err(gettext("fatal: out of memory"));
707*7c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
708*7c478bd9Sstevel@tonic-gate 	}
709*7c478bd9Sstevel@tonic-gate 	return (tmp);
710*7c478bd9Sstevel@tonic-gate }
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate int
713*7c478bd9Sstevel@tonic-gate file_copy(char *in, char *out)
714*7c478bd9Sstevel@tonic-gate {
715*7c478bd9Sstevel@tonic-gate 	int ret = TRUE;
716*7c478bd9Sstevel@tonic-gate 	FILE *fin, *fout;
717*7c478bd9Sstevel@tonic-gate 	int c;
718*7c478bd9Sstevel@tonic-gate 	sigset_t newmask, oldmask;
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&newmask);
721*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&newmask, SIGQUIT);
722*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&newmask, SIGINT);
723*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&newmask, SIGHUP);
724*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&newmask, SIGTERM);
725*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &newmask, &oldmask);
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 	if ((fin = fopen(in, "r")) == NULL) {
728*7c478bd9Sstevel@tonic-gate 		prg_err(gettext("cannot open \"%s\""), in);
729*7c478bd9Sstevel@tonic-gate 		ret = FALSE;
730*7c478bd9Sstevel@tonic-gate 		goto done;
731*7c478bd9Sstevel@tonic-gate 	}
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate 	if ((fout = fopen(out, "w")) == NULL) {
734*7c478bd9Sstevel@tonic-gate 		prg_err(gettext("cannot create \"%s\""), out);
735*7c478bd9Sstevel@tonic-gate 		ret = FALSE;
736*7c478bd9Sstevel@tonic-gate 		goto done;
737*7c478bd9Sstevel@tonic-gate 	}
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate 	while ((c = getc(fin)) != EOF)
740*7c478bd9Sstevel@tonic-gate 		(void) putc(c, fout);
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate 	(void) fclose(fin);
743*7c478bd9Sstevel@tonic-gate 	(void) fclose(fout);
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate done:
746*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &oldmask, NULL);
747*7c478bd9Sstevel@tonic-gate 	return (ret);
748*7c478bd9Sstevel@tonic-gate }
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate static void
751*7c478bd9Sstevel@tonic-gate cat_msg(char *out, char *msg, int max)
752*7c478bd9Sstevel@tonic-gate {
753*7c478bd9Sstevel@tonic-gate 	if (strlen(out) > max) {
754*7c478bd9Sstevel@tonic-gate 		return;
755*7c478bd9Sstevel@tonic-gate 	}
756*7c478bd9Sstevel@tonic-gate 
757*7c478bd9Sstevel@tonic-gate 	(void) strncat(out, msg, max);
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate 	if (strlen(out) > max) {
760*7c478bd9Sstevel@tonic-gate 		out[max] = '\0';
761*7c478bd9Sstevel@tonic-gate 	}
762*7c478bd9Sstevel@tonic-gate }
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate static void
765*7c478bd9Sstevel@tonic-gate makeup_msg(char **pmsg)
766*7c478bd9Sstevel@tonic-gate {
767*7c478bd9Sstevel@tonic-gate 	char buf[NL_TEXTMAX];
768*7c478bd9Sstevel@tonic-gate 	char *msg;
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate 	msg = *pmsg;
771*7c478bd9Sstevel@tonic-gate 	(void) memset((void *) buf, 0, NL_TEXTMAX);
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate 	if (IsActiveMode(TripleMode) &&	!strchr(msg, '%')) {
774*7c478bd9Sstevel@tonic-gate 		/* there is no '%' in message. */
775*7c478bd9Sstevel@tonic-gate 		int len = strlen(msg);
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate 		if (msg[len-2] == '\\' && msg[len-1] == 'n') {
778*7c478bd9Sstevel@tonic-gate 			msg[len-2] = '\0';
779*7c478bd9Sstevel@tonic-gate 			cat_msg(buf, msg, (NL_TEXTMAX - 2));
780*7c478bd9Sstevel@tonic-gate 			cat_msg(buf, msg, (NL_TEXTMAX - 2));
781*7c478bd9Sstevel@tonic-gate 			cat_msg(buf, msg, (NL_TEXTMAX - 2));
782*7c478bd9Sstevel@tonic-gate 			cat_msg(buf, "\\n", NL_TEXTMAX);
783*7c478bd9Sstevel@tonic-gate 		} else {
784*7c478bd9Sstevel@tonic-gate 			cat_msg(buf, msg, NL_TEXTMAX);
785*7c478bd9Sstevel@tonic-gate 			cat_msg(buf, msg, NL_TEXTMAX);
786*7c478bd9Sstevel@tonic-gate 			cat_msg(buf, msg, NL_TEXTMAX);
787*7c478bd9Sstevel@tonic-gate 		}
788*7c478bd9Sstevel@tonic-gate 		free(msg);
789*7c478bd9Sstevel@tonic-gate 		*pmsg = (char *) ustrdup(buf);
790*7c478bd9Sstevel@tonic-gate 	}
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	msg = *pmsg;
793*7c478bd9Sstevel@tonic-gate 	(void) memset((void *) buf, 0, NL_TEXTMAX);
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate 	if (IsActiveMode(PrefixMode)) {
796*7c478bd9Sstevel@tonic-gate 		cat_msg(buf, premsg, NL_TEXTMAX);
797*7c478bd9Sstevel@tonic-gate 		cat_msg(buf, msg, NL_TEXTMAX);
798*7c478bd9Sstevel@tonic-gate 		free(msg);
799*7c478bd9Sstevel@tonic-gate 		*pmsg = (char *) ustrdup(buf);
800*7c478bd9Sstevel@tonic-gate 	}
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 	msg = *pmsg;
803*7c478bd9Sstevel@tonic-gate 	(void) memset((void *) buf, 0, NL_TEXTMAX);
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate 	if (IsActiveMode(SuffixMode)) {
806*7c478bd9Sstevel@tonic-gate 		int len = strlen(msg);
807*7c478bd9Sstevel@tonic-gate 
808*7c478bd9Sstevel@tonic-gate 		if (msg[len-2] == '\\' && msg[len-1] == 'n') {
809*7c478bd9Sstevel@tonic-gate 			msg[len-2] = '\0';
810*7c478bd9Sstevel@tonic-gate 			cat_msg(buf, msg, (NL_TEXTMAX - 2));
811*7c478bd9Sstevel@tonic-gate 			cat_msg(buf, sufmsg, (NL_TEXTMAX - 2));
812*7c478bd9Sstevel@tonic-gate 			cat_msg(buf, "\\n", NL_TEXTMAX);
813*7c478bd9Sstevel@tonic-gate 		} else {
814*7c478bd9Sstevel@tonic-gate 			cat_msg(buf, msg, NL_TEXTMAX);
815*7c478bd9Sstevel@tonic-gate 			cat_msg(buf, sufmsg, NL_TEXTMAX);
816*7c478bd9Sstevel@tonic-gate 		}
817*7c478bd9Sstevel@tonic-gate 		free(msg);
818*7c478bd9Sstevel@tonic-gate 		*pmsg = (char *) ustrdup(buf);
819*7c478bd9Sstevel@tonic-gate 	}
820*7c478bd9Sstevel@tonic-gate }
821*7c478bd9Sstevel@tonic-gate 
822*7c478bd9Sstevel@tonic-gate void
823*7c478bd9Sstevel@tonic-gate prg_err(char *fmt, ...)
824*7c478bd9Sstevel@tonic-gate {
825*7c478bd9Sstevel@tonic-gate 	va_list ap;
826*7c478bd9Sstevel@tonic-gate 	char buf[BUFSIZ];
827*7c478bd9Sstevel@tonic-gate 
828*7c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
829*7c478bd9Sstevel@tonic-gate 
830*7c478bd9Sstevel@tonic-gate 	(void) vsprintf(buf, fmt, ap);
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s: %s\n", program, buf);
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 	va_end(ap);
835*7c478bd9Sstevel@tonic-gate }
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate void
838*7c478bd9Sstevel@tonic-gate src_err(char *file, int line, char *fmt, ...)
839*7c478bd9Sstevel@tonic-gate {
840*7c478bd9Sstevel@tonic-gate 	va_list ap;
841*7c478bd9Sstevel@tonic-gate 	char buf[BUFSIZ];
842*7c478bd9Sstevel@tonic-gate 	char sbuf[BUFSIZ/2];
843*7c478bd9Sstevel@tonic-gate 	char vbuf[BUFSIZ/2];
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate 	if (suppress_error == TRUE) {
846*7c478bd9Sstevel@tonic-gate 		return;
847*7c478bd9Sstevel@tonic-gate 	}
848*7c478bd9Sstevel@tonic-gate 
849*7c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
850*7c478bd9Sstevel@tonic-gate 
851*7c478bd9Sstevel@tonic-gate 	(void) sprintf(sbuf, gettext("\"%s\", line %d: "), file, line);
852*7c478bd9Sstevel@tonic-gate 	(void) vsprintf(vbuf, fmt, ap);
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate 	(void) sprintf(buf, "%s%s\n", sbuf, vbuf);
855*7c478bd9Sstevel@tonic-gate 	(void) fputs(buf, stderr);
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 	va_end(ap);
858*7c478bd9Sstevel@tonic-gate }
859