xref: /illumos-gate/usr/src/cmd/sgs/libconv/common/globals.c (revision ba4e3c84e6b9390bbf7df80b5f1d11dec34cc525)
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 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% 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  *	string - Buffer into which the resulting string is generated.
40  *	size - Size of string buffer (i.e. sizeof(string))
41  *	value - Value to be formatted.
42  *	fmt_flags - CONV_FMT_* values, used to specify formatting details.
43  *
44  * exit:
45  *	The formatted string, or as much as will fit, is placed into
46  *	string. String is returned.
47  */
48 const char *
49 conv_invalid_val(char *string, size_t size, Xword value, int 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(string, size, fmt, value);
65 	return ((const char *)string);
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 	int n;
104 
105 	if (list_item) {	/* This is a list item */
106 		/*
107 		 * If list is non-empty, and the buffer has room,
108 		 * then insert the separator.
109 		 */
110 		if (state->list_cnt != 0) {
111 			if (state->sep_str_len < state->room) {
112 				(void) memcpy(state->cur, state->sep_str,
113 					state->sep_str_len);
114 				state->cur += state->sep_str_len;
115 				state->room -= state->sep_str_len;
116 			} else {
117 				/* Ensure code below will catch lack of room */
118 				state->room = 0;
119 			}
120 		}
121 		state->list_cnt++;
122 	}
123 
124 	n = strlen(str);
125 	if (n < state->room) {
126 		(void) memcpy(state->cur, str, n);
127 		state->cur += n;
128 		state->room -= n;
129 		return (TRUE);
130 	}
131 
132 	/* Buffer too small. Fill in the numeric value and report failure */
133 	(void) conv_invalid_val(arg->buf, arg->bufsize, arg->oflags, 0);
134 	return (FALSE);
135 }
136 
137 
138 
139 /*
140  * Provide a focal point for expanding bit-fields values into
141  * their corresponding strings.
142  *
143  * entry:
144  *	arg - Specifies the operation to be carried out. See the
145  *		definition of CONV_EXPN_FIELD_ARG in conv.h for details.
146  *
147  * exit:
148  *	arg->buf contains the formatted result. True (1) is returned if there
149  *	was no error, and False (0) if the buffer was too small. In the failure
150  *	case, arg->buf contains a numeric representation of the value.
151  */
152 int
153 conv_expn_field(CONV_EXPN_FIELD_ARG *arg)
154 {
155 	const Val_desc *vde;
156 	CONV_EXPN_FIELD_STATE state;
157 	Xword rflags = arg->rflags;
158 	const char **lead_str;
159 
160 
161 	/* Initialize buffer state */
162 	state.cur = arg->buf;
163 	state.room = arg->bufsize;
164 	state.list_cnt = 0;
165 	state.sep_str = arg->sep ? arg->sep : MSG_ORIG(MSG_GBL_SEP);
166 	state.sep_str_len = strlen(state.sep_str);
167 
168 	/* Prefix string */
169 	if (!cef_cp(arg, &state, FALSE,
170 	    (arg->prefix ? arg->prefix : MSG_ORIG(MSG_GBL_OSQBRKT))))
171 		return (FALSE);
172 
173 	/* Any strings in the lead_str array go at the head of the list */
174 	lead_str = arg->lead_str;
175 	if (lead_str) {
176 		while (*lead_str) {
177 			if (!cef_cp(arg, &state, TRUE, *lead_str++))
178 				return (FALSE);
179 		}
180 	}
181 
182 	/*
183 	 * Traverse the callers Val_desc array and determine if the value
184 	 * corresponds to any array item and add those that are to the list.
185 	 */
186 	for (vde = arg->vdp; vde->v_msg; vde++) {
187 		if (arg->oflags & vde->v_val) {
188 			if (!cef_cp(arg, &state, TRUE, vde->v_msg))
189 				return (FALSE);
190 
191 			/* Indicate this item has been collected */
192 			rflags &= ~(vde->v_val);
193 		}
194 	}
195 
196 	/*
197 	 * If any flags remain, then they are unidentified.  Add the numeric
198 	 * representation of these flags to the users output buffer.
199 	 */
200 	if (rflags) {
201 		char ibuf[CONV_INV_STRSIZE];
202 
203 		(void) conv_invalid_val(ibuf, sizeof (ibuf), rflags, 0);
204 		if (!cef_cp(arg, &state, TRUE, ibuf))
205 			return (FALSE);
206 	}
207 
208 	/* Suffix string */
209 	if (!cef_cp(arg, &state, FALSE,
210 	    (arg->suffix ? arg->suffix : MSG_ORIG(MSG_GBL_CSQBRKT))))
211 		return (FALSE);
212 
213 	/* Terminate the buffer */
214 	*state.cur = '\0';
215 
216 	return (TRUE);
217 }
218