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