1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                 Glenn Fowler <gsf@research.att.com>                  *
18*                  David Korn <dgk@research.att.com>                   *
19*                   Phong Vo <kpv@research.att.com>                    *
20*                                                                      *
21***********************************************************************/
22#pragma prototyped
23/*
24 * fmtmsg implementation
25 */
26
27#include <ast.h>
28
29#if _lib_fmtmsg
30
31NoN(fmtmsg)
32
33#else
34
35#define MM_TABLES
36
37#include <fmtmsg.h>
38
39#define INIT_VERB	0x1
40#define INIT_CONSOLE	0x2
41
42static struct
43{
44	int		console;
45	unsigned int	init;
46	unsigned int	mask;
47} mm;
48
49const MM_table_t	mm_class[] =
50{
51	"null",		0,		0,
52	"hard",		"HARDWARE",	MM_HARD,
53	"soft",		"SOFTWARE",	MM_SOFT,
54	"firm",		"FIRMWARE",	MM_FIRM,
55	"appl",		"APPLICATION",	MM_APPL,
56	"util",		"UTILITY",	MM_UTIL,
57	"opsys",	"KERNEL",	MM_OPSYS,
58	"print",	0,		MM_PRINT,
59	"console",	0,		MM_CONSOLE,
60	"recov",	"RECOVERABLE",	MM_RECOVER,
61	"nrecov",	"PANIC",	MM_NRECOV,
62	0,		0,		0
63};
64
65static const MM_table_t	mm_severity_init[] =
66{
67	"nosev",	0,		MM_NOSEV,
68	"halt",		"HALT",		MM_HALT,
69	"error",	"ERROR",	MM_ERROR,
70	"warn",		"WARNING",	MM_WARNING,
71	"info",		"INFO",		MM_INFO,
72	0,		0,		0
73};
74
75const MM_table_t	mm_verb[] =
76{
77	"all",		0,		MM_all,
78	"action",	0,		MM_action,
79	"class",	0,		MM_class,
80	"default",	0,		MM_default,
81	"label",	0,		MM_label,
82	"severity",	0,		MM_severity,
83	"source",	0,		MM_source,
84	"tag",		0,		MM_tag,
85	"text",		0,		MM_text,
86	0,		0,		0
87};
88
89const MM_table_t*
90_mm_severity(void)
91{
92	static MM_table_t*	severity;
93
94	if (!severity)
95	{
96		register char*		s;
97		register MM_table_t*	p;
98		register int		n;
99		register int		c;
100		char*			e;
101		MM_table_t*		q;
102
103		n = 0;
104		if ((s = getenv(MM_SEVERITY_ENV)) && *s)
105		{
106			e = s;
107			c = 0;
108			for (;;)
109			{
110				switch (*s++)
111				{
112				case 0:
113					break;
114				case ',':
115					if (++c > 2)
116					{
117						n = 0;
118						break;
119					}
120					continue;
121				case ':':
122					if (c != 2)
123					{
124						n = 0;
125						break;
126					}
127					c = 0;
128					n++;
129					continue;
130				default:
131					continue;
132				}
133				break;
134			}
135			if (c == 2)
136				n++;
137			else n = 0;
138			if (n)
139			{
140				for (p = (MM_table_t*)mm_severity_init; p->name; p++);
141				n += p - (MM_table_t*)mm_severity_init + 1;
142				if (severity = newof(0, MM_table_t, n, s - e))
143				{
144					s = (char*)severity + n * sizeof(MM_table_t);
145					strcpy(s, e);
146					p = severity;
147					for (q = (MM_table_t*)mm_severity_init; q->name; q++)
148						*p++ = *q;
149					p->name = s;
150					c = 0;
151					for (;;)
152					{
153						switch (*s++)
154						{
155						case 0:
156							break;
157						case ',':
158							switch (c++)
159							{
160							case 0:
161								*(s - 1) = 0;
162								p->value = strtol(s, NiL, 0);
163								break;
164							case 1:
165								p->display = s;
166								break;
167							}
168							continue;
169						case ':':
170							c = 0;
171							*(s - 1) = 0;
172							(++p)->name = s;
173							continue;
174						default:
175							continue;
176						}
177						break;
178					}
179				}
180			}
181		}
182		if (!severity)
183			severity = (MM_table_t*)mm_severity_init;
184	}
185	return (const MM_table_t*)severity;
186}
187
188static char*
189display(register const MM_table_t* tab, int value, int mask)
190{
191	while (tab->name)
192	{
193		if (value == tab->value || mask && (value & tab->value))
194			return (char*)tab->display;
195		tab++;
196	}
197	return 0;
198}
199
200int
201fmtmsg(long classification, const char* label, int severity, const char* text, const char* action, const char* tag)
202{
203	register int		c;
204	register char*		s;
205	register char*		t;
206	register MM_table_t*	p;
207	int			n;
208	int			m;
209	int			r;
210	int			fd;
211	unsigned int		mask;
212	Sfio_t*			sp;
213	char			lab[MM_LABEL_1_MAX + MM_LABEL_2_MAX + 3];
214
215	if (!mm.init)
216	{
217		mm.init = INIT_VERB;
218		if (!(s = getenv(MM_VERB_ENV)))
219			mm.mask = MM_default;
220		else for (;;)
221		{
222			if (t = strchr(s, ':'))
223				*t = 0;
224			if (!(p = (MM_table_t*)strlook(mm_verb, sizeof(MM_table_t), s)))
225			{
226				mm.mask = MM_default;
227				if (t)
228					*t = ':';
229				break;
230			}
231			mm.mask |= p->value;
232			if (!t)
233				break;
234			*t++ = ':';
235			s = t;
236		}
237	}
238	if (!(classification & (MM_CONSOLE|MM_PRINT)))
239		return 0;
240	if (!(sp = sfstropen()))
241		return MM_NOTOK;
242	r = 0;
243	if (s = (char*)label)
244	{
245		if (t = strchr(s, ':'))
246		{
247			if ((n = t - s) > MM_LABEL_1_MAX)
248				n = MM_LABEL_1_MAX;
249			sfprintf(sp, "%*.*s:", n, n, s);
250			s = ++t;
251			if ((n = strlen(t)) > MM_LABEL_2_MAX)
252				n = MM_LABEL_2_MAX;
253			sfprintf(sp, "%*.*s", n, n, s);
254		}
255		else
256		{
257			if ((n = strlen(t)) > MM_LABEL_1_MAX)
258				n = MM_LABEL_1_MAX;
259			sfprintf(sp, "%*.*s", n, n, s);
260		}
261		if (!(s = sfstruse(sp)))
262		{
263			sfstrclose(sp);
264			return MM_NOTOK;
265		}
266		strcpy(lab, s);
267	}
268	for (;;)
269	{
270		if (classification & MM_CONSOLE)
271		{
272			classification &= ~MM_CONSOLE;
273			if (!(mm.init & INIT_CONSOLE))
274				mm.console = open("/dev/console", O_WRONLY|O_APPEND|O_NOCTTY);
275			if (mm.console < 0)
276			{
277				r |= MM_NOCON;
278				continue;
279			}
280			c = MM_NOCON;
281			fd = mm.console;
282			mask = MM_all;
283		}
284		else if (classification & MM_PRINT)
285		{
286			classification &= ~MM_PRINT;
287			c = MM_NOMSG;
288			fd = 2;
289			mask = mm.mask;
290		}
291		else break;
292		if ((mask & MM_label) && label)
293			sfprintf(sp, "%s: ", lab);
294		if ((mask & MM_severity) && (s = display(mm_severity, severity, 0)))
295			sfprintf(sp, "%s: ", s);
296		n = sfstrtell(sp);
297		if ((mask & MM_text) && text)
298			sfprintf(sp, "%s\n", text);
299		else sfputc(sp, '\n');
300		if ((mask & MM_action) && action || (mask & MM_tag) && (label || tag))
301		{
302			if (fd != mm.console && (n -= 8) > 0)
303				sfprintf(sp, "%*.*s", n, n, "");
304			sfprintf(sp, "TO FIX:");
305			if ((mask & MM_action) && action)
306				sfprintf(sp, " %s", action);
307			if ((mask & MM_tag) && (label || tag))
308			{
309				sfprintf(sp, "  ");
310				if (!tag || label && !strchr(tag, ':'))
311					sfprintf(sp, "%s%s", lab, tag ? ":" : "");
312				if (tag)
313					sfprintf(sp, "%s", tag);
314			}
315			if (mask & (MM_class|MM_source|MM_status))
316			{
317				sfputc(sp, ' ');
318				if ((mask & MM_source) && (m = classification & (MM_APPL|MM_UTIL|MM_OPSYS)) && (s = display(mm_class, m, 1)))
319					sfprintf(sp, " %s", s);
320				if ((mask & MM_class) && (m = classification & (MM_HARD|MM_SOFT|MM_FIRM)) && (s = display(mm_class, m, 1)))
321					sfprintf(sp, " %s", s);
322				if ((mask & MM_status) && (m = classification & (MM_RECOVER|MM_NRECOV)) && (s = display(mm_class, m, 1)))
323					sfprintf(sp, " %s", s);
324			}
325			sfputc(sp, '\n');
326		}
327		n = sfstrtell(sp);
328		if (!(s = sfstruse(sp)) || write(fd, s, n) != n)
329			r |= c;
330	}
331	sfstrclose(sp);
332	return r;
333}
334
335#endif
336