9192e62d99af029028cd163c0201dbd07d59d128
[platform/upstream/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 <chartypes.h>
32
33 #include "shell.h"
34
35 #ifdef ESC
36 #undef ESC
37 #endif
38 #define ESC '\033'      /* ASCII */
39
40 /* Convert STRING by expanding the escape sequences specified by the
41    ANSI C standard.  If SAWC is non-null, recognize `\c' and use that
42    as a string terminator.  If we see \c, set *SAWC to 1 before
43    returning.  LEN is the length of STRING.  FOR_ECHO is a flag that
44    means, if non-zero, that we're translating a string for `echo -e',
45    and therefore should not treat a single quote as a character that
46    may be escaped with a backslash. */
47 char *
48 ansicstr (string, len, for_echo, sawc, rlen)
49      char *string;
50      int len, for_echo, *sawc, *rlen;
51 {
52   int c, temp;
53   char *ret, *r, *s;
54
55   if (string == 0 || *string == '\0')
56     return ((char *)NULL);
57
58   ret = (char *)xmalloc (len + 1);
59   for (r = ret, s = string; s && *s; )
60     {
61       c = *s++;
62       if (c != '\\' || *s == '\0')
63         *r++ = c;
64       else
65         {
66           switch (c = *s++)
67             {
68 #if defined (__STDC__)
69             case 'a': c = '\a'; break;
70             case 'v': c = '\v'; break;
71 #else
72             case 'a': c = '\007'; break;
73             case 'v': c = (int) 0x0B; break;
74 #endif
75             case 'b': c = '\b'; break;
76             case 'e': case 'E':         /* ESC -- non-ANSI */
77               c = ESC; break;
78             case 'f': c = '\f'; break;
79             case 'n': c = '\n'; break;
80             case 'r': c = '\r'; break;
81             case 't': c = '\t'; break;
82             case '0': case '1': case '2': case '3':
83             case '4': case '5': case '6': case '7':
84               for (temp = 2, c -= '0'; ISOCTAL (*s) && temp--; s++)
85                 c = (c * 8) + OCTVALUE (*s);
86               c &= 0xFF;
87               break;
88             case 'x':                   /* Hex digit -- non-ANSI */
89               for (temp = 2, c = 0; ISXDIGIT ((unsigned char)*s) && temp--; s++)
90                 c = (c * 16) + HEXVALUE (*s);
91               /* \x followed by non-hex digits is passed through unchanged */
92               if (temp == 2)
93                 {
94                   *r++ = '\\';
95                   c = 'x';
96                 }
97               c &= 0xFF;
98               break;
99             case '\\':
100               break;
101             case '\'':
102               if (for_echo)
103                 *r++ = '\\';
104               break;
105             case 'c':
106               if (sawc)
107                 {
108                   *sawc = 1;
109                   *r = '\0';
110                   if (rlen)
111                     *rlen = r - ret;
112                   return ret;
113                 }
114             default:  *r++ = '\\'; break;
115             }
116           *r++ = c;
117         }
118     }
119   *r = '\0';
120   if (rlen)
121     *rlen = r - ret;
122   return ret;
123 }
124
125 /* Take a string STR, possibly containing non-printing characters, and turn it
126    into a $'...' ANSI-C style quoted string.  Returns a new string. */
127 char *
128 ansic_quote (str, flags, rlen)
129      char *str;
130      int flags, *rlen;
131 {
132   char *r, *ret, *s, obuf[8];
133   int l, rsize, t;
134   unsigned char c;
135
136   if (str == 0 || *str == 0)
137     return ((char *)0);
138
139   l = strlen (str);
140   rsize = 2 * l + 4;
141   r = ret = (char *)xmalloc (rsize);
142
143   *r++ = '$';
144   *r++ = '\'';
145
146   for (s = str, l = 0; *s; s++)
147     {
148       c = *s;
149       l = 1;            /* 1 == add backslash; 0 == no backslash */
150       switch (c)
151         {
152         case ESC: c = 'E'; break;
153 #ifdef __STDC__
154         case '\a': c = 'a'; break;
155         case '\v': c = 'v'; break;
156 #else
157         case '\007': c = 'a'; break;
158         case 0x0b: c = 'v'; break;
159 #endif
160
161         case '\b': c = 'b'; break;
162         case '\f': c = 'f'; break;
163         case '\n': c = 'n'; break;
164         case '\r': c = 'r'; break;
165         case '\t': c = 't'; break;
166         case '\\':
167         case '\'':
168           break;
169         default:
170           if (ISPRINT (c) == 0)
171             {
172               sprintf (obuf, "\\%.3o", c);
173               t = r - ret;
174               RESIZE_MALLOCED_BUFFER (ret, t, 5, rsize, 16);
175               r = ret + t;      /* in case reallocated */
176               for (t = 0; t < 4; t++)
177                 *r++ = obuf[t];
178               continue;
179             }
180           l = 0;
181           break;
182         }
183       if (l)
184         *r++ = '\\';
185       *r++ = c;
186     }
187
188   *r++ = '\'';
189   *r = '\0';
190   if (rlen)
191     *rlen = r - ret;
192   return ret;
193 }
194
195 /* return 1 if we need to quote with $'...' because of non-printing chars. */
196 ansic_shouldquote (string)
197      const char *string;
198 {
199   const char *s;
200   unsigned char c;
201
202   if (string == 0)
203     return 0;
204
205   for (s = string; c = *s; s++)
206     if (ISPRINT (c) == 0)
207       return 1;
208
209   return 0;
210 }