import less(1)
[unleashed/tickless.git] / usr / src / lib / libc / port / gen / fmtmsg.c
blobcffee5100f19b103096ebe96787dacd1347d1289
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 */
32 * fmtmsg.c
34 * Contains:
35 * fmtmsg() Writes a message in standard format.
36 * addseverity() Adds a severity definition to the list of known
37 * severity definitions.
39 * Notes:
40 * - None of these functions can use strtok().
44 * Header Files Referenced:
45 * <stdio.h> C Standard I/O Definitions
46 * <string.h> C string handling definitions
47 * <fcntl.h> UNIX file control definitions
48 * <errno.h> UNIX error numbers and definitions
49 * <fmtmsg.h> Global definitions for fmtmsg()
50 * <stdlib.h> miscellaneous function declarations
53 #pragma weak _fmtmsg = fmtmsg
54 #pragma weak _addseverity = addseverity
56 #include "lint.h"
57 #include "mtlib.h"
58 #include "libc.h"
59 #include <sys/types.h>
60 #include <stddef.h>
61 #include <stdio.h>
62 #include <string.h>
63 #include <fcntl.h>
64 #include <errno.h>
65 #include <fmtmsg.h>
66 #include <stdlib.h>
67 #include <thread.h>
68 #include <synch.h>
69 #include <alloca.h>
72 * External functions referenced:
73 * (Others may be defined in header files above)
75 * getenv Extracts data from the environment
76 * libc_malloc Allocates space from main memory
77 * libc_free Frees space allocated via libc_malloc()
78 * strtol Convert string to "long"
79 * clearerr Clears an error on a stream (this is to make "lint"
80 * happy)
85 * Local Constant Definitions
89 * Boolean constants
90 * TRUE Boolean value for "true" (any bits on)
91 * FALSE Boolean value for "false" (all bits off)
94 #ifndef FALSE
95 #define FALSE (0)
96 #endif
98 #ifndef TRUE
99 #define TRUE (1)
100 #endif
102 #define MAX_MSG_SIZE 1024
105 * Keywords for fields named in the MSGVERB environment variable.
108 #define ST_LBL "label"
109 #define ST_SEV "severity"
110 #define ST_TXT "text"
111 #define ST_TAG "tag"
112 #define ST_ACT "action"
116 * The following constants define the value of the "msgverb"
117 * variable. This variable tells fmtmsg() which parts of the
118 * standard message it is to display. If !(msgverb&MV_SET),
119 * fmtmsg() will interrogate the "MSGVERB" environment variable
120 * and set "msgverb" accordingly.
122 * NOTE: This means that if MSGVERB changes after the first call
123 * to fmtmsg(), it will be ignored.
125 * Constants:
126 * MV_INV Check MSGVERB environment variable (invalidates value)
127 * MV_SET MSGVERB checked, msgverb value valid
128 * MV_LBL "label" selected
129 * MV_SEV "severity" selected
130 * MV_TXT "text" selected
131 * MV_TAG "messageID" selected
132 * MV_ACT "action" selected
134 * MV_ALL All components selected
135 * MV_DFLT Default value for MSGVERB
138 #define MV_INV 0
139 #define MV_SET 0x0001
140 #define MV_LBL 0x0002
141 #define MV_SEV 0x0004
142 #define MV_TXT 0x0008
143 #define MV_TAG 0x0010
144 #define MV_ACT 0x0020
146 #define MV_ALL (MV_LBL|MV_SEV|MV_TXT|MV_TAG|MV_ACT)
147 #define MV_DFLT (MV_LBL|MV_SEV|MV_TXT|MV_TAG|MV_ACT)
152 * Strings defining the different severities of a message.
153 * Internationalization may demand that these come from the message database
156 #define SV_UNK "UNKNOWN"
157 #define SV_HALT "HALT"
158 #define SV_ERROR "ERROR"
159 #define SV_WARN "WARNING"
160 #define SV_INF "INFO"
164 * Text string if none is provided:
167 #define DEFLT_TEXT "No text provided with this message"
171 * Text string introduction for "action". This may have to come from
172 * the message database because of internationalization.
175 #define ACTINTRO "TO FIX: "
176 #define ACTINTROLN 8
180 * SEPSTR is the string that separates the "label" from what follows it,
181 * and the severity from what follows it.
184 #define SEPSTR ": "
185 #define SEPSTRLN 2
189 * Miscellaneous constants:
190 * CONNAME Filesystem entry name for the system console
193 #define CONNAME "/dev/console"
196 * Local data type definitions
200 * Severity string structure
202 * struct sevstr
203 * sevvalue Value of the severity-level being defined
204 * sevkywd Keyword identifying the severity
205 * sevprptr Pointer to the string associated with the value
206 * sevnext Pointer to the next value in the list.
208 * Restrictions:
209 * sevvalue Must be a non-negative integer (>=0)
211 * There are three (possibly null) lists of these structures.
212 * 1) is the list of standard severities
213 * 2) is the list of severity-levels defined by SEV_LEVEL
214 * 3) is the list of severity-levels defined by calls to
215 * addseverity()
218 struct sevstr {
219 int sevvalue;
220 const char *sevkywd;
221 const char *sevprstr;
222 struct sevstr *sevnext;
226 * Local Static Data
227 * msgverb int
228 * Contains the internal representation or the
229 * MSGVERB environment variable.
230 * sevlook TRUE if fmtmsg() has to look at SEV_LEVEL the
231 * next time it is called.
232 * paugsevs struct sevstr *
233 * Head of the linked list of structures that define
234 * severities that augment the standard severities,
235 * as defined by addseverity().
236 * penvsevs struct sevstrs *
237 * Head of the linked list of structures that define
238 * severities that augment the standard severities,
239 * as defined by SEV_LEVEL.
240 * pstdsevs struct sevstrs *
241 * Head of the linked list of structures that define
242 * the standard severities.
245 static mutex_t fmt_lock = DEFAULTMUTEX;
247 static int msgverb = 0;
248 static int sevlook = TRUE;
250 static struct sevstr *paugsevs = NULL;
251 static struct sevstr *penvsevs = NULL;
253 static struct sevstr sevstrs[] = {
254 { MM_HALT, "", SV_HALT, &sevstrs[1]},
255 { MM_ERROR, "", SV_ERROR, &sevstrs[2]},
256 { MM_WARNING, "", SV_WARN, &sevstrs[3]},
257 { MM_INFO, "", SV_INF, NULL},
259 static struct sevstr *pstdsevs = &sevstrs[0];
262 * static char *exttok(str, delims)
263 * const char *str
264 * const char *delims
266 * This function examines the string pointed to by "str", looking
267 * for the first occurrence of any of the characters in the string
268 * whose address is "delims". It returns the address of that
269 * character or NULL if there was nothing to search.
271 * Arguments:
272 * str Address of the string to search
273 * delims Address of the string containing delimiters
275 * Returns: char *
276 * Returns the address of the first occurrence of any of the characters
277 * in "delim" in the string "str" (incl '\0'). If there was nothing
278 * to search, the function returns NULL.
280 * Notes:
281 * - This function is needed because strtok() can't be used inside a
282 * function. Besides, strtok() is destructive in the string, which
283 * is undesirable in many circumstances.
284 * - This function understands escaped delimiters as non-delimiters.
285 * Delimiters are escaped by preceding them with '\' characters.
286 * The '\' character also must be escaped.
289 static char *
290 exttok(const char *tok, const char *delims)
292 char *tokend; /* Ptr to the end of the token */
293 char *p, *q; /* Temp pointers */
296 * Algorithm:
297 * 1. Get the starting address(new string or where we
298 * left off). If nothing to search, returnNULL
299 * 2. Find the end of the string
300 * 3. Look for the first unescaped delimiter closest to the
301 * beginning of the string
302 * 4. Remember where we left off
303 * 5. Return a pointer to the delimiter we found
306 /* Begin at the beginning, if any */
307 if (tok == NULL) {
308 return (NULL);
311 /* Find end of the token string */
312 tokend = (char *)tok + (ptrdiff_t)strlen(tok);
314 /* Look for the 1st occurrence of any delimiter */
315 for (p = (char *)delims; *p != '\0'; p++) {
316 for (q = strchr(tok, (int)*p);
317 (q != 0) && (q != tok) && (*(q - (ptrdiff_t)1) == '\\');
318 q = strchr(q + (ptrdiff_t)1, (int)*p))
320 if ((q != 0) && (q < tokend))
321 tokend = q;
324 /* Done */
325 return (tokend);
329 * char *noesc(str)
331 * This function squeezes out all of the escaped character sequences
332 * from the string <str>. It returns a pointer to that string.
334 * Arguments:
335 * str char *
336 * The string that is to have its escaped characters removed.
338 * Returns: char *
339 * This function returns its argument <str> always.
341 * Notes:
342 * This function potentially modifies the string it is given.
345 static char *
346 noesc(char *str)
348 char *p; /* Temp string pointer */
349 char *q; /* Temp string pointer */
351 /* Look for an escaped character */
352 p = str;
353 while (*p && (*p != '\\')) p++;
357 * If there was at least one, squeeze them out
358 * Otherwise, don't touch the argument string
361 if (*p) {
362 q = p++;
363 while (*q++ = *p++) {
364 if (*p == '\\')
365 p++;
369 /* Finished. Return our argument */
370 return (str);
374 * struct sevstr *getauxsevs(ptr)
376 * Parses a string that is in the format of the severity definitions.
377 * Returns a pointer to a (malloc'd) structure that contains the
378 * definition, or NULL if none was parsed.
380 * Arguments:
381 * ptr char *
382 * References the string from which data is to be extracted.
383 * If NULL, continue where we left off. Otherwise,
384 * start with the string referenced by ptr.
386 * Returns: struct sevstr *
387 * A pointer to a malloc'd structure containing the severity definition
388 * parsed from string, or NULL if none.
390 * Notes:
391 * - This function is destructive to the string referenced by its argument.
394 /* Static data */
395 static char *leftoff = NULL;
397 static struct sevstr *
398 getauxsevs(char *ptr)
400 char *current; /* Ptr to current sev def'n */
401 char *tokend; /* Ptr to end of current sev def'n */
402 char *kywd; /* Ptr to extracted kywd */
403 char *valstr; /* Ptr to extracted sev value */
404 char *prstr; /* Ptr to extracted print str */
405 char *p; /* Temp pointer */
406 int val; /* Converted severity value */
407 int done; /* Flag, sev def'n found and ok? */
408 struct sevstr *rtnval; /* Value to return */
411 /* Start anew or start where we left off? */
412 current = (ptr == NULL) ? leftoff : ptr;
415 /* If nothing to parse, return NULL */
416 if (current == NULL) {
417 return (NULL);
422 * Look through the string "current" for a token of the form
423 * <kywd>,<sev>,<printstring> delimited by ':' or '\0'
426 /* Loop initializations */
427 done = FALSE;
428 rtnval = NULL;
429 while (!done) {
430 /* Eat leading junk */
431 while (*(tokend = exttok(current, ":,")) == ':') {
432 current = tokend + (ptrdiff_t)1;
435 /* If we've found a <kywd>,... */
436 if (*tokend == ',') {
437 kywd = current;
438 *tokend = '\0';
440 /* Look for <kywd>,<sev>,... */
441 current = tokend + (ptrdiff_t)1;
442 if (*(tokend = exttok(current, ":,")) == ',') {
443 valstr = current;
444 *tokend = '\0';
446 current = tokend + (ptrdiff_t)1;
447 prstr = current;
449 /* Make sure <sev> > 4 */
450 val = (int)strtol(noesc(valstr), &p, 0);
451 if ((val > 4) && (p == tokend)) {
454 * Found <kywd>,<sev>,<printstring>.
455 * remember where we left off
458 if (*(tokend =
459 exttok(current, ":")) == ':') {
460 *tokend = '\0';
461 leftoff = tokend +
462 (ptrdiff_t)1;
463 } else {
464 leftoff = NULL;
468 * Alloc structure to contain
469 * severity definition
471 rtnval = libc_malloc(
472 sizeof (struct sevstr));
473 if (rtnval != NULL) {
475 /* Fill in structure */
476 rtnval->sevkywd = noesc(kywd);
477 rtnval->sevvalue = val;
478 rtnval->sevprstr = noesc(prstr);
479 rtnval->sevnext =
480 NULL;
482 done = TRUE;
483 } else {
485 * Invalid severity value,
486 * eat thru end of token
488 current = tokend;
489 if (*(tokend = exttok(prstr, ":")) ==
490 ':') {
491 current++;
494 } else {
496 * Invalid severity definition,
497 * eat thru end of token
499 current = tokend;
500 if (*tokend == ':')
501 current++;
503 } else {
504 /* End of string found */
505 done = TRUE;
506 leftoff = NULL;
508 } /* while (!done) */
510 /* Finished */
511 return (rtnval);
515 * void msgverbset()
517 * Parces the argument of the MSGVERB environment variable and places
518 * a representation of the value of that value in "msgverb"
520 * Arguments:
521 * None:
523 * Returns: void
525 * Notes:
528 static void
529 msgverbset(void)
531 char *opts; /* Pointer to MSGVERB's value */
532 char *alloced; /* Pointer to MSGVERB's value */
533 char *tok; /* Pointer to current token */
534 char *tokend; /* Pointer to end of current token */
535 char *nexttok; /* Pointer to next token */
538 /* Rid ourselves of junk in "msgverb" */
539 msgverb = 0;
541 /* Get the value of MSGVERB. If none, use default value */
542 if ((opts = getenv(MSGVERB)) == NULL) {
543 msgverb = MV_DFLT;
544 } else { /* MSGVERB has a value. Interpret it */
545 if ((alloced = libc_malloc(strlen(opts) + 1)) == NULL) {
546 msgverb = MV_DFLT;
547 } else {
548 /* Make a copy of the value of MSGVERB */
549 nexttok = strcpy(alloced, opts);
551 /* Parse the options given by the user */
552 while ((tok = nexttok) != NULL) {
554 * Find end of the next token and squeeze
555 * out escaped characters
557 tokend = exttok(tok, ":");
558 tok = noesc(tok);
560 /* Delimit token and mark next, if any */
561 if (*tokend == ':') {
562 nexttok = tokend + (ptrdiff_t)1;
563 *tokend = '\0';
564 } else {
565 nexttok = NULL;
568 /* Check for "text" */
569 if (strcmp(tok, ST_TXT) == 0) {
570 msgverb |= MV_TXT;
572 /* Check for "label" */
573 } else if (strcmp(tok, ST_LBL) == 0) {
574 msgverb |= MV_LBL;
576 /* Check for "action */
577 } else if (strcmp(tok, ST_ACT) == 0) {
578 msgverb |= MV_ACT;
580 /* Check for "severity" */
581 } else if (strcmp(tok, ST_SEV) == 0) {
582 msgverb |= MV_SEV;
584 /* Check for "tag" */
585 } else if (strcmp(tok, ST_TAG) == 0) {
586 msgverb |= MV_TAG;
588 /* Unknown, ignore MSGVERB value */
589 } else {
590 msgverb = MV_DFLT;
591 nexttok = NULL;
593 } /* do while */
596 * Use default if no keywords on MSGVERB
597 * environment variable
599 if (msgverb == 0)
600 msgverb = MV_DFLT;
602 /* Free allocated space */
603 libc_free(alloced);
606 /* Finished */
607 /* return; */
611 * void sevstrset()
613 * This function builds a structure containing auxillary severity
614 * definitions.
616 * Arguments: None
618 * Returns: Void
621 static char *sevspace = NULL;
623 static void
624 sevstrset(void)
626 struct sevstr *plast;
627 struct sevstr *psev;
628 char *value;
631 /* Look for SEV_LEVEL definition */
632 if ((value = getenv(SEV_LEVEL)) != NULL) {
634 /* Allocate space and make a copy of the value of SEV_LEVEL */
635 if ((sevspace = libc_malloc(strlen(value) + 1)) != NULL) {
636 (void) strcpy(sevspace, value);
638 /* Continue for all severity descriptions */
639 psev = getauxsevs(sevspace);
640 plast = NULL;
641 if (psev != NULL) {
642 penvsevs = psev;
643 plast = psev;
644 while (psev = getauxsevs(NULL)) {
645 plast->sevnext = psev;
646 plast = psev;
649 } /* if sevspace != NULL */
650 } /* if value != NULL */
654 * int addseverity(value, string)
655 * int value Value of the severity
656 * const char *string Print-string for the severity
658 * Arguments:
659 * value int
660 * The integer value of the severity being added
661 * string char *
662 * A pointer to the character-string to be printed
663 * whenever a severity of "value" is printed
665 * Returns: int
666 * Zero if successful, -1 if failed. The function can fail under
667 * the following circumstances:
668 * - libc_malloc() fails
669 * - The "value" is one of the reserved values.
671 * This function permits C applications to define severity-levels
672 * that augment the standard levels and those defined by the
673 * SEV_LEVEL environment variable.
677 addseverity(int value, const char *string)
679 struct sevstr *p; /* Temp ptr to severity structs */
680 struct sevstr *q; /* Temp ptr(follower) to severity */
681 int found; /* FLAG, element found in the list */
682 int rtnval; /* Value to return to the caller */
684 /* Make sure we're not trying to redefine one of the reserved values */
685 if (value <= 4) {
686 errno = EINVAL;
687 return (-1);
690 lmutex_lock(&fmt_lock);
692 /* Make sure we've interpreted SEV_LEVEL */
694 if (sevlook) {
695 sevstrset();
696 sevlook = FALSE;
701 * Leaf through the list. We may be redefining or removing a
702 * definition
704 q = NULL;
705 found = FALSE;
706 for (p = paugsevs; !found && (p != NULL);
707 p = p->sevnext) {
708 if (p->sevvalue == value) {
709 /* We've a match. Remove or modify the entry */
710 if (string == NULL) {
711 if (q == NULL) {
712 paugsevs = p->sevnext;
713 } else {
714 q->sevnext = p->sevnext;
716 libc_free(p);
717 } else {
718 p->sevprstr = string;
720 found = TRUE;
722 q = p;
725 /* Adding a definition */
726 if (!found && (string != NULL)) {
727 /* Allocate space for the severity structure */
728 if ((p = libc_malloc(sizeof (struct sevstr))) == NULL) {
729 lmutex_unlock(&fmt_lock);
730 return (-1);
734 * Fill in the new structure with the data supplied and add to
735 * the head of the augmented severity list.
738 p->sevkywd = NULL;
739 p->sevprstr = string;
740 p->sevvalue = value;
741 p->sevnext = paugsevs;
742 paugsevs = p;
744 /* Successfully added a new severity */
745 rtnval = 0;
746 } else if (string == NULL) {
747 /* Attempting to undefined a non-defined severity */
748 rtnval = -1;
749 errno = EINVAL;
750 } else {
751 /* Successfully redefined a severity */
752 rtnval = 0;
754 /* Finished, successful */
755 lmutex_unlock(&fmt_lock);
756 return (rtnval);
760 * Utility function for converting an integer to a string, avoiding stdio.
762 static void
763 itoa(int n, char *s)
765 char buf[12]; /* 32 bits fits in 10 decimal digits */
766 char *cp = buf;
767 uint_t un = (n < 0)? -n : n;
769 do {
770 *cp++ = "0123456789"[un % 10];
771 un /= 10;
772 } while (un);
774 if (n < 0)
775 *s++ = '-';
777 do {
778 *s++ = *--cp;
779 } while (cp > buf);
781 *s = '\0';
785 * void writemsg(buf, size, verbosity, label, severity, text, action, tag)
787 * Arguments:
788 * char *buf The buffer in which to format the message
789 * size_t size The size of the buffer
790 * int verbosity A bit-string that indicates which components
791 * are to be written
792 * const char *label The address of the label-component
793 * int severity The severity value of the message
794 * const char *text The address of the text-component
795 * const char *action The address of the action-component
796 * const char *tag The address of the tag-component
798 * This function formats the message consisting of the label-component,
799 * severity-component, text-component, action-component, and tag-
800 * component into the provided buffer. The "verbosity" argument
801 * tells which components can be selected. Any or all of the
802 * components can be their null-values.
804 * Returns: void
806 * Notes:
809 static void
810 writemsg(char *buf, size_t size,
811 int verbosity, const char *label, int severity,
812 const char *text, const char *action, const char *tag)
814 struct sevstr *psev; /* Ptr for severity str list */
815 char *p; /* General purpose pointer */
816 char *sevpstr = NULL; /* Pointer to severity string */
817 int l1indent; /* # chars to indent line 1 */
818 int l2indent; /* # chars to indent line 2 */
819 int textindent; /* # spaces to indent text */
820 int actindent = 0; /* # spaces to indent action */
821 int i; /* General purpose counter */
822 int dolabel; /* TRUE if label to be written */
823 int dotext; /* TRUE if text to be written */
824 int dosev; /* TRUE if severity to be written */
825 int doaction; /* TRUE if action to be written */
826 int dotag; /* TRUE if tag to be written */
827 char c; /* Temp, multiuse character */
828 char sevpstrbuf[15]; /* Space for SV=%d */
830 char lcllbl[MM_MXLABELLN+1]; /* Space for (possibly */
831 /* truncated) label */
832 char lcltag[MM_MXTAGLN+1]; /* Space for (possibly */
833 /* truncated) tag */
834 char *ebuf = buf + size - 2;
837 * initialize variables.
839 sevpstrbuf[0] = '\0';
840 lcllbl[0] = '\0';
841 lcltag[0] = '\0';
844 * Figure out what fields are to be written (all are optional)
847 dolabel = (verbosity & MV_LBL) && (label != MM_NULLLBL);
848 dosev = (verbosity & MV_SEV) && (severity != MM_NULLSEV);
849 dotext = (verbosity & MV_TXT) && (text != MM_NULLTXT);
850 doaction = (verbosity & MV_ACT) && (action != MM_NULLACT);
851 dotag = (verbosity & MV_TAG) && (tag != MM_NULLTAG);
854 * Figure out how much we'll need to indent the text of the message
857 /* Count the label of the message, if requested */
858 textindent = 0;
859 if (dolabel) {
860 (void) strncpy(lcllbl, label, (size_t)MM_MXLABELLN);
861 lcllbl[MM_MXLABELLN] = '\0';
862 textindent = (int)strlen(lcllbl) + SEPSTRLN;
866 * If severity req'd, determine the severity string and factor
867 * into indent count. Severity string generated by:
868 * 1. Search the standard list of severities.
869 * 2. Search the severities added by the application.
870 * 3. Search the severities added by the environment.
871 * 4. Use the default (SV=n where n is the value of the severity).
874 if (dosev) {
875 /* Search the default severity definitions */
876 psev = pstdsevs;
877 while (psev != NULL) {
878 if (psev->sevvalue == severity)
879 break;
880 psev = psev->sevnext;
883 if (psev == NULL) {
885 * Search the severity definitions
886 * added by the application
888 psev = paugsevs;
889 while (psev != NULL) {
890 if (psev->sevvalue == severity)
891 break;
892 psev = psev->sevnext;
894 if (psev == NULL) {
896 * Search the severity definitions
897 * added by the environment
899 psev = penvsevs;
900 while (psev != NULL) {
901 if (psev->sevvalue == severity)
902 break;
903 psev = psev->sevnext;
905 if (psev == NULL) {
906 /* Use default string, SV=severity */
907 (void) strcpy(sevpstrbuf, "SV=");
908 itoa(severity, &sevpstrbuf[3]);
909 sevpstr = sevpstrbuf;
910 } else {
911 sevpstr = (char *)psev->sevprstr;
913 } else {
914 sevpstr = (char *)psev->sevprstr;
916 } else {
917 sevpstr = (char *)psev->sevprstr;
919 /* Factor into indent counts */
920 textindent += (int)strlen(sevpstr) + SEPSTRLN;
924 * Figure out the indents.
927 if (doaction && dotext) {
928 if (textindent > ACTINTROLN) {
929 l1indent = 0;
930 l2indent = textindent - ACTINTROLN;
931 actindent = textindent;
932 } else {
933 l2indent = 0;
934 actindent = ACTINTROLN;
935 if (dosev || dolabel) {
936 l1indent = ACTINTROLN - textindent;
937 textindent = ACTINTROLN;
938 } else {
939 textindent = 0;
940 l1indent = 0;
943 } else {
944 l1indent = 0;
945 l2indent = 0;
946 if (doaction) {
947 actindent = textindent + ACTINTROLN;
948 } else if (dotext) {
949 actindent = 0;
954 * Write the message.
957 /* Write the LABEL, if requested */
958 if (dolabel) {
959 /* Write spaces to align on the ':' char, if needed */
960 while (--l1indent >= 0 && buf < ebuf)
961 *buf++ = ' ';
963 /* Write the label */
964 buf += strlcpy(buf, lcllbl, ebuf - buf);
967 * Write the separator string
968 * (if another component is to follow)
970 if (dosev || dotext || doaction || dotag)
971 buf += strlcpy(buf, SEPSTR, ebuf - buf);
974 /* Write the SEVERITY, if requested */
975 if (dosev) {
976 /* Write spaces to align on the ':' char, if needed */
977 while (--l1indent >= 0 && buf < ebuf)
978 *buf++ = ' ';
980 /* Write the severity print-string */
981 buf += strlcpy(buf, sevpstr, ebuf - buf);
984 * Write the separator string
985 * (if another component is to follow)
987 if (dotext || doaction || dotag)
988 buf += strlcpy(buf, SEPSTR, ebuf - buf);
991 /* Write the TEXT, if requested */
992 if (dotext) {
993 p = (char *)text;
994 for (c = *p++; c != '\0' && buf < ebuf; c = *p++) {
995 *buf++ = c;
996 if (c == '\n') {
997 for (i = 0; i < textindent && buf < ebuf; i++)
998 *buf++ = ' ';
1004 * Write ACTION if requested.
1007 if (doaction) {
1008 if (dotext && buf < ebuf) {
1009 *buf++ = '\n';
1010 while (--l2indent >= 0 && buf < ebuf)
1011 *buf++ = ' ';
1014 /* Write the action-string's introduction */
1015 buf += strlcpy(buf, ACTINTRO, ebuf - buf);
1017 /* Write the "action" string */
1018 p = (char *)action;
1019 for (c = *p++; c != '\0' && buf < ebuf; c = *p++) {
1020 *buf++ = c;
1021 if (c == '\n') {
1022 for (i = 0; i < actindent && buf < ebuf; i++)
1023 *buf++ = ' ';
1029 * Write the TAG if requested
1032 if (dotag) {
1033 if (doaction)
1034 buf += strlcpy(buf, " ", ebuf - buf);
1035 else if (dotext && buf < ebuf)
1036 *buf++ = '\n';
1037 (void) strncpy(lcltag, tag, (size_t)MM_MXTAGLN);
1038 lcltag[MM_MXTAGLN] = '\0';
1039 buf += strlcpy(buf, lcltag, ebuf - buf);
1043 * Write terminating newline and null byte.
1044 * We reserved space for these at the start.
1046 *buf++ = '\n';
1047 *buf++ = '\0';
1051 * int fmtmsg(class, label, severity, text, action, tag)
1052 * long class
1053 * const char *label
1054 * int severity
1055 * const char *text
1056 * const char *action
1057 * const char *tag
1059 * If requested, the fmtmsg() function writes a message to the standard
1060 * error stream in the standard message format. Also if requested, it
1061 * will write a message to the system console.
1063 * Arguments:
1064 * class Fields which classify the message for the system
1065 * logging facility
1066 * label A character-string that is printed as the "label"
1067 * of the message. Typically identifies the source
1068 * of the message
1069 * severity Identifies the severity of the message. Either one
1070 * of the standard severities, or possibly one of the
1071 * augmented severities
1072 * text Pointer to the text of the message
1073 * action Pointer to a char string that describes some type
1074 * of corrective action.
1075 * tag A character-string that is printed as the "tag" or
1076 * the message. Typically a pointer to documentation
1078 * Returns:
1079 * -1 if nothing was generated, 0 if everything requested was
1080 * generated, or flags if partially generated.
1082 * Needs:
1083 * - Nothing special for 4.0.
1087 fmtmsg(long class, const char *label, int severity,
1088 const char *text, const char *action, const char *tag)
1090 int rtnval; /* Value to return */
1091 FILE *console; /* Ptr to "console" stream */
1092 char *message1;
1093 char *message2;
1096 * Determine the "verbosity" of the message. If "msgverb" is
1097 * already set, don't interrogate the "MSGVERB" environment vbl.
1098 * If so, interrogate "MSGVERB" and do initialization stuff also.
1101 lmutex_lock(&fmt_lock);
1103 if (!(msgverb & MV_SET)) {
1104 msgverbset();
1105 msgverb |= MV_SET;
1110 * Extract the severity definitions from the SEV_LEVEL
1111 * environment variable and save away for later.
1114 if (sevlook) {
1115 sevstrset();
1116 sevlook = FALSE;
1120 /* Set up the default text component [if text==NULL] */
1121 if (text == NULL)
1122 text = DEFLT_TEXT;
1124 /* Prepare the message for stderr if requested */
1125 if (class & MM_PRINT) {
1126 message1 = alloca(MAX_MSG_SIZE);
1127 writemsg(message1, MAX_MSG_SIZE,
1128 msgverb, label, severity, text, action, tag);
1131 /* Prepare the message for the console if requested */
1132 if (class & MM_CONSOLE) {
1133 message2 = alloca(MAX_MSG_SIZE);
1134 writemsg(message2, MAX_MSG_SIZE,
1135 MV_ALL, label, severity, text, action, tag);
1138 lmutex_unlock(&fmt_lock);
1140 rtnval = MM_OK;
1142 /* Write the message to stderr if requested */
1143 if (class & MM_PRINT) {
1144 clearerr(stderr);
1145 (void) fputs(message1, stderr);
1146 if (ferror(stderr))
1147 rtnval |= MM_NOMSG;
1150 /* Write the message to the console if requested */
1151 if (class & MM_CONSOLE) {
1152 if ((console = fopen(CONNAME, "wF")) != NULL) {
1153 clearerr(console);
1154 (void) fputs(message2, console);
1155 if (ferror(console))
1156 rtnval |= MM_NOCON;
1157 (void) fclose(console);
1158 } else {
1159 rtnval |= MM_NOCON;
1163 if ((rtnval & (MM_NOCON | MM_NOMSG)) == (MM_NOCON | MM_NOMSG))
1164 rtnval = MM_NOTOK;
1165 return (rtnval);