-rw-r--r-- | microkde/kdecore/kshell.cpp | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/microkde/kdecore/kshell.cpp b/microkde/kdecore/kshell.cpp new file mode 100644 index 0000000..efc007a --- a/dev/null +++ b/microkde/kdecore/kshell.cpp | |||
@@ -0,0 +1,386 @@ | |||
1 | /* | ||
2 | This file is part of the KDE libraries | ||
3 | |||
4 | Copyright (c) 2003 Oswald Buddenhagen <ossi@kde.org> | ||
5 | |||
6 | This library is free software; you can redistribute it and/or | ||
7 | modify it under the terms of the GNU Library General Public | ||
8 | License as published by the Free Software Foundation; either | ||
9 | version 2 of the License, or (at your option) any later version. | ||
10 | |||
11 | This library 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 GNU | ||
14 | Library General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU Library General Public License | ||
17 | along with this library; see the file COPYING.LIB. If not, write to | ||
18 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
19 | Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <kshell.h> | ||
23 | |||
24 | #include <qfile.h> | ||
25 | #include <qdir.h> | ||
26 | |||
27 | #include <stdlib.h> | ||
28 | #ifndef _WIN32_ | ||
29 | #include <pwd.h> | ||
30 | #endif | ||
31 | //US #include <sys/types.h> | ||
32 | |||
33 | /*US | ||
34 | static int fromHex( QChar c ) | ||
35 | { | ||
36 | if (c >= '0' && c <= '9') | ||
37 | return c - '0'; | ||
38 | else if (c >= 'A' && c <= 'F') | ||
39 | return c - 'A' + 10; | ||
40 | else if (c >= 'a' && c <= 'f') | ||
41 | return c - 'a' + 10; | ||
42 | return -1; | ||
43 | } | ||
44 | |||
45 | inline static bool isQuoteMeta( uint c ) | ||
46 | { | ||
47 | #if 0 // it's not worth it, especially after seeing gcc's asm output ... | ||
48 | static const uchar iqm[] = { | ||
49 | 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, | ||
50 | 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00 | ||
51 | }; // \'"$ | ||
52 | |||
53 | return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))); | ||
54 | #else | ||
55 | return c == '\\' || c == '\'' || c == '"' || c == '$'; | ||
56 | #endif | ||
57 | } | ||
58 | |||
59 | inline static bool isMeta( uint c ) | ||
60 | { | ||
61 | static const uchar iqm[] = { | ||
62 | 0x00, 0x00, 0x00, 0x00, 0xdc, 0x07, 0x00, 0xd8, | ||
63 | 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x38 | ||
64 | }; // \'"$`<>|;&(){}*?# | ||
65 | |||
66 | return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))); | ||
67 | } | ||
68 | |||
69 | QStringList KShell::splitArgs( const QString &args, int flags, int *err ) | ||
70 | { | ||
71 | QStringList ret; | ||
72 | bool firstword = flags & AbortOnMeta; | ||
73 | |||
74 | for (uint pos = 0; ; ) { | ||
75 | QChar c; | ||
76 | do { | ||
77 | if (pos >= args.length()) | ||
78 | goto okret; | ||
79 | c = args.unicode()[pos++]; | ||
80 | } while (c.isSpace()); | ||
81 | QString cret; | ||
82 | if ((flags & TildeExpand) && c == '~') { | ||
83 | uint opos = pos; | ||
84 | for (; ; pos++) { | ||
85 | if (pos >= args.length()) | ||
86 | break; | ||
87 | c = args.unicode()[pos]; | ||
88 | if (c == '/' || c.isSpace()) | ||
89 | break; | ||
90 | if (isQuoteMeta( c )) { | ||
91 | pos = opos; | ||
92 | c = '~'; | ||
93 | goto notilde; | ||
94 | } | ||
95 | if ((flags & AbortOnMeta) && isMeta( c )) | ||
96 | goto metaerr; | ||
97 | } | ||
98 | QString ccret = homeDir( QConstString( args.unicode() + opos, pos - opos ).string() ); | ||
99 | if (ccret.isEmpty()) { | ||
100 | pos = opos; | ||
101 | c = '~'; | ||
102 | goto notilde; | ||
103 | } | ||
104 | if (pos >= args.length()) { | ||
105 | ret += ccret; | ||
106 | goto okret; | ||
107 | } | ||
108 | pos++; | ||
109 | if (c.isSpace()) { | ||
110 | ret += ccret; | ||
111 | firstword = false; | ||
112 | continue; | ||
113 | } | ||
114 | cret = ccret; | ||
115 | } | ||
116 | // before the notilde label, as a tilde does not match anyway | ||
117 | if (firstword) { | ||
118 | if (c == '_' || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { | ||
119 | uint pos2 = pos; | ||
120 | QChar cc; | ||
121 | do | ||
122 | cc = args[pos2++]; | ||
123 | while (cc == '_' || (cc >= 'A' && cc <= 'Z') || | ||
124 | (cc >= 'a' && cc <= 'z') || (cc >= '0' && cc <= '9')); | ||
125 | if (cc == '=') | ||
126 | goto metaerr; | ||
127 | } | ||
128 | } | ||
129 | notilde: | ||
130 | do { | ||
131 | if (c == '\'') { | ||
132 | uint spos = pos; | ||
133 | do { | ||
134 | if (pos >= args.length()) | ||
135 | goto quoteerr; | ||
136 | c = args.unicode()[pos++]; | ||
137 | } while (c != '\''); | ||
138 | cret += QConstString( args.unicode() + spos, pos - spos - 1 ).string(); | ||
139 | } else if (c == '"') { | ||
140 | for (;;) { | ||
141 | if (pos >= args.length()) | ||
142 | goto quoteerr; | ||
143 | c = args.unicode()[pos++]; | ||
144 | if (c == '"') | ||
145 | break; | ||
146 | if (c == '\\') { | ||
147 | if (pos >= args.length()) | ||
148 | goto quoteerr; | ||
149 | c = args.unicode()[pos++]; | ||
150 | if (c != '"' && c != '\\' && | ||
151 | !((flags & AbortOnMeta) && (c == '$' || c == '`'))) | ||
152 | cret += '\\'; | ||
153 | } else if ((flags & AbortOnMeta) && (c == '$' || c == '`')) | ||
154 | goto metaerr; | ||
155 | cret += c; | ||
156 | } | ||
157 | } else if (c == '$' && args[pos] == '\'') { | ||
158 | pos++; | ||
159 | for (;;) { | ||
160 | if (pos >= args.length()) | ||
161 | goto quoteerr; | ||
162 | c = args.unicode()[pos++]; | ||
163 | if (c == '\'') | ||
164 | break; | ||
165 | if (c == '\\') { | ||
166 | if (pos >= args.length()) | ||
167 | goto quoteerr; | ||
168 | c = args.unicode()[pos++]; | ||
169 | switch (c) { | ||
170 | case 'a': cret += '\a'; break; | ||
171 | case 'b': cret += '\b'; break; | ||
172 | case 'e': cret += '\033'; break; | ||
173 | case 'f': cret += '\f'; break; | ||
174 | case 'n': cret += '\n'; break; | ||
175 | case 'r': cret += '\r'; break; | ||
176 | case 't': cret += '\t'; break; | ||
177 | case '\\': cret += '\\'; break; | ||
178 | case '\'': cret += '\''; break; | ||
179 | case 'c': cret += args[pos++] & 31; break; | ||
180 | case 'x': | ||
181 | { | ||
182 | int hv = fromHex( args[pos] ); | ||
183 | if (hv < 0) { | ||
184 | cret += "\\x"; | ||
185 | } else { | ||
186 | int hhv = fromHex( args[++pos] ); | ||
187 | if (hhv > 0) { | ||
188 | hv = hv * 16 + hhv; | ||
189 | pos++; | ||
190 | } | ||
191 | cret += QChar( hv ); | ||
192 | } | ||
193 | break; | ||
194 | } | ||
195 | default: | ||
196 | if (c >= '0' && c <= '7') { | ||
197 | int hv = c - '0'; | ||
198 | for (int i = 0; i < 2; i++) { | ||
199 | c = args[pos]; | ||
200 | if (c < '0' || c > '7') | ||
201 | break; | ||
202 | hv = hv * 8 + (c - '0'); | ||
203 | pos++; | ||
204 | } | ||
205 | cret += QChar( hv ); | ||
206 | } else { | ||
207 | cret += '\\'; | ||
208 | cret += c; | ||
209 | } | ||
210 | break; | ||
211 | } | ||
212 | } else | ||
213 | cret += c; | ||
214 | } | ||
215 | } else { | ||
216 | if (c == '\\') { | ||
217 | if (pos >= args.length()) | ||
218 | goto quoteerr; | ||
219 | c = args.unicode()[pos++]; | ||
220 | if (!c.isSpace() && | ||
221 | !((flags & AbortOnMeta) ? isMeta( c ) : isQuoteMeta( c ))) | ||
222 | cret += '\\'; | ||
223 | } else if ((flags & AbortOnMeta) && isMeta( c )) | ||
224 | goto metaerr; | ||
225 | cret += c; | ||
226 | } | ||
227 | if (pos >= args.length()) | ||
228 | break; | ||
229 | c = args.unicode()[pos++]; | ||
230 | } while (!c.isSpace()); | ||
231 | ret += cret; | ||
232 | firstword = false; | ||
233 | } | ||
234 | |||
235 | okret: | ||
236 | if (err) | ||
237 | *err = NoError; | ||
238 | return ret; | ||
239 | |||
240 | quoteerr: | ||
241 | if (err) | ||
242 | *err = BadQuoting; | ||
243 | return QStringList(); | ||
244 | |||
245 | metaerr: | ||
246 | if (err) | ||
247 | *err = FoundMeta; | ||
248 | return QStringList(); | ||
249 | } | ||
250 | |||
251 | inline static bool isSpecial( uint c ) | ||
252 | { | ||
253 | static const uchar iqm[] = { | ||
254 | 0xff, 0xff, 0xff, 0xff, 0xdd, 0x07, 0x00, 0xd8, | ||
255 | 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x38 | ||
256 | }; // 0-32 \'"$`<>|;&(){}*?# | ||
257 | |||
258 | return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))); | ||
259 | } | ||
260 | |||
261 | QString KShell::joinArgs( const QStringList &args ) | ||
262 | { | ||
263 | QChar q( '\'' ); | ||
264 | QString ret; | ||
265 | for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it) { | ||
266 | if (!ret.isEmpty()) | ||
267 | ret += ' '; | ||
268 | if (!(*it).length()) | ||
269 | ret.append( q ).append( q ); | ||
270 | else { | ||
271 | for (uint i = 0; i < (*it).length(); i++) | ||
272 | if (isSpecial((*it).unicode()[i])) { | ||
273 | QString tmp(*it); | ||
274 | tmp.replace( q, "'\\''" ); | ||
275 | ret += q; | ||
276 | tmp += q; | ||
277 | ret += tmp; | ||
278 | goto ex; | ||
279 | } | ||
280 | ret += *it; | ||
281 | ex: ; | ||
282 | } | ||
283 | } | ||
284 | return ret; | ||
285 | } | ||
286 | |||
287 | QString KShell::joinArgs( const char * const *args, int nargs ) | ||
288 | { | ||
289 | if (!args) | ||
290 | return QString::null; // well, QString::empty, in fact. qt sucks ;) | ||
291 | QChar q( '\'' ); | ||
292 | QString ret; | ||
293 | for (const char * const *argp = args; nargs && *argp; argp++, nargs--) { | ||
294 | if (!ret.isEmpty()) | ||
295 | ret += ' '; | ||
296 | if (!**argp) | ||
297 | ret.append( q ).append( q ); | ||
298 | else { | ||
299 | QString tmp( QFile::decodeName( *argp ) ); | ||
300 | for (uint i = 0; i < tmp.length(); i++) | ||
301 | if (isSpecial(tmp.unicode()[i])) { | ||
302 | tmp.replace( q, "'\\''" ); | ||
303 | ret += q; | ||
304 | tmp += q; | ||
305 | ret += tmp; | ||
306 | goto ex; | ||
307 | } | ||
308 | ret += tmp; | ||
309 | ex: ; | ||
310 | } | ||
311 | } | ||
312 | return ret; | ||
313 | } | ||
314 | |||
315 | QString KShell::joinArgsDQ( const QStringList &args ) | ||
316 | { | ||
317 | QChar q( '\'' ), sp( ' ' ), bs( '\\' ); | ||
318 | QString ret; | ||
319 | for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it) { | ||
320 | if (!ret.isEmpty()) | ||
321 | ret += sp; | ||
322 | if (!(*it).length()) | ||
323 | ret.append( q ).append( q ); | ||
324 | else { | ||
325 | for (uint i = 0; i < (*it).length(); i++) | ||
326 | if (isSpecial((*it).unicode()[i])) { | ||
327 | ret.append( '$' ).append( q ); | ||
328 | for (uint pos = 0; pos < (*it).length(); pos++) { | ||
329 | int c = (*it).unicode()[pos]; | ||
330 | if (c < 32) { | ||
331 | ret += bs; | ||
332 | switch (c) { | ||
333 | case '\a': ret += 'a'; break; | ||
334 | case '\b': ret += 'b'; break; | ||
335 | case '\033': ret += 'e'; break; | ||
336 | case '\f': ret += 'f'; break; | ||
337 | case '\n': ret += 'n'; break; | ||
338 | case '\r': ret += 'r'; break; | ||
339 | case '\t': ret += 't'; break; | ||
340 | case '\034': ret += 'c'; ret += '|'; break; | ||
341 | default: ret += 'c'; ret += c + '@'; break; | ||
342 | } | ||
343 | } else { | ||
344 | if (c == '\'' || c == '\\') | ||
345 | ret += bs; | ||
346 | ret += c; | ||
347 | } | ||
348 | } | ||
349 | ret.append( q ); | ||
350 | goto ex; | ||
351 | } | ||
352 | ret += *it; | ||
353 | ex: ; | ||
354 | } | ||
355 | } | ||
356 | return ret; | ||
357 | } | ||
358 | */ | ||
359 | |||
360 | QString KShell::tildeExpand( const QString &fname ) | ||
361 | { | ||
362 | if (fname[0] == '~') { | ||
363 | int pos = fname.find( '/' ); | ||
364 | if (pos < 0) | ||
365 | return homeDir( QConstString( (QChar*)(fname.unicode() + 1), fname.length() - 1 ).string() ); | ||
366 | QString ret = homeDir( QConstString( (QChar*)(fname.unicode() + 1), pos - 1 ).string() ); | ||
367 | if (!ret.isNull()) | ||
368 | ret += QConstString( (QChar*)(fname.unicode() + pos), fname.length() - pos ).string(); | ||
369 | return ret; | ||
370 | } | ||
371 | return fname; | ||
372 | } | ||
373 | |||
374 | QString KShell::homeDir( const QString &user ) | ||
375 | { | ||
376 | #ifdef _WIN32_ | ||
377 | return QDir::homeDirPath(); | ||
378 | #else | ||
379 | if (user.isEmpty()) | ||
380 | return QFile::decodeName( getenv( "HOME" ) ); | ||
381 | struct passwd *pw = getpwnam( QFile::encodeName( user ).data() ); | ||
382 | if (!pw) | ||
383 | return QString::null; | ||
384 | return QFile::decodeName( pw->pw_dir ); | ||
385 | #endif | ||
386 | } | ||