1 /* Expand escape sequences in a string.
2 Copyright (C) 1995-1997, 2000-2007, 2012, 2018-2019 Free Software
3 Foundation, Inc.
4 Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, May 1995.
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18
19 /* Expand some escape sequences found in the argument string.
20 If backslash_c_seen is != NULL, '\c' sequences are recognized and
21 have the effect of setting *backslash_c_seen to true.
22 Returns either the argument string or a freshly allocated string. */
23 static const char *
expand_escapes(const char * str,bool * backslash_c_seen)24 expand_escapes (const char *str, bool *backslash_c_seen)
25 {
26 const char *cp = str;
27
28 /* Find the location of the first escape sequence.
29 If the string contains no escape sequences, return it right away. */
30 for (;;)
31 {
32 while (cp[0] != '\0' && cp[0] != '\\')
33 ++cp;
34 if (cp[0] == '\0')
35 /* The argument string contains no escape sequence. */
36 return str;
37 /* Found a backslash. */
38 if (cp[1] == '\0')
39 return str;
40 if (strchr ("abcfnrtv\\01234567", cp[1]) != NULL)
41 break;
42 ++cp;
43 }
44
45 {
46 char *retval = XNMALLOC (strlen (str), char);
47
48 memcpy (retval, str, cp - str);
49 {
50 char *rp = retval + (cp - str);
51
52 do
53 {
54 /* Here cp[0] == '\\'. */
55 switch (*++cp)
56 {
57 case 'a': /* alert */
58 *rp++ = '\a';
59 ++cp;
60 break;
61 case 'b': /* backspace */
62 *rp++ = '\b';
63 ++cp;
64 break;
65 case 'f': /* form feed */
66 *rp++ = '\f';
67 ++cp;
68 break;
69 case 'n': /* new line */
70 *rp++ = '\n';
71 ++cp;
72 break;
73 case 'r': /* carriage return */
74 *rp++ = '\r';
75 ++cp;
76 break;
77 case 't': /* horizontal tab */
78 *rp++ = '\t';
79 ++cp;
80 break;
81 case 'v': /* vertical tab */
82 *rp++ = '\v';
83 ++cp;
84 break;
85 case '\\':
86 *rp++ = '\\';
87 ++cp;
88 break;
89 case '0': case '1': case '2': case '3':
90 case '4': case '5': case '6': case '7':
91 {
92 int ch = *cp++ - '0';
93
94 if (*cp >= '0' && *cp <= '7')
95 {
96 ch *= 8;
97 ch += *cp++ - '0';
98
99 if (*cp >= '0' && *cp <= '7')
100 {
101 ch *= 8;
102 ch += *cp++ - '0';
103 }
104 }
105 *rp++ = ch;
106 }
107 break;
108 case 'c':
109 if (backslash_c_seen != NULL)
110 {
111 *backslash_c_seen = true;
112 ++cp;
113 break;
114 }
115 /* FALLTHROUGH */
116 default:
117 *rp++ = '\\';
118 break;
119 }
120
121 /* Find the next escape sequence. */
122 while (cp[0] != '\0' && cp[0] != '\\')
123 *rp++ = *cp++;
124 }
125 while (cp[0] != '\0');
126
127 /* Terminate the resulting string. */
128 *rp = '\0';
129 }
130
131 return retval;
132 }
133 }
134