mhl: mhl_shell_unescape_buf(): fixed memory array OOB.
[midnight-commander.git] / mhl / escape.h
blob2ec4e0d46b21ca55c7db0c820126403c625288bb
1 #ifndef __MHL_SHELL_ESCAPE_H
2 #define __MHL_SHELL_ESCAPE_H
4 /* Micro helper library: shell escaping functions */
6 #include <string.h>
7 #include <stdlib.h>
9 #include <mhl/types.h>
11 #define mhl_shell_escape_toesc(x) \
12 (((x)==' ')||((x)=='!')||((x)=='#')||((x)=='$')||((x)=='%')|| \
13 ((x)=='(')||((x)==')')||((x)=='\'')||((x)=='&')||((x)=='~')|| \
14 ((x)=='{')||((x)=='}')||((x)=='[')||((x)==']')||((x)=='`')|| \
15 ((x)=='?')||((x)=='|')||((x)=='<')||((x)=='>')||((x)==';')|| \
16 ((x)=='*')||((x)=='\\')||((x)=='"'))
18 #define mhl_shell_escape_nottoesc(x) \
19 (((x)!=0) && (!mhl_shell_escape_toesc((x))))
21 /* type for escaped string - just for a bit more type safety ;-p */
22 typedef struct { char* s; } SHELL_ESCAPED_STR;
24 /** To be compatible with the general posix command lines we have to escape
25 strings for the command line
27 /params const char * in
28 string for escaping
29 /returns
30 return escaped string (later need to free)
32 static inline SHELL_ESCAPED_STR mhl_shell_escape_dup(const char* src)
34 if ((src==NULL)||(!(*src)))
35 return (SHELL_ESCAPED_STR){ .s = strdup("") };
37 char* buffer = calloc(1, strlen(src)*2+2);
38 char* ptr = buffer;
40 /* look for the first char to escape */
41 while (1)
43 char c;
44 /* copy over all chars not to escape */
45 while ((c=(*src)) && mhl_shell_escape_nottoesc(c))
47 *ptr = c;
48 ptr++;
49 src++;
52 /* at this point we either have an \0 or an char to escape */
53 if (!c)
54 return (SHELL_ESCAPED_STR){ .s = buffer };
56 *ptr = '\\';
57 ptr++;
58 *ptr = c;
59 ptr++;
60 src++;
64 /** Unescape paths or other strings for e.g the internal cd
65 shell-unescape within a given buffer (writing to it!)
67 /params const char * in
68 string for unescaping
69 /returns
70 return unescaped string
72 static inline char* mhl_shell_unescape_buf(char* text)
74 if (!text)
75 return NULL;
77 /* look for the first \ - that's quick skipover if there's nothing to escape */
78 char* readptr = text;
79 while ((*readptr) && ((*readptr)!='\\')) readptr++;
80 if (!(*readptr)) return text;
82 /* if we're here, we're standing on the first '\' */
83 char* writeptr = readptr;
84 char c;
85 while ((c = *readptr))
87 if (c=='\\')
89 readptr++;
90 switch ((c = *readptr))
92 case 'n': (*writeptr) = '\n'; writeptr++; break;
93 case 'r': (*writeptr) = '\r'; writeptr++; break;
94 case 't': (*writeptr) = '\t'; writeptr++; break;
96 case ' ':
97 case '\\':
98 case '#':
99 case '$':
100 case '%':
101 case '(':
102 case ')':
103 case '[':
104 case ']':
105 case '{':
106 case '}':
107 case '<':
108 case '>':
109 case '!':
110 case '*':
111 case '?':
112 case '~':
113 case '`':
114 case '"':
115 case ';':
116 case '\0': /* end of line! malformed escape string */
117 goto out;
118 default:
119 (*writeptr) = c; writeptr++; break;
122 else /* got a normal character */
124 (*writeptr) = *readptr;
125 writeptr++;
127 readptr++;
129 out:
130 *writeptr = 0;
132 return text;
135 /** Check if char in pointer contain escape'd chars
137 /params const char * in
138 string for checking
139 /returns
140 return TRUE if string contain escaped chars
141 otherwise return FALSE
143 static inline bool
144 mhl_shell_is_char_escaped ( const char *in )
146 if (in == NULL || !*in || in[0] != '\\')
147 return false;
148 if (mhl_shell_escape_toesc(in[1]))
149 return true;
150 return false;
153 #endif