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 <_machelf.h>
30 #include "_conv.h"
31 #include "globals_msg.h"
32
33
34 /*
35 * Given an integer value, generate an ASCII representation of it.
36 *
37 * entry:
38 * inv_buf - Buffer into which the resulting string is generated.
39 * value - Value to be formatted.
40 * fmt_flags - CONV_FMT_* values, used to specify formatting details.
41 *
42 * exit:
43 * The formatted string is placed into inv_buf. The pointer
44 * to the string is returned.
45 */
46 const char *
conv_invalid_val(Conv_inv_buf_t * inv_buf,Xword value,Conv_fmt_flags_t fmt_flags)47 conv_invalid_val(Conv_inv_buf_t *inv_buf, Xword value,
48 Conv_fmt_flags_t fmt_flags)
49 {
50 const char *fmt;
51
52 if (fmt_flags & CONV_FMT_DECIMAL) {
53 if (fmt_flags & CONV_FMT_SPACE)
54 fmt = MSG_ORIG(MSG_GBL_FMT_DECS);
55 else
56 fmt = MSG_ORIG(MSG_GBL_FMT_DEC);
57 } else {
58 if (fmt_flags & CONV_FMT_SPACE)
59 fmt = MSG_ORIG(MSG_GBL_FMT_HEXS);
60 else
61 fmt = MSG_ORIG(MSG_GBL_FMT_HEX);
62 }
63 (void) snprintf(inv_buf->buf, sizeof (inv_buf->buf), fmt, value);
64 return ((const char *)inv_buf->buf);
65 }
66
67
68
69 /*
70 * cef_cp() is used by conv_expn_field() to fill in the output buffer.
71 * A CONV_EXPN_FIELD_STATE variable is used to maintain the buffer state
72 * as the operation progresses.
73 *
74 * entry:
75 * arg - As passed to conv_expn_field().
76 * state - Variable used to maintain buffer state between calls.
77 * list_item - TRUE(1) if this is a list item, and FALSE(0)
78 * if it is something else.
79 * str - String to be added to the buffer.
80 *
81 * exit:
82 * On Success:
83 * buffer contains the output string, including a list
84 * separator if appropriate. state has been updated.
85 * TRUE(1) is returned.
86 * On Failure:
87 * Buffer contains the numeric representation for the flags,
88 * and FALSE(0) is returned.
89 */
90 typedef struct {
91 char *cur; /* Current output position in buf */
92 size_t room; /* # of bytes left in buf */
93 int list_cnt; /* # of list items output into buf */
94 const char *sep_str; /* String used as list separator */
95 int sep_str_len; /* strlen(sep_str) */
96 } CONV_EXPN_FIELD_STATE;
97
98 static int
cef_cp(CONV_EXPN_FIELD_ARG * arg,CONV_EXPN_FIELD_STATE * state,int list_item,const char * str)99 cef_cp(CONV_EXPN_FIELD_ARG *arg, CONV_EXPN_FIELD_STATE *state,
100 int list_item, const char *str)
101 {
102 Conv_inv_buf_t inv_buf;
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(&inv_buf, arg->oflags, 0);
134 (void) strlcpy(arg->buf, inv_buf.buf, arg->bufsize);
135 return (FALSE);
136 }
137
138
139
140 /*
141 * Common setup code for conv_expn_field() and conv_expn_field2()
142 */
143 static int
cef_setup(CONV_EXPN_FIELD_ARG * arg,Conv_fmt_flags_t fmt_flags,CONV_EXPN_FIELD_STATE * state)144 cef_setup(CONV_EXPN_FIELD_ARG *arg, Conv_fmt_flags_t fmt_flags,
145 CONV_EXPN_FIELD_STATE *state)
146 {
147 const char **lead_str;
148
149 /* Initialize buffer state */
150 state->cur = arg->buf;
151 state->room = arg->bufsize;
152 state->list_cnt = 0;
153 state->sep_str = arg->sep ? arg->sep : MSG_ORIG(MSG_GBL_SEP);
154 state->sep_str_len = strlen(state->sep_str);
155
156 /* Prefix string */
157 if ((fmt_flags & CONV_FMT_NOBKT) == 0)
158 if (!cef_cp(arg, state, FALSE,
159 (arg->prefix ? arg->prefix : MSG_ORIG(MSG_GBL_OSQBRKT))))
160 return (FALSE);
161
162 /* Any strings in the lead_str array go at the head of the list */
163 lead_str = arg->lead_str;
164 if (lead_str) {
165 while (*lead_str) {
166 if (!cef_cp(arg, state, TRUE, *lead_str++))
167 return (FALSE);
168 }
169 }
170
171 return (TRUE);
172 }
173
174 /*
175 * Common finishing code for conv_expn_field() and conv_expn_field2()
176 */
177 static int
cef_wrap(CONV_EXPN_FIELD_ARG * arg,Conv_fmt_flags_t fmt_flags,CONV_EXPN_FIELD_STATE * state,Xword rflags)178 cef_wrap(CONV_EXPN_FIELD_ARG *arg, Conv_fmt_flags_t fmt_flags,
179 CONV_EXPN_FIELD_STATE *state, Xword rflags)
180 {
181 /*
182 * If any flags remain, then they are unidentified. Add the numeric
183 * representation of these flags to the users output buffer.
184 */
185 if (rflags) {
186 Conv_inv_buf_t inv_buf;
187
188 (void) conv_invalid_val(&inv_buf, rflags, fmt_flags);
189 if (!cef_cp(arg, state, TRUE, inv_buf.buf))
190 return (FALSE);
191 }
192
193 /* Suffix string */
194 if ((fmt_flags & CONV_FMT_NOBKT) == 0)
195 if (!cef_cp(arg, state, FALSE,
196 (arg->suffix ? arg->suffix : MSG_ORIG(MSG_GBL_CSQBRKT))))
197 return (FALSE);
198
199 /* Terminate the buffer */
200 *state->cur = '\0';
201
202 return (TRUE);
203 }
204
205 /*
206 * Provide a focal point for expanding bit-fields values into
207 * their corresponding strings.
208 *
209 * entry:
210 * arg - Specifies the operation to be carried out. See the
211 * definition of CONV_EXPN_FIELD_ARG in conv.h for details.
212 * vdp - Array of value descriptors, giving the possible bit values,
213 * and their corresponding strings. Note that the final element
214 * must contain only NULL values. This terminates the list.
215 *
216 * exit:
217 * arg->buf contains the formatted result. True (1) is returned if there
218 * was no error, and False (0) if the buffer was too small. In the failure
219 * case, arg->buf contains a numeric representation of the value.
220 *
221 * note:
222 * The Val_desc2 variant of this routine ignores entries from vdp that
223 * have a non-zero osabi or machine value that does not match that
224 * supplied by the caller.
225 */
226 /*ARGSUSED3*/
227 int
_conv_expn_field(CONV_EXPN_FIELD_ARG * arg,const Val_desc * vdp,Conv_fmt_flags_t fmt_flags,const char * local_sgs_msg)228 _conv_expn_field(CONV_EXPN_FIELD_ARG *arg, const Val_desc *vdp,
229 Conv_fmt_flags_t fmt_flags, const char *local_sgs_msg)
230 {
231 CONV_EXPN_FIELD_STATE state;
232 Xword rflags = arg->rflags;
233
234 if (cef_setup(arg, fmt_flags, &state) == FALSE)
235 return (FALSE);
236
237 /*
238 * Traverse the callers Val_desc array and determine if the value
239 * corresponds to any array item and add those that are to the list.
240 */
241 for (; vdp->v_msg; vdp++) {
242 if (arg->oflags & vdp->v_val) {
243 if (!cef_cp(arg, &state, TRUE,
244 MSG_ORIG_STRTAB(vdp->v_msg, local_sgs_msg)))
245 return (FALSE);
246
247 /* Indicate this item has been collected */
248 rflags &= ~(vdp->v_val);
249 }
250 }
251
252 return (cef_wrap(arg, fmt_flags, &state, rflags));
253 }
254
255 /*ARGSUSED5*/
256 int
_conv_expn_field2(CONV_EXPN_FIELD_ARG * arg,uchar_t osabi,Half mach,const Val_desc2 * vdp,Conv_fmt_flags_t fmt_flags,const char * local_sgs_msg)257 _conv_expn_field2(CONV_EXPN_FIELD_ARG *arg, uchar_t osabi, Half mach,
258 const Val_desc2 *vdp, Conv_fmt_flags_t fmt_flags, const char *local_sgs_msg)
259 {
260 CONV_EXPN_FIELD_STATE state;
261 Xword rflags = arg->rflags;
262
263 if (cef_setup(arg, fmt_flags, &state) == FALSE)
264 return (FALSE);
265
266 /*
267 * Traverse the callers Val_desc array and determine if the value
268 * corresponds to any array item and add those that are to the list.
269 */
270 for (; vdp->v_msg; vdp++) {
271 if (CONV_VD2_SKIP(osabi, mach, vdp))
272 continue;
273
274 if (arg->oflags & vdp->v_val) {
275 if (!cef_cp(arg, &state, TRUE,
276 MSG_ORIG_STRTAB(vdp->v_msg, local_sgs_msg)))
277 return (FALSE);
278
279 /* Indicate this item has been collected */
280 rflags &= ~(vdp->v_val);
281 }
282 }
283
284 return (cef_wrap(arg, fmt_flags, &state, rflags));
285 }
286