Home | History | Annotate | Download | only in common
      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 /*
     23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 #pragma ident	"@(#)globals.c	1.15	07/09/18 SMI"
     27 
     28 #include	<stdio.h>
     29 #include	<strings.h>
     30 #include	<sys/machelf.h>
     31 #include	"_conv.h"
     32 #include	"globals_msg.h"
     33 
     34 
     35 /*
     36  * Given an integer value, generate an ASCII representation of it.
     37  *
     38  * entry:
     39  *	inv_buf - Buffer into which the resulting string is generated.
     40  *	value - Value to be formatted.
     41  *	fmt_flags - CONV_FMT_* values, used to specify formatting details.
     42  *
     43  * exit:
     44  *	The formatted string is placed into inv_buf. The pointer
     45  *	to the string is returned.
     46  */
     47 const char *
     48 conv_invalid_val(Conv_inv_buf_t *inv_buf, Xword value,
     49     Conv_fmt_flags_t fmt_flags)
     50 {
     51 	const char	*fmt;
     52 
     53 	if (fmt_flags & CONV_FMT_DECIMAL) {
     54 		if (fmt_flags & CONV_FMT_SPACE)
     55 			fmt = MSG_ORIG(MSG_GBL_FMT_DECS);
     56 		else
     57 			fmt = MSG_ORIG(MSG_GBL_FMT_DEC);
     58 	} else {
     59 		if (fmt_flags & CONV_FMT_SPACE)
     60 			fmt = MSG_ORIG(MSG_GBL_FMT_HEXS);
     61 		else
     62 			fmt = MSG_ORIG(MSG_GBL_FMT_HEX);
     63 	}
     64 	(void) snprintf(inv_buf->buf, sizeof (inv_buf->buf), fmt, value);
     65 	return ((const char *)inv_buf->buf);
     66 }
     67 
     68 
     69 
     70 /*
     71  * cef_cp() is used by conv_expn_field() to fill in the output buffer.
     72  * A CONV_EXPN_FIELD_STATE variable is used to maintain the buffer state
     73  * as the operation progresses.
     74  *
     75  * entry:
     76  *	arg - As passed to conv_expn_field().
     77  *	state - Variable used to maintain buffer state between calls.
     78  *	list_item - TRUE(1) if this is a list item, and FALSE(0)
     79  *		if it is something else.
     80  *	str - String to be added to the buffer.
     81  *
     82  * exit:
     83  *	On Success:
     84  *		buffer contains the output string, including a list
     85  *		separator if appropriate. state has been updated.
     86  *		TRUE(1) is returned.
     87  *	On Failure:
     88  *		Buffer contains the numeric representation for the flags,
     89  *		and FALSE(0) is returned.
     90  */
     91 typedef struct {
     92 	char *cur;		/* Current output position in buf */
     93 	size_t room;		/* # of bytes left in buf */
     94 	int list_cnt;		/* # of list items output into buf  */
     95 	const char *sep_str;	/* String used as list separator */
     96 	int sep_str_len;	/* strlen(sep_str) */
     97 } CONV_EXPN_FIELD_STATE;
     98 
     99 static int
    100 cef_cp(CONV_EXPN_FIELD_ARG *arg, CONV_EXPN_FIELD_STATE *state,
    101 	int list_item, const char *str)
    102 {
    103 	Conv_inv_buf_t inv_buf;
    104 	int n;
    105 
    106 	if (list_item) {	/* This is a list item */
    107 		/*
    108 		 * If list is non-empty, and the buffer has room,
    109 		 * then insert the separator.
    110 		 */
    111 		if (state->list_cnt != 0) {
    112 			if (state->sep_str_len < state->room) {
    113 				(void) memcpy(state->cur, state->sep_str,
    114 				    state->sep_str_len);
    115 				state->cur += state->sep_str_len;
    116 				state->room -= state->sep_str_len;
    117 			} else {
    118 				/* Ensure code below will catch lack of room */
    119 				state->room = 0;
    120 			}
    121 		}
    122 		state->list_cnt++;
    123 	}
    124 
    125 	n = strlen(str);
    126 	if (n < state->room) {
    127 		(void) memcpy(state->cur, str, n);
    128 		state->cur += n;
    129 		state->room -= n;
    130 		return (TRUE);
    131 	}
    132 
    133 	/* Buffer too small. Fill in the numeric value and report failure */
    134 	(void) conv_invalid_val(&inv_buf, arg->oflags, 0);
    135 	(void) strlcpy(arg->buf, inv_buf.buf, arg->bufsize);
    136 	return (FALSE);
    137 }
    138 
    139 
    140 
    141 /*
    142  * Provide a focal point for expanding bit-fields values into
    143  * their corresponding strings.
    144  *
    145  * entry:
    146  *	arg - Specifies the operation to be carried out. See the
    147  *		definition of CONV_EXPN_FIELD_ARG in conv.h for details.
    148  *
    149  * exit:
    150  *	arg->buf contains the formatted result. True (1) is returned if there
    151  *	was no error, and False (0) if the buffer was too small. In the failure
    152  *	case, arg->buf contains a numeric representation of the value.
    153  */
    154 int
    155 conv_expn_field(CONV_EXPN_FIELD_ARG *arg, Conv_fmt_flags_t fmt_flags)
    156 {
    157 	const Val_desc *vde;
    158 	CONV_EXPN_FIELD_STATE state;
    159 	Xword rflags = arg->rflags;
    160 	const char **lead_str;
    161 
    162 
    163 	/* Initialize buffer state */
    164 	state.cur = arg->buf;
    165 	state.room = arg->bufsize;
    166 	state.list_cnt = 0;
    167 	state.sep_str = arg->sep ? arg->sep : MSG_ORIG(MSG_GBL_SEP);
    168 	state.sep_str_len = strlen(state.sep_str);
    169 
    170 	/* Prefix string */
    171 	if ((fmt_flags & CONV_FMT_NOBKT) == 0)
    172 		if (!cef_cp(arg, &state, FALSE,
    173 		    (arg->prefix ? arg->prefix : MSG_ORIG(MSG_GBL_OSQBRKT))))
    174 			return (FALSE);
    175 
    176 	/* Any strings in the lead_str array go at the head of the list */
    177 	lead_str = arg->lead_str;
    178 	if (lead_str) {
    179 		while (*lead_str) {
    180 			if (!cef_cp(arg, &state, TRUE, *lead_str++))
    181 				return (FALSE);
    182 		}
    183 	}
    184 
    185 	/*
    186 	 * Traverse the callers Val_desc array and determine if the value
    187 	 * corresponds to any array item and add those that are to the list.
    188 	 */
    189 	for (vde = arg->vdp; vde->v_msg; vde++) {
    190 		if (arg->oflags & vde->v_val) {
    191 			if (!cef_cp(arg, &state, TRUE, vde->v_msg))
    192 				return (FALSE);
    193 
    194 			/* Indicate this item has been collected */
    195 			rflags &= ~(vde->v_val);
    196 		}
    197 	}
    198 
    199 	/*
    200 	 * If any flags remain, then they are unidentified.  Add the numeric
    201 	 * representation of these flags to the users output buffer.
    202 	 */
    203 	if (rflags) {
    204 		Conv_inv_buf_t inv_buf;
    205 
    206 		(void) conv_invalid_val(&inv_buf, rflags, fmt_flags);
    207 		if (!cef_cp(arg, &state, TRUE, inv_buf.buf))
    208 			return (FALSE);
    209 	}
    210 
    211 	/* Suffix string */
    212 	if ((fmt_flags & CONV_FMT_NOBKT) == 0)
    213 		if (!cef_cp(arg, &state, FALSE,
    214 		    (arg->suffix ? arg->suffix : MSG_ORIG(MSG_GBL_CSQBRKT))))
    215 			return (FALSE);
    216 
    217 	/* Terminate the buffer */
    218 	*state.cur = '\0';
    219 
    220 	return (TRUE);
    221 }
    222