00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <config.h>
00026 #include <string.h>
00027 #include "dbus-internals.h"
00028 #include "dbus-list.h"
00029 #include "dbus-memory.h"
00030 #include "dbus-protocol.h"
00031 #include "dbus-shell.h"
00032 #include "dbus-string.h"
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 static dbus_bool_t
00043 unquote_string_inplace (char* str, char** end)
00044 {
00045 char* dest;
00046 char* s;
00047 char quote_char;
00048
00049 dest = s = str;
00050
00051 quote_char = *s;
00052
00053 if (!(*s == '"' || *s == '\''))
00054 {
00055 *end = str;
00056 return FALSE;
00057 }
00058
00059
00060 ++s;
00061
00062 if (quote_char == '"')
00063 {
00064 while (*s)
00065 {
00066 _dbus_assert(s > dest);
00067
00068 switch (*s)
00069 {
00070 case '"':
00071
00072 *dest = '\0';
00073 ++s;
00074 *end = s;
00075 return TRUE;
00076
00077 case '\\':
00078
00079 ++s;
00080 switch (*s)
00081 {
00082 case '"':
00083 case '\\':
00084 case '`':
00085 case '$':
00086 case '\n':
00087 *dest = *s;
00088 ++s;
00089 ++dest;
00090 break;
00091
00092 default:
00093
00094 *dest = '\\';
00095 ++dest;
00096
00097 break;
00098 }
00099 break;
00100
00101 default:
00102 *dest = *s;
00103 ++dest;
00104 ++s;
00105 break;
00106 }
00107
00108 _dbus_assert(s > dest);
00109 }
00110 }
00111 else
00112 {
00113 while (*s)
00114 {
00115 _dbus_assert(s > dest);
00116
00117 if (*s == '\'')
00118 {
00119
00120 *dest = '\0';
00121 ++s;
00122 *end = s;
00123 return TRUE;
00124 }
00125 else
00126 {
00127 *dest = *s;
00128 ++dest;
00129 ++s;
00130 }
00131
00132 _dbus_assert(s > dest);
00133 }
00134 }
00135
00136
00137
00138 *dest = '\0';
00139
00140 *end = s;
00141 return FALSE;
00142 }
00143
00168 char*
00169 _dbus_shell_unquote (const char *quoted_string)
00170 {
00171 char *unquoted;
00172 char *end;
00173 char *start;
00174 char *ret;
00175 DBusString retval;
00176
00177 unquoted = _dbus_strdup (quoted_string);
00178 if (unquoted == NULL)
00179 return NULL;
00180
00181 start = unquoted;
00182 end = unquoted;
00183 if (!_dbus_string_init (&retval))
00184 {
00185 dbus_free (unquoted);
00186 return NULL;
00187 }
00188
00189
00190
00191
00192 while (*start)
00193 {
00194
00195
00196
00197 while (*start && !(*start == '"' || *start == '\''))
00198 {
00199 if (*start == '\\')
00200 {
00201
00202
00203
00204
00205
00206 ++start;
00207 if (*start)
00208 {
00209 if (*start != '\n')
00210 {
00211 if (!_dbus_string_append_byte (&retval, *start))
00212 goto error;
00213 }
00214 ++start;
00215 }
00216 }
00217 else
00218 {
00219 if (!_dbus_string_append_byte (&retval, *start))
00220 goto error;
00221 ++start;
00222 }
00223 }
00224
00225 if (*start)
00226 {
00227 if (!unquote_string_inplace (start, &end))
00228 goto error;
00229 else
00230 {
00231 if (!_dbus_string_append (&retval, start))
00232 goto error;
00233 start = end;
00234 }
00235 }
00236 }
00237
00238 ret = _dbus_strdup (_dbus_string_get_data (&retval));
00239 if (!ret)
00240 goto error;
00241
00242 dbus_free (unquoted);
00243 _dbus_string_free (&retval);
00244
00245 return ret;
00246
00247 error:
00248 dbus_free (unquoted);
00249 _dbus_string_free (&retval);
00250 return NULL;
00251 }
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 static dbus_bool_t
00323 delimit_token (DBusString *token,
00324 DBusList **retval,
00325 DBusError *error)
00326 {
00327 char *str;
00328
00329 str = _dbus_strdup (_dbus_string_get_data (token));
00330 if (!str)
00331 {
00332 _DBUS_SET_OOM (error);
00333 return FALSE;
00334 }
00335
00336 if (!_dbus_list_append (retval, str))
00337 {
00338 dbus_free (str);
00339 _DBUS_SET_OOM (error);
00340 return FALSE;
00341 }
00342
00343 return TRUE;
00344 }
00345
00346 static DBusList*
00347 tokenize_command_line (const char *command_line, DBusError *error)
00348 {
00349 char current_quote;
00350 const char *p;
00351 DBusString current_token;
00352 DBusList *retval = NULL;
00353 dbus_bool_t quoted;;
00354
00355 current_quote = '\0';
00356 quoted = FALSE;
00357 p = command_line;
00358
00359 if (!_dbus_string_init (¤t_token))
00360 {
00361 _DBUS_SET_OOM (error);
00362 return NULL;
00363 }
00364
00365 while (*p)
00366 {
00367 if (current_quote == '\\')
00368 {
00369 if (*p == '\n')
00370 {
00371
00372 }
00373 else
00374 {
00375 if (!_dbus_string_append_byte (¤t_token, '\\') ||
00376 !_dbus_string_append_byte (¤t_token, *p))
00377 {
00378 _DBUS_SET_OOM (error);
00379 goto error;
00380 }
00381 }
00382
00383 current_quote = '\0';
00384 }
00385 else if (current_quote == '#')
00386 {
00387
00388 while (*p && *p != '\n')
00389 ++p;
00390
00391 current_quote = '\0';
00392
00393 if (*p == '\0')
00394 break;
00395 }
00396 else if (current_quote)
00397 {
00398 if (*p == current_quote &&
00399
00400 !(current_quote == '"' && quoted))
00401 {
00402
00403 current_quote = '\0';
00404 }
00405
00406
00407
00408
00409
00410 if (!_dbus_string_append_byte (¤t_token, *p))
00411 {
00412 _DBUS_SET_OOM (error);
00413 goto error;
00414 }
00415 }
00416 else
00417 {
00418 switch (*p)
00419 {
00420 case '\n':
00421 if (!delimit_token (¤t_token, &retval, error))
00422 goto error;
00423
00424 _dbus_string_free (¤t_token);
00425
00426 if (!_dbus_string_init (¤t_token))
00427 {
00428 _DBUS_SET_OOM (error);
00429 goto init_error;
00430 }
00431
00432 break;
00433
00434 case ' ':
00435 case '\t':
00436
00437
00438
00439
00440 if (_dbus_string_get_length (¤t_token) > 0)
00441 {
00442 if (!delimit_token (¤t_token, &retval, error))
00443 goto error;
00444
00445 _dbus_string_free (¤t_token);
00446
00447 if (!_dbus_string_init (¤t_token))
00448 {
00449 _DBUS_SET_OOM (error);
00450 goto init_error;
00451 }
00452
00453 }
00454
00455
00456 break;
00457
00458
00459
00460
00461
00462
00463
00464 case '\'':
00465 case '"':
00466 if (!_dbus_string_append_byte (¤t_token, *p))
00467 {
00468 _DBUS_SET_OOM (error);
00469 goto error;
00470 }
00471
00472
00473
00474 case '#':
00475 case '\\':
00476 current_quote = *p;
00477 break;
00478
00479 default:
00480
00481
00482
00483 if (!_dbus_string_append_byte (¤t_token, *p))
00484 {
00485 _DBUS_SET_OOM (error);
00486 goto error;
00487 }
00488 break;
00489 }
00490 }
00491
00492
00493
00494
00495 if (*p != '\\')
00496 quoted = FALSE;
00497 else
00498 quoted = !quoted;
00499
00500 ++p;
00501 }
00502
00503 if (!delimit_token (¤t_token, &retval, error))
00504 goto error;
00505
00506 if (current_quote)
00507 {
00508 dbus_set_error_const (error, DBUS_ERROR_INVALID_ARGS, "Unclosed quotes in command line");
00509 goto error;
00510 }
00511
00512 if (retval == NULL)
00513 {
00514 dbus_set_error_const (error, DBUS_ERROR_INVALID_ARGS, "No tokens found in command line");
00515 goto error;
00516 }
00517
00518 _dbus_string_free (¤t_token);
00519
00520 return retval;
00521
00522 error:
00523 _dbus_string_free (¤t_token);
00524
00525 init_error:
00526 if (retval)
00527 {
00528 _dbus_list_foreach (&retval, (DBusForeachFunction) dbus_free, NULL);
00529 _dbus_list_clear (&retval);
00530 }
00531
00532 return NULL;
00533 }
00534
00552 dbus_bool_t
00553 _dbus_shell_parse_argv (const char *command_line,
00554 int *argcp,
00555 char ***argvp,
00556 DBusError *error)
00557 {
00558
00559 int argc = 0;
00560 char **argv = NULL;
00561 DBusList *tokens = NULL;
00562 int i;
00563 DBusList *tmp_list;
00564
00565 if (!command_line)
00566 {
00567 _dbus_verbose ("Command line is NULL\n");
00568 return FALSE;
00569 }
00570
00571 tokens = tokenize_command_line (command_line, error);
00572 if (tokens == NULL)
00573 {
00574 _dbus_verbose ("No tokens for command line '%s'\n", command_line);
00575 return FALSE;
00576 }
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592 argc = _dbus_list_get_length (&tokens);
00593 argv = dbus_new (char *, argc + 1);
00594 if (!argv)
00595 {
00596 _DBUS_SET_OOM (error);
00597 goto error;
00598 }
00599
00600 i = 0;
00601 tmp_list = tokens;
00602 while (tmp_list)
00603 {
00604 argv[i] = _dbus_shell_unquote (tmp_list->data);
00605
00606 if (!argv[i])
00607 {
00608 int j;
00609 for (j = 0; j < i; j++)
00610 dbus_free(argv[j]);
00611
00612 dbus_free (argv);
00613 _DBUS_SET_OOM (error);
00614 goto error;
00615 }
00616
00617 tmp_list = _dbus_list_get_next_link (&tokens, tmp_list);
00618 ++i;
00619 }
00620 argv[argc] = NULL;
00621
00622 _dbus_list_foreach (&tokens, (DBusForeachFunction) dbus_free, NULL);
00623 _dbus_list_clear (&tokens);
00624
00625 if (argcp)
00626 *argcp = argc;
00627
00628 if (argvp)
00629 *argvp = argv;
00630 else
00631 dbus_free_string_array (argv);
00632
00633 return TRUE;
00634
00635 error:
00636 _dbus_list_foreach (&tokens, (DBusForeachFunction) dbus_free, NULL);
00637 _dbus_list_clear (&tokens);
00638
00639 return FALSE;
00640
00641 }