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