1 /*- 2 * Redistribution and use in source and binary forms, with or without 3 * modification, are permitted provided that the following conditions 4 * are met: 5 * 1. Redistributions of source code must retain the above copyright 6 * notice, this list of conditions and the following disclaimer. 7 * 2. Redistributions in binary form must reproduce the above copyright 8 * notice, this list of conditions and the following disclaimer in the 9 * documentation and/or other materials provided with the distribution. 10 * 11 * Jordan K. Hubbard 12 * 29 August 1998 13 * 14 * Routine for doing backslash elimination. 15 * 16 * $FreeBSD: src/sys/boot/common/interp_backslash.c,v 1.6 2003/08/25 23:30:41 obrien Exp $ 17 * $DragonFly: src/sys/boot/common/interp_backslash.c,v 1.3 2003/11/10 06:08:31 dillon Exp $ 18 */ 19 20 #include <stand.h> 21 #include <string.h> 22 #include "bootstrap.h" 23 24 #define DIGIT(x) (isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A') 25 26 /* 27 * backslash: Return malloc'd copy of str with all standard "backslash 28 * processing" done on it. Original can be free'd if desired. 29 */ 30 char * 31 backslash(char *str) 32 { 33 /* 34 * Remove backslashes from the strings. Turn \040 etc. into a single 35 * character (we allow eight bit values). Currently NUL is not 36 * allowed. Also escape as needed. 37 * 38 * Turn "\n" and "\t" into '\n' and '\t' characters. Etc. 39 * 40 */ 41 char *new_str; 42 int seenbs = 0; 43 int i = 0; 44 int j = 0; 45 46 for (i = 0; str[i]; ++i) { 47 if (str[i] == '\'' || 48 str[i] == '"' || 49 str[i] == '$') { 50 ++j; 51 } 52 } 53 j += i + 2; /* terminator + possible final backslash */ 54 55 new_str = malloc(j); 56 57 i = 0; 58 while (*str) { 59 if (seenbs) { 60 seenbs = 0; 61 switch (*str) { 62 case '\\': 63 new_str[i++] = '\\'; 64 str++; 65 break; 66 67 /* preserve backslashed quotes, dollar signs */ 68 case '\'': 69 case '"': 70 case '$': 71 new_str[i++] = '\\'; 72 new_str[i++] = *str++; 73 break; 74 75 case 'b': 76 new_str[i++] = '\b'; 77 str++; 78 break; 79 80 case 'f': 81 new_str[i++] = '\f'; 82 str++; 83 break; 84 85 case 'r': 86 new_str[i++] = '\r'; 87 str++; 88 break; 89 90 case 'n': 91 new_str[i++] = '\n'; 92 str++; 93 break; 94 95 case 's': 96 new_str[i++] = ' '; 97 str++; 98 break; 99 100 case 't': 101 new_str[i++] = '\t'; 102 str++; 103 break; 104 105 case 'v': 106 new_str[i++] = '\13'; 107 str++; 108 break; 109 110 case 'z': 111 str++; 112 break; 113 114 case '0': case '1': case '2': case '3': case '4': 115 case '5': case '6': case '7': case '8': case '9': { 116 char val; 117 118 /* Three digit octal constant? */ 119 if (*str >= '0' && *str <= '3' && 120 *(str + 1) >= '0' && *(str + 1) <= '7' && 121 *(str + 2) >= '0' && *(str + 2) <= '7') { 122 123 val = (DIGIT(*str) << 6) + (DIGIT(*(str + 1)) << 3) + 124 DIGIT(*(str + 2)); 125 126 /* Allow null value if user really wants to shoot 127 at feet, but beware! */ 128 new_str[i++] = val; 129 str += 3; 130 break; 131 } 132 133 /* One or two digit hex constant? 134 * If two are there they will both be taken. 135 * Use \z to split them up if this is not wanted. 136 */ 137 if (*str == '0' && 138 (*(str + 1) == 'x' || *(str + 1) == 'X') && 139 isxdigit(*(str + 2))) { 140 val = DIGIT(*(str + 2)); 141 if (isxdigit(*(str + 3))) { 142 val = (val << 4) + DIGIT(*(str + 3)); 143 str += 4; 144 } 145 else 146 str += 3; 147 /* Yep, allow null value here too */ 148 new_str[i++] = val; 149 break; 150 } 151 } 152 break; 153 154 default: 155 new_str[i++] = *str++; 156 break; 157 } 158 } 159 else { 160 if (*str == '\\') { 161 seenbs = 1; 162 str++; 163 } else { 164 new_str[i++] = *str++; 165 } 166 } 167 } 168 169 if (seenbs) { 170 /* 171 * The final character was a '\'. Put it in as a single backslash. 172 */ 173 new_str[i++] = '\\'; 174 } 175 new_str[i] = 0; 176 if (i >= j) 177 panic("bls"); 178 179 return new_str; 180 } 181