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 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 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