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