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