globals_machelf.c revision 9273:9a0603d78ad3
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 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include	<stdio.h>
28#include	<strings.h>
29#include	<ctype.h>
30#include	<_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 */
47const char *
48conv_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 */
91typedef 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
99static int
100cef_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 * Common setup code for conv_expn_field() and conv_expn_field2()
143 */
144static int
145cef_setup(CONV_EXPN_FIELD_ARG *arg, Conv_fmt_flags_t fmt_flags,
146    CONV_EXPN_FIELD_STATE *state)
147{
148	const char **lead_str;
149
150	/* Initialize buffer state */
151	state->cur = arg->buf;
152	state->room = arg->bufsize;
153	state->list_cnt = 0;
154	state->sep_str = arg->sep ? arg->sep : MSG_ORIG(MSG_GBL_SEP);
155	state->sep_str_len = strlen(state->sep_str);
156
157	/* Prefix string */
158	if ((fmt_flags & CONV_FMT_NOBKT) == 0)
159		if (!cef_cp(arg, state, FALSE,
160		    (arg->prefix ? arg->prefix : MSG_ORIG(MSG_GBL_OSQBRKT))))
161			return (FALSE);
162
163	/* Any strings in the lead_str array go at the head of the list */
164	lead_str = arg->lead_str;
165	if (lead_str) {
166		while (*lead_str) {
167			if (!cef_cp(arg, state, TRUE, *lead_str++))
168				return (FALSE);
169		}
170	}
171
172	return (TRUE);
173}
174
175/*
176 * Common finishing code for conv_expn_field() and conv_expn_field2()
177 */
178static int
179cef_wrap(CONV_EXPN_FIELD_ARG *arg, Conv_fmt_flags_t fmt_flags,
180    CONV_EXPN_FIELD_STATE *state, Xword rflags)
181{
182	/*
183	 * If any flags remain, then they are unidentified.  Add the numeric
184	 * representation of these flags to the users output buffer.
185	 */
186	if (rflags) {
187		Conv_inv_buf_t inv_buf;
188
189		(void) conv_invalid_val(&inv_buf, rflags, fmt_flags);
190		if (!cef_cp(arg, state, TRUE, inv_buf.buf))
191			return (FALSE);
192	}
193
194	/* Suffix string */
195	if ((fmt_flags & CONV_FMT_NOBKT) == 0)
196		if (!cef_cp(arg, state, FALSE,
197		    (arg->suffix ? arg->suffix : MSG_ORIG(MSG_GBL_CSQBRKT))))
198			return (FALSE);
199
200	/* Terminate the buffer */
201	*state->cur = '\0';
202
203	return (TRUE);
204}
205
206/*
207 * Provide a focal point for expanding bit-fields values into
208 * their corresponding strings.
209 *
210 * entry:
211 *	arg - Specifies the operation to be carried out. See the
212 *		definition of CONV_EXPN_FIELD_ARG in conv.h for details.
213 *	vdp - Array of value descriptors, giving the possible bit values,
214 *		and their corresponding strings. Note that the final element
215 *		must contain only NULL values. This terminates the list.
216 *
217 * exit:
218 *	arg->buf contains the formatted result. True (1) is returned if there
219 *	was no error, and False (0) if the buffer was too small. In the failure
220 *	case, arg->buf contains a numeric representation of the value.
221 *
222 * note:
223 *	The Val_desc2 variant of this routine ignores entries from vdp that
224 *	have a non-zero osabi or machine value that does not match that
225 *	supplied by the caller.
226 */
227/*ARGSUSED3*/
228int
229_conv_expn_field(CONV_EXPN_FIELD_ARG *arg, const Val_desc *vdp,
230    Conv_fmt_flags_t fmt_flags, const char *local_sgs_msg)
231{
232	CONV_EXPN_FIELD_STATE state;
233	Xword rflags = arg->rflags;
234
235	if (cef_setup(arg, fmt_flags, &state) == FALSE)
236		return (FALSE);
237
238	/*
239	 * Traverse the callers Val_desc array and determine if the value
240	 * corresponds to any array item and add those that are to the list.
241	 */
242	for (; vdp->v_msg; vdp++) {
243		if (arg->oflags & vdp->v_val) {
244			if (!cef_cp(arg, &state, TRUE,
245			    MSG_ORIG_STRTAB(vdp->v_msg, local_sgs_msg)))
246				return (FALSE);
247
248			/* Indicate this item has been collected */
249			rflags &= ~(vdp->v_val);
250		}
251	}
252
253	return (cef_wrap(arg, fmt_flags, &state, rflags));
254}
255
256/*ARGSUSED5*/
257int
258_conv_expn_field2(CONV_EXPN_FIELD_ARG *arg, uchar_t osabi, Half mach,
259    const Val_desc2 *vdp, Conv_fmt_flags_t fmt_flags, const char *local_sgs_msg)
260{
261	CONV_EXPN_FIELD_STATE state;
262	Xword rflags = arg->rflags;
263
264	if (cef_setup(arg, fmt_flags, &state) == FALSE)
265		return (FALSE);
266
267	/*
268	 * Traverse the callers Val_desc array and determine if the value
269	 * corresponds to any array item and add those that are to the list.
270	 */
271	for (; vdp->v_msg; vdp++) {
272		if (CONV_VD2_SKIP(osabi, mach, vdp))
273			continue;
274
275		if (arg->oflags & vdp->v_val) {
276			if (!cef_cp(arg, &state, TRUE,
277			    MSG_ORIG_STRTAB(vdp->v_msg, local_sgs_msg)))
278				return (FALSE);
279
280			/* Indicate this item has been collected */
281			rflags &= ~(vdp->v_val);
282		}
283	}
284
285	return (cef_wrap(arg, fmt_flags, &state, rflags));
286}
287