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