Merge branch '161_drop_bundled_slang'
[midnight-commander.git] / mhl / escape.h
blob485579c594ea80f7bdaa489b5051418a5ebd381b
1 #ifndef MHL_ESCAPE_H
2 #define MHL_ESCAPE_H
4 /* Micro helper library: shell escaping functions */
6 #include <string.h>
7 #include <stdlib.h>
8 #include <stdbool.h>
10 #define mhl_shell_escape_toesc(x) \
11 (((x)==' ')||((x)=='!')||((x)=='#')||((x)=='$')||((x)=='%')|| \
12 ((x)=='(')||((x)==')')||((x)=='\'')||((x)=='&')||((x)=='~')|| \
13 ((x)=='{')||((x)=='}')||((x)=='[')||((x)==']')||((x)=='`')|| \
14 ((x)=='?')||((x)=='|')||((x)=='<')||((x)=='>')||((x)==';')|| \
15 ((x)=='*')||((x)=='\\')||((x)=='"'))
17 #define mhl_shell_escape_nottoesc(x) \
18 (((x)!=0) && (!mhl_shell_escape_toesc((x))))
20 /* type for escaped string - just for a bit more type safety ;-p */
21 typedef struct { char* s; } SHELL_ESCAPED_STR;
23 /** To be compatible with the general posix command lines we have to escape
24 strings for the command line
26 /params const char * in
27 string for escaping
28 /returns
29 return escaped string (later need to free)
31 static inline SHELL_ESCAPED_STR mhl_shell_escape_dup(const char* src)
33 if ((src==NULL)||(!(*src)))
34 return (SHELL_ESCAPED_STR){ .s = strdup("") };
36 char* buffer = calloc(1, strlen(src)*2+2);
37 char* ptr = buffer;
39 /* look for the first char to escape */
40 while (1)
42 char c;
43 /* copy over all chars not to escape */
44 while ((c=(*src)) && mhl_shell_escape_nottoesc(c))
46 *ptr = c;
47 ptr++;
48 src++;
51 /* at this point we either have an \0 or an char to escape */
52 if (!c)
53 return (SHELL_ESCAPED_STR){ .s = buffer };
55 *ptr = '\\';
56 ptr++;
57 *ptr = c;
58 ptr++;
59 src++;
63 /** Unescape paths or other strings for e.g the internal cd
64 shell-unescape within a given buffer (writing to it!)
66 /params const char * src
67 string for unescaping
68 /returns
69 return unescaped string
71 static inline char* mhl_shell_unescape_buf(char* text)
73 if (!text)
74 return NULL;
76 /* look for the first \ - that's quick skipover if there's nothing to escape */
77 char* readptr = text;
78 while ((*readptr) && ((*readptr)!='\\')) readptr++;
79 if (!(*readptr)) return text;
81 /* if we're here, we're standing on the first '\' */
82 char* writeptr = readptr;
83 char c;
84 while ((c = *readptr))
86 if (c=='\\')
88 readptr++;
89 switch ((c = *readptr))
91 case 'n': (*writeptr) = '\n'; writeptr++; break;
92 case 'r': (*writeptr) = '\r'; writeptr++; break;
93 case 't': (*writeptr) = '\t'; writeptr++; break;
95 case ' ':
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 '\0': /* end of string! malformed escape string */
116 goto out;
117 default:
118 (*writeptr) = c; writeptr++; break;
121 else /* got a normal character */
123 (*writeptr) = *readptr;
124 writeptr++;
126 readptr++;
128 out:
129 *writeptr = 0;
131 return text;
134 /** Check if char in pointer contain escape'd chars
136 /params const char * in
137 string for checking
138 /returns
139 return TRUE if string contain escaped chars
140 otherwise return FALSE
142 static inline bool
143 mhl_shell_is_char_escaped ( const char *in )
145 if (in == NULL || !*in || in[0] != '\\')
146 return false;
147 if (mhl_shell_escape_toesc(in[1]))
148 return true;
149 return false;
152 #endif