1 /*- 2 * Copyright (c) 2012 Michihiro NAKAJIMA 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "archive_platform.h" 27 28 #ifdef HAVE_STRING_H 29 # include <string.h> 30 #endif 31 #ifdef HAVE_STDLIB_H 32 # include <stdlib.h> 33 #endif 34 35 #include "archive.h" 36 #include "archive_cmdline_private.h" 37 #include "archive_string.h" 38 39 static int cmdline_set_path(struct archive_cmdline *, const char *); 40 static int cmdline_add_arg(struct archive_cmdline *, const char *); 41 42 static ssize_t 43 extract_quotation(struct archive_string *as, const char *p) 44 { 45 const char *s; 46 47 for (s = p + 1; *s;) { 48 if (*s == '\\') { 49 if (s[1] != '\0') { 50 archive_strappend_char(as, s[1]); 51 s += 2; 52 } else 53 s++; 54 } else if (*s == '"') 55 break; 56 else { 57 archive_strappend_char(as, s[0]); 58 s++; 59 } 60 } 61 if (*s != '"') 62 return (ARCHIVE_FAILED);/* Invalid sequence. */ 63 return ((ssize_t)(s + 1 - p)); 64 } 65 66 static ssize_t 67 get_argument(struct archive_string *as, const char *p) 68 { 69 const char *s = p; 70 71 archive_string_empty(as); 72 73 /* Skip beginning space characters. */ 74 while (*s != '\0' && *s == ' ') 75 s++; 76 /* Copy non-space characters. */ 77 while (*s != '\0' && *s != ' ') { 78 if (*s == '\\') { 79 if (s[1] != '\0') { 80 archive_strappend_char(as, s[1]); 81 s += 2; 82 } else { 83 s++;/* Ignore this character.*/ 84 break; 85 } 86 } else if (*s == '"') { 87 ssize_t q = extract_quotation(as, s); 88 if (q < 0) 89 return (ARCHIVE_FAILED);/* Invalid sequence. */ 90 s += q; 91 } else { 92 archive_strappend_char(as, s[0]); 93 s++; 94 } 95 } 96 return ((ssize_t)(s - p)); 97 } 98 99 /* 100 * Set up command line arguments. 101 * Returns ARCHIVE_OK if everything okey. 102 * Returns ARCHIVE_FAILED if there is a lack of the `"' terminator or an 103 * empty command line. 104 * Returns ARCHIVE_FATAL if no memory. 105 */ 106 int 107 __archive_cmdline_parse(struct archive_cmdline *data, const char *cmd) 108 { 109 struct archive_string as; 110 const char *p; 111 ssize_t al; 112 int r; 113 114 archive_string_init(&as); 115 116 /* Get first argument as a command path. */ 117 al = get_argument(&as, cmd); 118 if (al < 0) { 119 r = ARCHIVE_FAILED;/* Invalid sequence. */ 120 goto exit_function; 121 } 122 if (archive_strlen(&as) == 0) { 123 r = ARCHIVE_FAILED;/* An empty command path. */ 124 goto exit_function; 125 } 126 r = cmdline_set_path(data, as.s); 127 if (r != ARCHIVE_OK) 128 goto exit_function; 129 p = strrchr(as.s, '/'); 130 if (p == NULL) 131 p = as.s; 132 else 133 p++; 134 r = cmdline_add_arg(data, p); 135 if (r != ARCHIVE_OK) 136 goto exit_function; 137 cmd += al; 138 139 for (;;) { 140 al = get_argument(&as, cmd); 141 if (al < 0) { 142 r = ARCHIVE_FAILED;/* Invalid sequence. */ 143 goto exit_function; 144 } 145 if (al == 0) 146 break; 147 cmd += al; 148 if (archive_strlen(&as) == 0 && *cmd == '\0') 149 break; 150 r = cmdline_add_arg(data, as.s); 151 if (r != ARCHIVE_OK) 152 goto exit_function; 153 } 154 r = ARCHIVE_OK; 155 exit_function: 156 archive_string_free(&as); 157 return (r); 158 } 159 160 /* 161 * Set the program path. 162 */ 163 static int 164 cmdline_set_path(struct archive_cmdline *data, const char *path) 165 { 166 char *newptr; 167 168 newptr = realloc(data->path, strlen(path) + 1); 169 if (newptr == NULL) 170 return (ARCHIVE_FATAL); 171 data->path = newptr; 172 strcpy(data->path, path); 173 return (ARCHIVE_OK); 174 } 175 176 /* 177 * Add a argument for the program. 178 */ 179 static int 180 cmdline_add_arg(struct archive_cmdline *data, const char *arg) 181 { 182 char **newargv; 183 184 if (data->path == NULL) 185 return (ARCHIVE_FAILED); 186 187 newargv = realloc(data->argv, (data->argc + 2) * sizeof(char *)); 188 if (newargv == NULL) 189 return (ARCHIVE_FATAL); 190 data->argv = newargv; 191 data->argv[data->argc] = strdup(arg); 192 if (data->argv[data->argc] == NULL) 193 return (ARCHIVE_FATAL); 194 /* Set the terminator of argv. */ 195 data->argv[++data->argc] = NULL; 196 return (ARCHIVE_OK); 197 } 198 199 struct archive_cmdline * 200 __archive_cmdline_allocate(void) 201 { 202 return (struct archive_cmdline *) 203 calloc(1, sizeof(struct archive_cmdline)); 204 } 205 206 /* 207 * Release the resources. 208 */ 209 int 210 __archive_cmdline_free(struct archive_cmdline *data) 211 { 212 213 if (data) { 214 free(data->path); 215 if (data->argv != NULL) { 216 int i; 217 for (i = 0; data->argv[i] != NULL; i++) 218 free(data->argv[i]); 219 free(data->argv); 220 } 221 free(data); 222 } 223 return (ARCHIVE_OK); 224 } 225 226