]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/common/interp_backslash.c
ofw_bus_is_compatible(9): Fix a few mandoc related issues
[FreeBSD/FreeBSD.git] / stand / common / interp_backslash.c
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
17 #include <sys/cdefs.h>
18 __FBSDID("$FreeBSD$");
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(const 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.
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
45         if ((new_str = strdup(str)) == NULL)
46                 return NULL;
47
48         while (*str) {
49                 if (seenbs) {
50                         seenbs = 0;
51                         switch (*str) {
52                         case '\\':
53                                 new_str[i++] = '\\';
54                                 str++;
55                                 break;
56
57                                 /* preserve backslashed quotes, dollar signs */
58                         case '\'':
59                         case '"':
60                         case '$':
61                                 new_str[i++] = '\\';
62                                 new_str[i++] = *str++;
63                                 break;
64
65                         case 'b':
66                                 new_str[i++] = '\b';
67                                 str++;
68                                 break;
69
70                         case 'f':
71                                 new_str[i++] = '\f';
72                                 str++;
73                                 break;
74
75                         case 'r':
76                                 new_str[i++] = '\r';
77                                 str++;
78                                 break;
79
80                         case 'n':
81                                 new_str[i++] = '\n';
82                                 str++;
83                                 break;
84
85                         case 's':
86                                 new_str[i++] = ' ';
87                                 str++;
88                                 break;
89
90                         case 't':
91                                 new_str[i++] = '\t';
92                                 str++;
93                                 break;
94
95                         case 'v':
96                                 new_str[i++] = '\13';
97                                 str++;
98                                 break;
99
100                         case 'z':
101                                 str++;
102                                 break;
103
104                         case '0': case '1': case '2': case '3': case '4':
105                         case '5': case '6': case '7': case '8': case '9': {
106                                 char val;
107
108                                 /* Three digit octal constant? */
109                                 if (*str >= '0' && *str <= '3' && 
110                                     *(str + 1) >= '0' && *(str + 1) <= '7' &&
111                                     *(str + 2) >= '0' && *(str + 2) <= '7') {
112
113                                         val = (DIGIT(*str) << 6) + (DIGIT(*(str + 1)) << 3) + 
114                                             DIGIT(*(str + 2));
115
116                                         /* Allow null value if user really wants to shoot
117                                            at feet, but beware! */
118                                         new_str[i++] = val;
119                                         str += 3;
120                                         break;
121                                 }
122
123                                 /* One or two digit hex constant?
124                                  * If two are there they will both be taken.
125                                  * Use \z to split them up if this is not wanted.
126                                  */
127                                 if (*str == '0' &&
128                                     (*(str + 1) == 'x' || *(str + 1) == 'X') &&
129                                     isxdigit(*(str + 2))) {
130                                         val = DIGIT(*(str + 2));
131                                         if (isxdigit(*(str + 3))) {
132                                                 val = (val << 4) + DIGIT(*(str + 3));
133                                                 str += 4;
134                                         }
135                                         else
136                                                 str += 3;
137                                         /* Yep, allow null value here too */
138                                         new_str[i++] = val;
139                                         break;
140                                 }
141                         }
142                                 break;
143
144                         default:
145                                 new_str[i++] = *str++;
146                                 break;
147                         }
148                 }
149                 else {
150                         if (*str == '\\') {
151                                 seenbs = 1;
152                                 str++;
153                         }
154                         else
155                                 new_str[i++] = *str++;
156                 }
157         }
158
159         if (seenbs) {
160                 /*
161                  * The final character was a '\'. Put it in as a single backslash.
162                  */
163                 new_str[i++] = '\\';
164         }
165         new_str[i] = '\0';
166         return new_str;
167 }