]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/sh/strtrans.c
Imported from ../bash-2.05.tar.gz.
[thirdparty/bash.git] / lib / sh / strtrans.c
1 /* strtrans.c - Translate and untranslate strings with ANSI-C escape
2 sequences. */
3
4 /* Copyright (C) 2000
5 Free Software Foundation, Inc.
6
7 This file is part of GNU Bash, the Bourne Again SHell.
8
9 Bash is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 2, or (at your option) any later
12 version.
13
14 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 for more details.
18
19 You should have received a copy of the GNU General Public License along
20 with Bash; see the file COPYING. If not, write to the Free Software
21 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
22
23 #include <config.h>
24
25 #if defined (HAVE_UNISTD_H)
26 # include <unistd.h>
27 #endif
28
29 #include "bashansi.h"
30 #include <stdio.h>
31 #include <ctype.h>
32
33 #include "shell.h"
34
35 #ifdef ESC
36 #undef ESC
37 #endif
38 #define ESC '\033' /* ASCII */
39
40 #ifndef ISOCTAL
41 #define ISOCTAL(c) ((c) >= '0' && (c) <= '7')
42 #endif
43
44 #ifndef OCTVALUE
45 #define OCTVALUE(c) ((c) - '0')
46 #endif
47
48 #ifndef isxdigit
49 # define isxdigit(c) (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
50 #endif
51
52 #define HEXVALUE(c) \
53 ((c) >= 'a' && (c) <= 'f' ? (c)-'a'+10 : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0')
54
55 /* Convert STRING by expanding the escape sequences specified by the
56 ANSI C standard. If SAWC is non-null, recognize `\c' and use that
57 as a string terminator. If we see \c, set *SAWC to 1 before
58 returning. LEN is the length of STRING. FOR_ECHO is a flag that
59 means, if non-zero, that we're translating a string for `echo -e',
60 and therefore should not treat a single quote as a character that
61 may be escaped with a backslash. */
62 char *
63 ansicstr (string, len, for_echo, sawc, rlen)
64 char *string;
65 int len, for_echo, *sawc, *rlen;
66 {
67 int c, temp;
68 char *ret, *r, *s;
69
70 if (string == 0 || *string == '\0')
71 return ((char *)NULL);
72
73 ret = xmalloc (len + 1);
74 for (r = ret, s = string; s && *s; )
75 {
76 c = *s++;
77 if (c != '\\' || *s == '\0')
78 *r++ = c;
79 else
80 {
81 switch (c = *s++)
82 {
83 #if defined (__STDC__)
84 case 'a': c = '\a'; break;
85 case 'v': c = '\v'; break;
86 #else
87 case 'a': c = '\007'; break;
88 case 'v': c = (int) 0x0B; break;
89 #endif
90 case 'b': c = '\b'; break;
91 case 'e': case 'E': /* ESC -- non-ANSI */
92 c = ESC; break;
93 case 'f': c = '\f'; break;
94 case 'n': c = '\n'; break;
95 case 'r': c = '\r'; break;
96 case 't': c = '\t'; break;
97 case '0': case '1': case '2': case '3':
98 case '4': case '5': case '6': case '7':
99 for (temp = 2, c -= '0'; ISOCTAL (*s) && temp--; s++)
100 c = (c * 8) + OCTVALUE (*s);
101 break;
102 case 'x': /* Hex digit -- non-ANSI */
103 for (temp = 3, c = 0; isxdigit (*s) && temp--; s++)
104 c = (c * 16) + HEXVALUE (*s);
105 /* \x followed by non-hex digits is passed through unchanged */
106 if (temp == 3)
107 {
108 *r++ = '\\';
109 c = 'x';
110 }
111 break;
112 case '\\':
113 break;
114 case '\'':
115 if (for_echo)
116 *r++ = '\\';
117 break;
118 case 'c':
119 if (sawc)
120 {
121 *sawc = 1;
122 *r = '\0';
123 if (rlen)
124 *rlen = r - ret;
125 return ret;
126 }
127 default: *r++ = '\\'; break;
128 }
129 *r++ = c;
130 }
131 }
132 *r = '\0';
133 if (rlen)
134 *rlen = r - ret;
135 return ret;
136 }
137
138 /* Take a string STR, possibly containing non-printing characters, and turn it
139 into a $'...' ANSI-C style quoted string. Returns a new string. */
140 char *
141 ansic_quote (str, flags, rlen)
142 char *str;
143 int flags, *rlen;
144 {
145 char *r, *ret, *s, obuf[8];
146 int l, c, rsize, t;
147
148 if (str == 0 || *str == 0)
149 return ((char *)0);
150
151 l = strlen (str);
152 rsize = 2 * l + 4;
153 r = ret = xmalloc (rsize);
154
155 *r++ = '$';
156 *r++ = '\'';
157
158 for (s = str, l = 0; *s; s++)
159 {
160 c = *(unsigned char *)s;
161 l = 1; /* 1 == add backslash; 0 == no backslash */
162 switch (c)
163 {
164 case ESC: c = 'E'; break;
165 #ifdef __STDC__
166 case '\a': c = 'a'; break;
167 case '\v': c = 'v'; break;
168 #else
169 case '\007': c = 'a'; break;
170 case 0x0b: c = 'v'; break;
171 #endif
172
173 case '\b': c = 'b'; break;
174 case '\f': c = 'f'; break;
175 case '\n': c = 'n'; break;
176 case '\r': c = 'r'; break;
177 case '\t': c = 't'; break;
178 case '\\':
179 case '\'':
180 break;
181 default:
182 if (isprint (c) == 0)
183 {
184 sprintf (obuf, "\\%.3o", c);
185 t = r - ret;
186 RESIZE_MALLOCED_BUFFER (ret, t, 5, rsize, 16);
187 r = ret + t; /* in case reallocated */
188 for (t = 0; t < 4; t++)
189 *r++ = obuf[t];
190 continue;
191 }
192 l = 0;
193 break;
194 }
195 if (l)
196 *r++ = '\\';
197 *r++ = c;
198 }
199
200 *r++ = '\'';
201 *r = '\0';
202 if (rlen)
203 *rlen = r - ret;
204 return ret;
205 }