8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libc / port / gen / fmtmsg.c
blob08ada435ce31aa14143b709912f0d456445f6001
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
30 #pragma ident "%Z%%M% %I% %E% SMI"
33 * fmtmsg.c
35 * Contains:
36 * fmtmsg() Writes a message in standard format.
37 * addseverity() Adds a severity definition to the list of known
38 * severity definitions.
40 * Notes:
41 * - None of these functions can use strtok().
45 * Header Files Referenced:
46 * <stdio.h> C Standard I/O Definitions
47 * <string.h> C string handling definitions
48 * <fcntl.h> UNIX file control definitions
49 * <errno.h> UNIX error numbers and definitions
50 * <fmtmsg.h> Global definitions for fmtmsg()
51 * <stdlib.h> miscellaneous function declarations
54 #pragma weak _fmtmsg = fmtmsg
55 #pragma weak _addseverity = addseverity
57 #include "lint.h"
58 #include "mtlib.h"
59 #include "libc.h"
60 #include <sys/types.h>
61 #include <stddef.h>
62 #include <stdio.h>
63 #include <string.h>
64 #include <fcntl.h>
65 #include <errno.h>
66 #include <fmtmsg.h>
67 #include <stdlib.h>
68 #include <thread.h>
69 #include <synch.h>
70 #include <alloca.h>
73 * External functions referenced:
74 * (Others may be defined in header files above)
76 * getenv Extracts data from the environment
77 * libc_malloc Allocates space from main memory
78 * libc_free Frees space allocated via libc_malloc()
79 * strtol Convert string to "long"
80 * clearerr Clears an error on a stream (this is to make "lint"
81 * happy)
86 * Local Constant Definitions
90 * Boolean constants
91 * TRUE Boolean value for "true" (any bits on)
92 * FALSE Boolean value for "false" (all bits off)
95 #ifndef FALSE
96 #define FALSE (0)
97 #endif
99 #ifndef TRUE
100 #define TRUE (1)
101 #endif
103 #define MAX_MSG_SIZE 1024
106 * Keywords for fields named in the MSGVERB environment variable.
109 #define ST_LBL "label"
110 #define ST_SEV "severity"
111 #define ST_TXT "text"
112 #define ST_TAG "tag"
113 #define ST_ACT "action"
117 * The following constants define the value of the "msgverb"
118 * variable. This variable tells fmtmsg() which parts of the
119 * standard message it is to display. If !(msgverb&MV_SET),
120 * fmtmsg() will interrogate the "MSGVERB" environment variable
121 * and set "msgverb" accordingly.
123 * NOTE: This means that if MSGVERB changes after the first call
124 * to fmtmsg(), it will be ignored.
126 * Constants:
127 * MV_INV Check MSGVERB environment variable (invalidates value)
128 * MV_SET MSGVERB checked, msgverb value valid
129 * MV_LBL "label" selected
130 * MV_SEV "severity" selected
131 * MV_TXT "text" selected
132 * MV_TAG "messageID" selected
133 * MV_ACT "action" selected
135 * MV_ALL All components selected
136 * MV_DFLT Default value for MSGVERB
139 #define MV_INV 0
140 #define MV_SET 0x0001
141 #define MV_LBL 0x0002
142 #define MV_SEV 0x0004
143 #define MV_TXT 0x0008
144 #define MV_TAG 0x0010
145 #define MV_ACT 0x0020
147 #define MV_ALL (MV_LBL|MV_SEV|MV_TXT|MV_TAG|MV_ACT)
148 #define MV_DFLT (MV_LBL|MV_SEV|MV_TXT|MV_TAG|MV_ACT)
153 * Strings defining the different severities of a message.
154 * Internationalization may demand that these come from the message database
157 #define SV_UNK "UNKNOWN"
158 #define SV_HALT "HALT"
159 #define SV_ERROR "ERROR"
160 #define SV_WARN "WARNING"
161 #define SV_INF "INFO"
165 * Text string if none is provided:
168 #define DEFLT_TEXT "No text provided with this message"
172 * Text string introduction for "action". This may have to come from
173 * the message database because of internationalization.
176 #define ACTINTRO "TO FIX: "
177 #define ACTINTROLN 8
181 * SEPSTR is the string that separates the "label" from what follows it,
182 * and the severity from what follows it.
185 #define SEPSTR ": "
186 #define SEPSTRLN 2
190 * Miscellaneous constants:
191 * CONNAME Filesystem entry name for the system console
194 #define CONNAME "/dev/console"
197 * Local data type definitions
201 * Severity string structure
203 * struct sevstr
204 * sevvalue Value of the severity-level being defined
205 * sevkywd Keyword identifying the severity
206 * sevprptr Pointer to the string associated with the value
207 * sevnext Pointer to the next value in the list.
209 * Restrictions:
210 * sevvalue Must be a non-negative integer (>=0)
212 * There are three (possibly null) lists of these structures.
213 * 1) is the list of standard severities
214 * 2) is the list of severity-levels defined by SEV_LEVEL
215 * 3) is the list of severity-levels defined by calls to
216 * addseverity()
219 struct sevstr {
220 int sevvalue;
221 const char *sevkywd;
222 const char *sevprstr;
223 struct sevstr *sevnext;
227 * Local Static Data
228 * msgverb int
229 * Contains the internal representation or the
230 * MSGVERB environment variable.
231 * sevlook TRUE if fmtmsg() has to look at SEV_LEVEL the
232 * next time it is called.
233 * paugsevs struct sevstr *
234 * Head of the linked list of structures that define
235 * severities that augment the standard severities,
236 * as defined by addseverity().
237 * penvsevs struct sevstrs *
238 * Head of the linked list of structures that define
239 * severities that augment the standard severities,
240 * as defined by SEV_LEVEL.
241 * pstdsevs struct sevstrs *
242 * Head of the linked list of structures that define
243 * the standard severities.
246 static mutex_t fmt_lock = DEFAULTMUTEX;
248 static int msgverb = 0;
249 static int sevlook = TRUE;
251 static struct sevstr *paugsevs = (struct sevstr *)NULL;
252 static struct sevstr *penvsevs = (struct sevstr *)NULL;
254 static struct sevstr sevstrs[] = {
255 { MM_HALT, "", SV_HALT, &sevstrs[1]},
256 { MM_ERROR, "", SV_ERROR, &sevstrs[2]},
257 { MM_WARNING, "", SV_WARN, &sevstrs[3]},
258 { MM_INFO, "", SV_INF, (struct sevstr *)NULL},
260 static struct sevstr *pstdsevs = &sevstrs[0];
263 * static char *exttok(str, delims)
264 * const char *str
265 * const char *delims
267 * This function examines the string pointed to by "str", looking
268 * for the first occurrence of any of the characters in the string
269 * whose address is "delims". It returns the address of that
270 * character or (char *)NULL if there was nothing to search.
272 * Arguments:
273 * str Address of the string to search
274 * delims Address of the string containing delimiters
276 * Returns: char *
277 * Returns the address of the first occurrence of any of the characters
278 * in "delim" in the string "str" (incl '\0'). If there was nothing
279 * to search, the function returns (char *)NULL.
281 * Notes:
282 * - This function is needed because strtok() can't be used inside a
283 * function. Besides, strtok() is destructive in the string, which
284 * is undesirable in many circumstances.
285 * - This function understands escaped delimiters as non-delimiters.
286 * Delimiters are escaped by preceding them with '\' characters.
287 * The '\' character also must be escaped.
290 static char *
291 exttok(const char *tok, const char *delims)
293 char *tokend; /* Ptr to the end of the token */
294 char *p, *q; /* Temp pointers */
297 * Algorithm:
298 * 1. Get the starting address(new string or where we
299 * left off). If nothing to search, return(char *)NULL
300 * 2. Find the end of the string
301 * 3. Look for the first unescaped delimiter closest to the
302 * beginning of the string
303 * 4. Remember where we left off
304 * 5. Return a pointer to the delimiter we found
307 /* Begin at the beginning, if any */
308 if (tok == (char *)NULL) {
309 return ((char *)NULL);
312 /* Find end of the token string */
313 tokend = (char *)tok + (ptrdiff_t)strlen(tok);
315 /* Look for the 1st occurrence of any delimiter */
316 for (p = (char *)delims; *p != '\0'; p++) {
317 for (q = strchr(tok, (int)*p);
318 (q != 0) && (q != tok) && (*(q - (ptrdiff_t)1) == '\\');
319 q = strchr(q + (ptrdiff_t)1, (int)*p))
321 if ((q != 0) && (q < tokend))
322 tokend = q;
325 /* Done */
326 return (tokend);
330 * char *noesc(str)
332 * This function squeezes out all of the escaped character sequences
333 * from the string <str>. It returns a pointer to that string.
335 * Arguments:
336 * str char *
337 * The string that is to have its escaped characters removed.
339 * Returns: char *
340 * This function returns its argument <str> always.
342 * Notes:
343 * This function potentially modifies the string it is given.
346 static char *
347 noesc(char *str)
349 char *p; /* Temp string pointer */
350 char *q; /* Temp string pointer */
352 /* Look for an escaped character */
353 p = str;
354 while (*p && (*p != '\\')) p++;
358 * If there was at least one, squeeze them out
359 * Otherwise, don't touch the argument string
362 if (*p) {
363 q = p++;
364 while (*q++ = *p++) {
365 if (*p == '\\')
366 p++;
370 /* Finished. Return our argument */
371 return (str);
375 * struct sevstr *getauxsevs(ptr)
377 * Parses a string that is in the format of the severity definitions.
378 * Returns a pointer to a (malloc'd) structure that contains the
379 * definition, or (struct sevstr *)NULL if none was parsed.
381 * Arguments:
382 * ptr char *
383 * References the string from which data is to be extracted.
384 * If (char *)NULL, continue where we left off. Otherwise,
385 * start with the string referenced by ptr.
387 * Returns: struct sevstr *
388 * A pointer to a malloc'd structure containing the severity definition
389 * parsed from string, or (struct sevstr *)NULL if none.
391 * Notes:
392 * - This function is destructive to the string referenced by its argument.
395 /* Static data */
396 static char *leftoff = (char *)NULL;
398 static struct sevstr *
399 getauxsevs(char *ptr)
401 char *current; /* Ptr to current sev def'n */
402 char *tokend; /* Ptr to end of current sev def'n */
403 char *kywd; /* Ptr to extracted kywd */
404 char *valstr; /* Ptr to extracted sev value */
405 char *prstr; /* Ptr to extracted print str */
406 char *p; /* Temp pointer */
407 int val; /* Converted severity value */
408 int done; /* Flag, sev def'n found and ok? */
409 struct sevstr *rtnval; /* Value to return */
412 /* Start anew or start where we left off? */
413 current = (ptr == (char *)NULL) ? leftoff : ptr;
416 /* If nothing to parse, return (char *)NULL */
417 if (current == (char *)NULL) {
418 return ((struct sevstr *)NULL);
423 * Look through the string "current" for a token of the form
424 * <kywd>,<sev>,<printstring> delimited by ':' or '\0'
427 /* Loop initializations */
428 done = FALSE;
429 rtnval = (struct sevstr *)NULL;
430 while (!done) {
431 /* Eat leading junk */
432 while (*(tokend = exttok(current, ":,")) == ':') {
433 current = tokend + (ptrdiff_t)1;
436 /* If we've found a <kywd>,... */
437 if (*tokend == ',') {
438 kywd = current;
439 *tokend = '\0';
441 /* Look for <kywd>,<sev>,... */
442 current = tokend + (ptrdiff_t)1;
443 if (*(tokend = exttok(current, ":,")) == ',') {
444 valstr = current;
445 *tokend = '\0';
447 current = tokend + (ptrdiff_t)1;
448 prstr = current;
450 /* Make sure <sev> > 4 */
451 val = (int)strtol(noesc(valstr), &p, 0);
452 if ((val > 4) && (p == tokend)) {
455 * Found <kywd>,<sev>,<printstring>.
456 * remember where we left off
459 if (*(tokend =
460 exttok(current, ":")) == ':') {
461 *tokend = '\0';
462 leftoff = tokend +
463 (ptrdiff_t)1;
464 } else {
465 leftoff = (char *)NULL;
469 * Alloc structure to contain
470 * severity definition
472 rtnval = libc_malloc(
473 sizeof (struct sevstr));
474 if (rtnval != NULL) {
476 /* Fill in structure */
477 rtnval->sevkywd = noesc(kywd);
478 rtnval->sevvalue = val;
479 rtnval->sevprstr = noesc(prstr);
480 rtnval->sevnext =
481 (struct sevstr *)NULL;
483 done = TRUE;
484 } else {
486 * Invalid severity value,
487 * eat thru end of token
489 current = tokend;
490 if (*(tokend = exttok(prstr, ":")) ==
491 ':') {
492 current++;
495 } else {
497 * Invalid severity definition,
498 * eat thru end of token
500 current = tokend;
501 if (*tokend == ':')
502 current++;
504 } else {
505 /* End of string found */
506 done = TRUE;
507 leftoff = (char *)NULL;
509 } /* while (!done) */
511 /* Finished */
512 return (rtnval);
516 * void msgverbset()
518 * Parces the argument of the MSGVERB environment variable and places
519 * a representation of the value of that value in "msgverb"
521 * Arguments:
522 * None:
524 * Returns: void
526 * Notes:
529 static void
530 msgverbset(void)
532 char *opts; /* Pointer to MSGVERB's value */
533 char *alloced; /* Pointer to MSGVERB's value */
534 char *tok; /* Pointer to current token */
535 char *tokend; /* Pointer to end of current token */
536 char *nexttok; /* Pointer to next token */
539 /* Rid ourselves of junk in "msgverb" */
540 msgverb = 0;
542 /* Get the value of MSGVERB. If none, use default value */
543 if ((opts = getenv(MSGVERB)) == (char *)NULL) {
544 msgverb = MV_DFLT;
545 } else { /* MSGVERB has a value. Interpret it */
546 if ((alloced = libc_malloc(strlen(opts) + 1)) == NULL) {
547 msgverb = MV_DFLT;
548 } else {
549 /* Make a copy of the value of MSGVERB */
550 nexttok = strcpy(alloced, opts);
552 /* Parse the options given by the user */
553 while ((tok = nexttok) != (char *)NULL) {
555 * Find end of the next token and squeeze
556 * out escaped characters
558 tokend = exttok(tok, ":");
559 tok = noesc(tok);
561 /* Delimit token and mark next, if any */
562 if (*tokend == ':') {
563 nexttok = tokend + (ptrdiff_t)1;
564 *tokend = '\0';
565 } else {
566 nexttok = (char *)NULL;
569 /* Check for "text" */
570 if (strcmp(tok, ST_TXT) == 0) {
571 msgverb |= MV_TXT;
573 /* Check for "label" */
574 } else if (strcmp(tok, ST_LBL) == 0) {
575 msgverb |= MV_LBL;
577 /* Check for "action */
578 } else if (strcmp(tok, ST_ACT) == 0) {
579 msgverb |= MV_ACT;
581 /* Check for "severity" */
582 } else if (strcmp(tok, ST_SEV) == 0) {
583 msgverb |= MV_SEV;
585 /* Check for "tag" */
586 } else if (strcmp(tok, ST_TAG) == 0) {
587 msgverb |= MV_TAG;
589 /* Unknown, ignore MSGVERB value */
590 } else {
591 msgverb = MV_DFLT;
592 nexttok = (char *)NULL;
594 } /* do while */
597 * Use default if no keywords on MSGVERB
598 * environment variable
600 if (msgverb == 0)
601 msgverb = MV_DFLT;
603 /* Free allocated space */
604 libc_free(alloced);
607 /* Finished */
608 /* return; */
612 * void sevstrset()
614 * This function builds a structure containing auxillary severity
615 * definitions.
617 * Arguments: None
619 * Returns: Void
622 static char *sevspace = (char *)NULL;
624 static void
625 sevstrset(void)
627 struct sevstr *plast;
628 struct sevstr *psev;
629 char *value;
632 /* Look for SEV_LEVEL definition */
633 if ((value = getenv(SEV_LEVEL)) != (char *)NULL) {
635 /* Allocate space and make a copy of the value of SEV_LEVEL */
636 if ((sevspace = libc_malloc(strlen(value) + 1)) != NULL) {
637 (void) strcpy(sevspace, value);
639 /* Continue for all severity descriptions */
640 psev = getauxsevs(sevspace);
641 plast = (struct sevstr *)NULL;
642 if (psev != (struct sevstr *)NULL) {
643 penvsevs = psev;
644 plast = psev;
645 while (psev = getauxsevs((char *)NULL)) {
646 plast->sevnext = psev;
647 plast = psev;
650 } /* if sevspace != (char *)NULL */
651 } /* if value != (char *)NULL */
655 * int addseverity(value, string)
656 * int value Value of the severity
657 * const char *string Print-string for the severity
659 * Arguments:
660 * value int
661 * The integer value of the severity being added
662 * string char *
663 * A pointer to the character-string to be printed
664 * whenever a severity of "value" is printed
666 * Returns: int
667 * Zero if successful, -1 if failed. The function can fail under
668 * the following circumstances:
669 * - libc_malloc() fails
670 * - The "value" is one of the reserved values.
672 * This function permits C applications to define severity-levels
673 * that augment the standard levels and those defined by the
674 * SEV_LEVEL environment variable.
678 addseverity(int value, const char *string)
680 struct sevstr *p; /* Temp ptr to severity structs */
681 struct sevstr *q; /* Temp ptr(follower) to severity */
682 int found; /* FLAG, element found in the list */
683 int rtnval; /* Value to return to the caller */
685 /* Make sure we're not trying to redefine one of the reserved values */
686 if (value <= 4) {
687 errno = EINVAL;
688 return (-1);
691 lmutex_lock(&fmt_lock);
693 /* Make sure we've interpreted SEV_LEVEL */
695 if (sevlook) {
696 sevstrset();
697 sevlook = FALSE;
702 * Leaf through the list. We may be redefining or removing a
703 * definition
705 q = (struct sevstr *)NULL;
706 found = FALSE;
707 for (p = paugsevs; !found && (p != (struct sevstr *)NULL);
708 p = p->sevnext) {
709 if (p->sevvalue == value) {
710 /* We've a match. Remove or modify the entry */
711 if (string == (char *)NULL) {
712 if (q == (struct sevstr *)NULL) {
713 paugsevs = p->sevnext;
714 } else {
715 q->sevnext = p->sevnext;
717 libc_free(p);
718 } else {
719 p->sevprstr = string;
721 found = TRUE;
723 q = p;
726 /* Adding a definition */
727 if (!found && (string != (char *)NULL)) {
728 /* Allocate space for the severity structure */
729 if ((p = libc_malloc(sizeof (struct sevstr))) == NULL) {
730 lmutex_unlock(&fmt_lock);
731 return (-1);
735 * Fill in the new structure with the data supplied and add to
736 * the head of the augmented severity list.
739 p->sevkywd = (char *)NULL;
740 p->sevprstr = string;
741 p->sevvalue = value;
742 p->sevnext = paugsevs;
743 paugsevs = p;
745 /* Successfully added a new severity */
746 rtnval = 0;
747 } else if (string == (char *)NULL) {
748 /* Attempting to undefined a non-defined severity */
749 rtnval = -1;
750 errno = EINVAL;
751 } else {
752 /* Successfully redefined a severity */
753 rtnval = 0;
755 /* Finished, successful */
756 lmutex_unlock(&fmt_lock);
757 return (rtnval);
761 * Utility function for converting an integer to a string, avoiding stdio.
763 static void
764 itoa(int n, char *s)
766 char buf[12]; /* 32 bits fits in 10 decimal digits */
767 char *cp = buf;
768 uint_t un = (n < 0)? -n : n;
770 do {
771 *cp++ = "0123456789"[un % 10];
772 un /= 10;
773 } while (un);
775 if (n < 0)
776 *s++ = '-';
778 do {
779 *s++ = *--cp;
780 } while (cp > buf);
782 *s = '\0';
786 * void writemsg(buf, size, verbosity, label, severity, text, action, tag)
788 * Arguments:
789 * char *buf The buffer in which to format the message
790 * size_t size The size of the buffer
791 * int verbosity A bit-string that indicates which components
792 * are to be written
793 * const char *label The address of the label-component
794 * int severity The severity value of the message
795 * const char *text The address of the text-component
796 * const char *action The address of the action-component
797 * const char *tag The address of the tag-component
799 * This function formats the message consisting of the label-component,
800 * severity-component, text-component, action-component, and tag-
801 * component into the provided buffer. The "verbosity" argument
802 * tells which components can be selected. Any or all of the
803 * components can be their null-values.
805 * Returns: void
807 * Notes:
810 static void
811 writemsg(char *buf, size_t size,
812 int verbosity, const char *label, int severity,
813 const char *text, const char *action, const char *tag)
815 struct sevstr *psev; /* Ptr for severity str list */
816 char *p; /* General purpose pointer */
817 char *sevpstr = NULL; /* Pointer to severity string */
818 int l1indent; /* # chars to indent line 1 */
819 int l2indent; /* # chars to indent line 2 */
820 int textindent; /* # spaces to indent text */
821 int actindent = 0; /* # spaces to indent action */
822 int i; /* General purpose counter */
823 int dolabel; /* TRUE if label to be written */
824 int dotext; /* TRUE if text to be written */
825 int dosev; /* TRUE if severity to be written */
826 int doaction; /* TRUE if action to be written */
827 int dotag; /* TRUE if tag to be written */
828 char c; /* Temp, multiuse character */
829 char sevpstrbuf[15]; /* Space for SV=%d */
831 char lcllbl[MM_MXLABELLN+1]; /* Space for (possibly */
832 /* truncated) label */
833 char lcltag[MM_MXTAGLN+1]; /* Space for (possibly */
834 /* truncated) tag */
835 char *ebuf = buf + size - 2;
838 * initialize variables.
840 sevpstrbuf[0] = (char)0;
841 lcllbl[0] = (char)0;
842 lcltag[0] = (char)0;
845 * Figure out what fields are to be written (all are optional)
848 dolabel = (verbosity & MV_LBL) && (label != MM_NULLLBL);
849 dosev = (verbosity & MV_SEV) && (severity != MM_NULLSEV);
850 dotext = (verbosity & MV_TXT) && (text != MM_NULLTXT);
851 doaction = (verbosity & MV_ACT) && (action != MM_NULLACT);
852 dotag = (verbosity & MV_TAG) && (tag != MM_NULLTAG);
855 * Figure out how much we'll need to indent the text of the message
858 /* Count the label of the message, if requested */
859 textindent = 0;
860 if (dolabel) {
861 (void) strncpy(lcllbl, label, (size_t)MM_MXLABELLN);
862 lcllbl[MM_MXLABELLN] = '\0';
863 textindent = (int)strlen(lcllbl) + SEPSTRLN;
867 * If severity req'd, determine the severity string and factor
868 * into indent count. Severity string generated by:
869 * 1. Search the standard list of severities.
870 * 2. Search the severities added by the application.
871 * 3. Search the severities added by the environment.
872 * 4. Use the default (SV=n where n is the value of the severity).
875 if (dosev) {
876 /* Search the default severity definitions */
877 psev = pstdsevs;
878 while (psev != (struct sevstr *)NULL) {
879 if (psev->sevvalue == severity)
880 break;
881 psev = psev->sevnext;
884 if (psev == (struct sevstr *)NULL) {
886 * Search the severity definitions
887 * added by the application
889 psev = paugsevs;
890 while (psev != (struct sevstr *)NULL) {
891 if (psev->sevvalue == severity)
892 break;
893 psev = psev->sevnext;
895 if (psev == (struct sevstr *)NULL) {
897 * Search the severity definitions
898 * added by the environment
900 psev = penvsevs;
901 while (psev != (struct sevstr *)NULL) {
902 if (psev->sevvalue == severity)
903 break;
904 psev = psev->sevnext;
906 if (psev == (struct sevstr *)NULL) {
907 /* Use default string, SV=severity */
908 (void) strcpy(sevpstrbuf, "SV=");
909 itoa(severity, &sevpstrbuf[3]);
910 sevpstr = sevpstrbuf;
911 } else {
912 sevpstr = (char *)psev->sevprstr;
914 } else {
915 sevpstr = (char *)psev->sevprstr;
917 } else {
918 sevpstr = (char *)psev->sevprstr;
920 /* Factor into indent counts */
921 textindent += (int)strlen(sevpstr) + SEPSTRLN;
925 * Figure out the indents.
928 if (doaction && dotext) {
929 if (textindent > ACTINTROLN) {
930 l1indent = 0;
931 l2indent = textindent - ACTINTROLN;
932 actindent = textindent;
933 } else {
934 l2indent = 0;
935 actindent = ACTINTROLN;
936 if (dosev || dolabel) {
937 l1indent = ACTINTROLN - textindent;
938 textindent = ACTINTROLN;
939 } else {
940 textindent = 0;
941 l1indent = 0;
944 } else {
945 l1indent = 0;
946 l2indent = 0;
947 if (doaction) {
948 actindent = textindent + ACTINTROLN;
949 } else if (dotext) {
950 actindent = 0;
955 * Write the message.
958 /* Write the LABEL, if requested */
959 if (dolabel) {
960 /* Write spaces to align on the ':' char, if needed */
961 while (--l1indent >= 0 && buf < ebuf)
962 *buf++ = ' ';
964 /* Write the label */
965 buf += strlcpy(buf, lcllbl, ebuf - buf);
968 * Write the separator string
969 * (if another component is to follow)
971 if (dosev || dotext || doaction || dotag)
972 buf += strlcpy(buf, SEPSTR, ebuf - buf);
975 /* Write the SEVERITY, if requested */
976 if (dosev) {
977 /* Write spaces to align on the ':' char, if needed */
978 while (--l1indent >= 0 && buf < ebuf)
979 *buf++ = ' ';
981 /* Write the severity print-string */
982 buf += strlcpy(buf, sevpstr, ebuf - buf);
985 * Write the separator string
986 * (if another component is to follow)
988 if (dotext || doaction || dotag)
989 buf += strlcpy(buf, SEPSTR, ebuf - buf);
992 /* Write the TEXT, if requested */
993 if (dotext) {
994 p = (char *)text;
995 for (c = *p++; c != NULL && buf < ebuf; c = *p++) {
996 *buf++ = c;
997 if (c == '\n') {
998 for (i = 0; i < textindent && buf < ebuf; i++)
999 *buf++ = ' ';
1005 * Write ACTION if requested.
1008 if (doaction) {
1009 if (dotext && buf < ebuf) {
1010 *buf++ = '\n';
1011 while (--l2indent >= 0 && buf < ebuf)
1012 *buf++ = ' ';
1015 /* Write the action-string's introduction */
1016 buf += strlcpy(buf, ACTINTRO, ebuf - buf);
1018 /* Write the "action" string */
1019 p = (char *)action;
1020 for (c = *p++; c != NULL && buf < ebuf; c = *p++) {
1021 *buf++ = c;
1022 if (c == '\n') {
1023 for (i = 0; i < actindent && buf < ebuf; i++)
1024 *buf++ = ' ';
1030 * Write the TAG if requested
1033 if (dotag) {
1034 if (doaction)
1035 buf += strlcpy(buf, " ", ebuf - buf);
1036 else if (dotext && buf < ebuf)
1037 *buf++ = '\n';
1038 (void) strncpy(lcltag, tag, (size_t)MM_MXTAGLN);
1039 lcltag[MM_MXTAGLN] = '\0';
1040 buf += strlcpy(buf, lcltag, ebuf - buf);
1044 * Write terminating newline and null byte.
1045 * We reserved space for these at the start.
1047 *buf++ = '\n';
1048 *buf++ = '\0';
1052 * int fmtmsg(class, label, severity, text, action, tag)
1053 * long class
1054 * const char *label
1055 * int severity
1056 * const char *text
1057 * const char *action
1058 * const char *tag
1060 * If requested, the fmtmsg() function writes a message to the standard
1061 * error stream in the standard message format. Also if requested, it
1062 * will write a message to the system console.
1064 * Arguments:
1065 * class Fields which classify the message for the system
1066 * logging facility
1067 * label A character-string that is printed as the "label"
1068 * of the message. Typically identifies the source
1069 * of the message
1070 * severity Identifies the severity of the message. Either one
1071 * of the standard severities, or possibly one of the
1072 * augmented severities
1073 * text Pointer to the text of the message
1074 * action Pointer to a char string that describes some type
1075 * of corrective action.
1076 * tag A character-string that is printed as the "tag" or
1077 * the message. Typically a pointer to documentation
1079 * Returns:
1080 * -1 if nothing was generated, 0 if everything requested was
1081 * generated, or flags if partially generated.
1083 * Needs:
1084 * - Nothing special for 4.0.
1088 fmtmsg(long class, const char *label, int severity,
1089 const char *text, const char *action, const char *tag)
1091 int rtnval; /* Value to return */
1092 FILE *console; /* Ptr to "console" stream */
1093 char *message1;
1094 char *message2;
1097 * Determine the "verbosity" of the message. If "msgverb" is
1098 * already set, don't interrogate the "MSGVERB" environment vbl.
1099 * If so, interrogate "MSGVERB" and do initialization stuff also.
1102 lmutex_lock(&fmt_lock);
1104 if (!(msgverb & MV_SET)) {
1105 msgverbset();
1106 msgverb |= MV_SET;
1111 * Extract the severity definitions from the SEV_LEVEL
1112 * environment variable and save away for later.
1115 if (sevlook) {
1116 sevstrset();
1117 sevlook = FALSE;
1121 /* Set up the default text component [if text==(char *)NULL] */
1122 if (text == (char *)NULL)
1123 text = DEFLT_TEXT;
1125 /* Prepare the message for stderr if requested */
1126 if (class & MM_PRINT) {
1127 message1 = alloca(MAX_MSG_SIZE);
1128 writemsg(message1, MAX_MSG_SIZE,
1129 msgverb, label, severity, text, action, tag);
1132 /* Prepare the message for the console if requested */
1133 if (class & MM_CONSOLE) {
1134 message2 = alloca(MAX_MSG_SIZE);
1135 writemsg(message2, MAX_MSG_SIZE,
1136 MV_ALL, label, severity, text, action, tag);
1139 lmutex_unlock(&fmt_lock);
1141 rtnval = MM_OK;
1143 /* Write the message to stderr if requested */
1144 if (class & MM_PRINT) {
1145 clearerr(stderr);
1146 (void) fputs(message1, stderr);
1147 if (ferror(stderr))
1148 rtnval |= MM_NOMSG;
1151 /* Write the message to the console if requested */
1152 if (class & MM_CONSOLE) {
1153 if ((console = fopen(CONNAME, "wF")) != NULL) {
1154 clearerr(console);
1155 (void) fputs(message2, console);
1156 if (ferror(console))
1157 rtnval |= MM_NOCON;
1158 (void) fclose(console);
1159 } else {
1160 rtnval |= MM_NOCON;
1164 if ((rtnval & (MM_NOCON | MM_NOMSG)) == (MM_NOCON | MM_NOMSG))
1165 rtnval = MM_NOTOK;
1166 return (rtnval);