/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* fmtmsg.c
*
* Contains:
* fmtmsg() Writes a message in standard format.
* addseverity() Adds a severity definition to the list of known
* severity definitions.
*
* Notes:
* - None of these functions can use strtok().
*/
/*
* Header Files Referenced:
* <stdio.h> C Standard I/O Definitions
* <string.h> C string handling definitions
* <fcntl.h> UNIX file control definitions
* <errno.h> UNIX error numbers and definitions
* <fmtmsg.h> Global definitions for fmtmsg()
* <stdlib.h> miscellaneous function declarations
*/
#include "lint.h"
#include "mtlib.h"
#include "libc.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <fmtmsg.h>
#include <stdlib.h>
#include <thread.h>
#include <synch.h>
#include <alloca.h>
/*
* External functions referenced:
* (Others may be defined in header files above)
*
* getenv Extracts data from the environment
* libc_malloc Allocates space from main memory
* libc_free Frees space allocated via libc_malloc()
* strtol Convert string to "long"
* clearerr Clears an error on a stream (this is to make "lint"
* happy)
*/
/*
* Local Constant Definitions
*/
/*
* Boolean constants
* TRUE Boolean value for "true" (any bits on)
* FALSE Boolean value for "false" (all bits off)
*/
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#endif
/*
* Keywords for fields named in the MSGVERB environment variable.
*/
/*
* The following constants define the value of the "msgverb"
* variable. This variable tells fmtmsg() which parts of the
* standard message it is to display. If !(msgverb&MV_SET),
* fmtmsg() will interrogate the "MSGVERB" environment variable
* and set "msgverb" accordingly.
*
* NOTE: This means that if MSGVERB changes after the first call
* to fmtmsg(), it will be ignored.
*
* Constants:
* MV_INV Check MSGVERB environment variable (invalidates value)
* MV_SET MSGVERB checked, msgverb value valid
* MV_LBL "label" selected
* MV_SEV "severity" selected
* MV_TXT "text" selected
* MV_TAG "messageID" selected
* MV_ACT "action" selected
*
* MV_ALL All components selected
* MV_DFLT Default value for MSGVERB
*/
#define MV_INV 0
/*
* Strings defining the different severities of a message.
* Internationalization may demand that these come from the message database
*/
/*
* Text string if none is provided:
*/
/*
* Text string introduction for "action". This may have to come from
* the message database because of internationalization.
*/
/*
* SEPSTR is the string that separates the "label" from what follows it,
* and the severity from what follows it.
*/
/*
* Miscellaneous constants:
* CONNAME Filesystem entry name for the system console
*/
/*
* Local data type definitions
*/
/*
* Severity string structure
*
* struct sevstr
* sevvalue Value of the severity-level being defined
* sevkywd Keyword identifying the severity
* sevprptr Pointer to the string associated with the value
* sevnext Pointer to the next value in the list.
*
* Restrictions:
* sevvalue Must be a non-negative integer (>=0)
*
* There are three (possibly null) lists of these structures.
* 1) is the list of standard severities
* 2) is the list of severity-levels defined by SEV_LEVEL
* 3) is the list of severity-levels defined by calls to
* addseverity()
*/
struct sevstr {
int sevvalue;
const char *sevkywd;
const char *sevprstr;
};
/*
* Local Static Data
* msgverb int
* Contains the internal representation or the
* MSGVERB environment variable.
* sevlook TRUE if fmtmsg() has to look at SEV_LEVEL the
* next time it is called.
* paugsevs struct sevstr *
* Head of the linked list of structures that define
* severities that augment the standard severities,
* as defined by addseverity().
* penvsevs struct sevstrs *
* Head of the linked list of structures that define
* severities that augment the standard severities,
* as defined by SEV_LEVEL.
* pstdsevs struct sevstrs *
* Head of the linked list of structures that define
* the standard severities.
*/
static int msgverb = 0;
};
/*
* static char *exttok(str, delims)
* const char *str
* const char *delims
*
* This function examines the string pointed to by "str", looking
* for the first occurrence of any of the characters in the string
* whose address is "delims". It returns the address of that
* character or (char *)NULL if there was nothing to search.
*
* Arguments:
* str Address of the string to search
* delims Address of the string containing delimiters
*
* Returns: char *
* Returns the address of the first occurrence of any of the characters
* in "delim" in the string "str" (incl '\0'). If there was nothing
* to search, the function returns (char *)NULL.
*
* Notes:
* - This function is needed because strtok() can't be used inside a
* function. Besides, strtok() is destructive in the string, which
* is undesirable in many circumstances.
* - This function understands escaped delimiters as non-delimiters.
* Delimiters are escaped by preceding them with '\' characters.
* The '\' character also must be escaped.
*/
static char *
{
char *p, *q; /* Temp pointers */
/*
* Algorithm:
* 1. Get the starting address(new string or where we
* left off). If nothing to search, return(char *)NULL
* 2. Find the end of the string
* 3. Look for the first unescaped delimiter closest to the
* beginning of the string
* 4. Remember where we left off
* 5. Return a pointer to the delimiter we found
*/
/* Begin at the beginning, if any */
return ((char *)NULL);
}
/* Find end of the token string */
/* Look for the 1st occurrence of any delimiter */
for (p = (char *)delims; *p != '\0'; p++) {
;
if ((q != 0) && (q < tokend))
tokend = q;
}
/* Done */
return (tokend);
}
/*
* char *noesc(str)
*
* This function squeezes out all of the escaped character sequences
* from the string <str>. It returns a pointer to that string.
*
* Arguments:
* str char *
* The string that is to have its escaped characters removed.
*
* Returns: char *
* This function returns its argument <str> always.
*
* Notes:
* This function potentially modifies the string it is given.
*/
static char *
{
char *p; /* Temp string pointer */
char *q; /* Temp string pointer */
/* Look for an escaped character */
p = str;
while (*p && (*p != '\\')) p++;
/*
* If there was at least one, squeeze them out
* Otherwise, don't touch the argument string
*/
if (*p) {
q = p++;
while (*q++ = *p++) {
if (*p == '\\')
p++;
}
}
/* Finished. Return our argument */
return (str);
}
/*
* struct sevstr *getauxsevs(ptr)
*
* Parses a string that is in the format of the severity definitions.
* Returns a pointer to a (malloc'd) structure that contains the
* definition, or (struct sevstr *)NULL if none was parsed.
*
* Arguments:
* ptr char *
* References the string from which data is to be extracted.
* If (char *)NULL, continue where we left off. Otherwise,
* start with the string referenced by ptr.
*
* Returns: struct sevstr *
* A pointer to a malloc'd structure containing the severity definition
* parsed from string, or (struct sevstr *)NULL if none.
*
* Notes:
* - This function is destructive to the string referenced by its argument.
*/
/* Static data */
static struct sevstr *
{
char *p; /* Temp pointer */
/* Start anew or start where we left off? */
/* If nothing to parse, return (char *)NULL */
}
/*
* Look through the string "current" for a token of the form
* <kywd>,<sev>,<printstring> delimited by ':' or '\0'
*/
/* Loop initializations */
while (!done) {
/* Eat leading junk */
}
/* If we've found a <kywd>,... */
if (*tokend == ',') {
*tokend = '\0';
/* Look for <kywd>,<sev>,... */
*tokend = '\0';
/* Make sure <sev> > 4 */
/*
* Found <kywd>,<sev>,<printstring>.
* remember where we left off
*/
if (*(tokend =
*tokend = '\0';
(ptrdiff_t)1;
} else {
}
/*
* Alloc structure to contain
* severity definition
*/
sizeof (struct sevstr));
/* Fill in structure */
}
} else {
/*
* Invalid severity value,
* eat thru end of token
*/
':') {
current++;
}
}
} else {
/*
* Invalid severity definition,
* eat thru end of token
*/
if (*tokend == ':')
current++;
}
} else {
/* End of string found */
}
} /* while (!done) */
/* Finished */
return (rtnval);
}
/*
* void msgverbset()
*
* Parces the argument of the MSGVERB environment variable and places
* a representation of the value of that value in "msgverb"
*
* Arguments:
* None:
*
* Returns: void
*
* Notes:
*/
static void
msgverbset(void)
{
/* Rid ourselves of junk in "msgverb" */
msgverb = 0;
/* Get the value of MSGVERB. If none, use default value */
} else { /* MSGVERB has a value. Interpret it */
} else {
/* Make a copy of the value of MSGVERB */
/* Parse the options given by the user */
/*
* Find end of the next token and squeeze
* out escaped characters
*/
/* Delimit token and mark next, if any */
if (*tokend == ':') {
*tokend = '\0';
} else {
}
/* Check for "text" */
/* Check for "label" */
/* Check for "action */
/* Check for "severity" */
/* Check for "tag" */
/* Unknown, ignore MSGVERB value */
} else {
}
} /* do while */
/*
* Use default if no keywords on MSGVERB
* environment variable
*/
if (msgverb == 0)
/* Free allocated space */
}
}
/* Finished */
/* return; */
}
/*
* void sevstrset()
*
* This function builds a structure containing auxillary severity
* definitions.
*
* Arguments: None
*
* Returns: Void
*/
static void
sevstrset(void)
{
char *value;
/* Look for SEV_LEVEL definition */
/* Allocate space and make a copy of the value of SEV_LEVEL */
/* Continue for all severity descriptions */
}
}
} /* if sevspace != (char *)NULL */
} /* if value != (char *)NULL */
}
/*
* int addseverity(value, string)
* int value Value of the severity
* const char *string Print-string for the severity
*
* Arguments:
* value int
* The integer value of the severity being added
* string char *
* A pointer to the character-string to be printed
* whenever a severity of "value" is printed
*
* Returns: int
* Zero if successful, -1 if failed. The function can fail under
* the following circumstances:
* - libc_malloc() fails
* - The "value" is one of the reserved values.
*
* This function permits C applications to define severity-levels
* that augment the standard levels and those defined by the
* SEV_LEVEL environment variable.
*/
int
{
struct sevstr *p; /* Temp ptr to severity structs */
struct sevstr *q; /* Temp ptr(follower) to severity */
/* Make sure we're not trying to redefine one of the reserved values */
if (value <= 4) {
return (-1);
}
/* Make sure we've interpreted SEV_LEVEL */
if (sevlook) {
sevstrset();
}
/*
* Leaf through the list. We may be redefining or removing a
* definition
*/
p = p->sevnext) {
/* We've a match. Remove or modify the entry */
} else {
}
libc_free(p);
} else {
}
}
q = p;
}
/* Adding a definition */
/* Allocate space for the severity structure */
return (-1);
}
/*
* Fill in the new structure with the data supplied and add to
* the head of the augmented severity list.
*/
paugsevs = p;
/* Successfully added a new severity */
rtnval = 0;
/* Attempting to undefined a non-defined severity */
rtnval = -1;
} else {
/* Successfully redefined a severity */
rtnval = 0;
}
/* Finished, successful */
return (rtnval);
}
/*
* Utility function for converting an integer to a string, avoiding stdio.
*/
static void
itoa(int n, char *s)
{
do {
un /= 10;
} while (un);
if (n < 0)
*s++ = '-';
do {
*s++ = *--cp;
*s = '\0';
}
/*
* void writemsg(buf, size, verbosity, label, severity, text, action, tag)
*
* Arguments:
* char *buf The buffer in which to format the message
* size_t size The size of the buffer
* int verbosity A bit-string that indicates which components
* are to be written
* const char *label The address of the label-component
* int severity The severity value of the message
* const char *text The address of the text-component
* const char *action The address of the action-component
* const char *tag The address of the tag-component
*
* This function formats the message consisting of the label-component,
* severity-component, text-component, action-component, and tag-
* component into the provided buffer. The "verbosity" argument
* tells which components can be selected. Any or all of the
* components can be their null-values.
*
* Returns: void
*
* Notes:
*/
static void
{
char *p; /* General purpose pointer */
int i; /* General purpose counter */
char c; /* Temp, multiuse character */
/* truncated) label */
/* truncated) tag */
/*
* initialize variables.
*/
sevpstrbuf[0] = (char)0;
lcllbl[0] = (char)0;
lcltag[0] = (char)0;
/*
* Figure out what fields are to be written (all are optional)
*/
/*
* Figure out how much we'll need to indent the text of the message
*/
/* Count the label of the message, if requested */
textindent = 0;
if (dolabel) {
}
/*
* If severity req'd, determine the severity string and factor
* into indent count. Severity string generated by:
* 1. Search the standard list of severities.
* 2. Search the severities added by the application.
* 3. Search the severities added by the environment.
* 4. Use the default (SV=n where n is the value of the severity).
*/
if (dosev) {
/* Search the default severity definitions */
break;
}
/*
* Search the severity definitions
* added by the application
*/
break;
}
/*
* Search the severity definitions
* added by the environment
*/
break;
}
/* Use default string, SV=severity */
} else {
}
} else {
}
} else {
}
/* Factor into indent counts */
}
/*
* Figure out the indents.
*/
if (textindent > ACTINTROLN) {
l1indent = 0;
} else {
l2indent = 0;
} else {
textindent = 0;
l1indent = 0;
}
}
} else {
l1indent = 0;
l2indent = 0;
if (doaction) {
} else if (dotext) {
actindent = 0;
}
}
/*
* Write the message.
*/
/* Write the LABEL, if requested */
if (dolabel) {
/* Write spaces to align on the ':' char, if needed */
*buf++ = ' ';
/* Write the label */
/*
* Write the separator string
* (if another component is to follow)
*/
}
/* Write the SEVERITY, if requested */
if (dosev) {
/* Write spaces to align on the ':' char, if needed */
*buf++ = ' ';
/* Write the severity print-string */
/*
* Write the separator string
* (if another component is to follow)
*/
}
/* Write the TEXT, if requested */
if (dotext) {
p = (char *)text;
*buf++ = c;
if (c == '\n') {
*buf++ = ' ';
}
}
}
/*
* Write ACTION if requested.
*/
if (doaction) {
*buf++ = '\n';
*buf++ = ' ';
}
/* Write the action-string's introduction */
/* Write the "action" string */
p = (char *)action;
*buf++ = c;
if (c == '\n') {
*buf++ = ' ';
}
}
}
/*
* Write the TAG if requested
*/
if (dotag) {
if (doaction)
*buf++ = '\n';
}
/*
* Write terminating newline and null byte.
* We reserved space for these at the start.
*/
*buf++ = '\n';
*buf++ = '\0';
}
/*
* int fmtmsg(class, label, severity, text, action, tag)
* long class
* const char *label
* int severity
* const char *text
* const char *action
* const char *tag
*
* If requested, the fmtmsg() function writes a message to the standard
* error stream in the standard message format. Also if requested, it
* will write a message to the system console.
*
* Arguments:
* class Fields which classify the message for the system
* logging facility
* label A character-string that is printed as the "label"
* of the message. Typically identifies the source
* of the message
* severity Identifies the severity of the message. Either one
* of the standard severities, or possibly one of the
* augmented severities
* text Pointer to the text of the message
* action Pointer to a char string that describes some type
* of corrective action.
* tag A character-string that is printed as the "tag" or
* the message. Typically a pointer to documentation
*
* Returns:
* -1 if nothing was generated, 0 if everything requested was
* generated, or flags if partially generated.
*
* Needs:
* - Nothing special for 4.0.
*/
int
{
char *message1;
char *message2;
/*
* Determine the "verbosity" of the message. If "msgverb" is
* already set, don't interrogate the "MSGVERB" environment vbl.
* If so, interrogate "MSGVERB" and do initialization stuff also.
*/
msgverbset();
}
/*
* Extract the severity definitions from the SEV_LEVEL
* environment variable and save away for later.
*/
if (sevlook) {
sevstrset();
}
/* Set up the default text component [if text==(char *)NULL] */
text = DEFLT_TEXT;
/* Prepare the message for stderr if requested */
}
/* Prepare the message for the console if requested */
if (class & MM_CONSOLE) {
}
/* Write the message to stderr if requested */
}
/* Write the message to the console if requested */
if (class & MM_CONSOLE) {
} else {
}
}
return (rtnval);
}