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 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28 /*
29 * Translate a string into C literal string constant notation.
30 */
31
32 #include <stdio.h>
33 #include <ctype.h>
34 #include <_conv.h>
35 #include <c_literal_msg.h>
36
37
38 /*
39 * Convert characters to the form used by the C language to represent
40 * literal strings:
41 * - Printable characters are shown as themselves
42 * - Convert special characters to their 2-character escaped forms:
43 * alert (bell) \a
44 * backspace \b
45 * formfeed \f
46 * newline \n
47 * return \r
48 * horizontal tab \t
49 * vertical tab \v
50 * backspace \\
51 * single quote \'
52 * double quote \"
53 * - Display other non-printable characters as 4-character escaped
54 * octal constants.
55 *
56 * entry:
57 * buf - Buffer of characters to be processed
58 * n # of characters in buf to be processed
59 * outfunc - Function to be called to move output characters.
60 * uvalue - User value. This argument is passed to outfunc without
61 * examination. The caller can use it to pass additional
62 * information required by the callback.
63 *
64 * exit:
65 * The string has been processed, with the resulting data passed
66 * to outfunc for processing.
67 */
68 void
conv_str_to_c_literal(const char * buf,size_t n,Conv_str_to_c_literal_func_t * outfunc,void * uvalue)69 conv_str_to_c_literal(const char *buf, size_t n,
70 Conv_str_to_c_literal_func_t *outfunc, void *uvalue)
71 {
72 char bs_buf[2]; /* For two-character backslash codes */
73 char octal_buf[10]; /* For \000 style octal constants */
74
75 bs_buf[0] = '\\';
76 while (n > 0) {
77 switch (*buf) {
78 case '\0':
79 bs_buf[1] = '0';
80 break;
81 case '\a':
82 bs_buf[1] = 'a';
83 break;
84 case '\b':
85 bs_buf[1] = 'b';
86 break;
87 case '\f':
88 bs_buf[1] = 'f';
89 break;
90 case '\n':
91 bs_buf[1] = 'n';
92 break;
93 case '\r':
94 bs_buf[1] = 'r';
95 break;
96 case '\t':
97 bs_buf[1] = 't';
98 break;
99 case '\v':
100 bs_buf[1] = 'v';
101 break;
102 case '\\':
103 bs_buf[1] = '\\';
104 break;
105 case '\'':
106 bs_buf[1] = '\'';
107 break;
108 case '"':
109 bs_buf[1] = '"';
110 break;
111 default:
112 bs_buf[1] = '\0';
113 }
114
115 if (bs_buf[1] != '\0') {
116 (*outfunc)(bs_buf, 2, uvalue);
117 buf++;
118 n--;
119 } else if (isprint(*buf)) {
120 /*
121 * Output the entire sequence of printable
122 * characters in a single shot.
123 */
124 const char *start = buf;
125 size_t outlen = 0;
126
127 for (start = buf; (n > 0) && isprint(*buf); buf++, n--)
128 outlen++;
129 (*outfunc)(start, outlen, uvalue);
130 } else {
131 /* Generic unprintable character: Use octal notation */
132 (void) snprintf(octal_buf, sizeof (octal_buf),
133 MSG_ORIG(MSG_FMT_OCTCONST), (uchar_t)*buf);
134 (*outfunc)(octal_buf, strlen(octal_buf), uvalue);
135 buf++;
136 n--;
137 }
138 }
139 }
140
141 /*
142 * Given the pointer to the character following a '\' character in
143 * a C style literal, return the ASCII character code it represents,
144 * and advance the string pointer to the character following the last
145 * character in the escape sequence.
146 *
147 * entry:
148 * str - Address of string pointer to first character following
149 * the backslash.
150 *
151 * exit:
152 * If the character is not valid, -1 is returned. Otherwise
153 * it returns the ASCII code for the translated character, and
154 * *str has been advanced.
155 */
156 int
conv_translate_c_esc(char ** str)157 conv_translate_c_esc(char **str)
158 {
159 char *s = *str;
160 int ch, i;
161
162 ch = *s++;
163 switch (ch) {
164 case 'a':
165 ch = '\a';
166 break;
167 case 'b':
168 ch = '\b';
169 break;
170 case 'f':
171 ch = '\f';
172 break;
173 case 'n':
174 ch = '\n';
175 break;
176 case 'r':
177 ch = '\r';
178 break;
179 case 't':
180 ch = '\t';
181 break;
182 case 'v':
183 ch = '\v';
184 break;
185
186 case '0':
187 case '1':
188 case '2':
189 case '3':
190 case '4':
191 case '5':
192 case '6':
193 case '7':
194 /* Octal constant: There can be up to 3 digits */
195 ch -= '0';
196 for (i = 0; i < 2; i++) {
197 if ((*s < '0') || (*s > '7'))
198 break;
199 ch = (ch << 3) + (*s++ - '0');
200 }
201 break;
202
203 /*
204 * There are some cases where ch already has the desired value.
205 * These cases exist simply to remove the special meaning that
206 * character would otherwise have. We need to match them to
207 * prevent them from falling into the default error case.
208 */
209 case '\\':
210 case '\'':
211 case '"':
212 break;
213
214 default:
215 ch = -1;
216 break;
217 }
218
219 *str = s;
220 return (ch);
221 }
222