/src/CMake/Utilities/cmlibarchive/libarchive/archive_cmdline.c
Line | Count | Source |
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_add_arg(struct archive_cmdline *, const char *); |
40 | | |
41 | | static ssize_t |
42 | | extract_quotation(struct archive_string *as, const char *p) |
43 | 0 | { |
44 | 0 | const char *s; |
45 | |
|
46 | 0 | for (s = p + 1; *s;) { |
47 | 0 | if (*s == '\\') { |
48 | 0 | if (s[1] != '\0') { |
49 | 0 | archive_strappend_char(as, s[1]); |
50 | 0 | s += 2; |
51 | 0 | } else |
52 | 0 | s++; |
53 | 0 | } else if (*s == '"') |
54 | 0 | break; |
55 | 0 | else { |
56 | 0 | archive_strappend_char(as, s[0]); |
57 | 0 | s++; |
58 | 0 | } |
59 | 0 | } |
60 | 0 | if (*s != '"') |
61 | 0 | return (ARCHIVE_FAILED);/* Invalid sequence. */ |
62 | 0 | return ((ssize_t)(s + 1 - p)); |
63 | 0 | } |
64 | | |
65 | | static ssize_t |
66 | | get_argument(struct archive_string *as, const char *p) |
67 | 58 | { |
68 | 58 | const char *s = p; |
69 | | |
70 | 58 | archive_string_empty(as); |
71 | | |
72 | | /* Skip beginning space characters. */ |
73 | 84 | while (*s == ' ') |
74 | 26 | s++; |
75 | | /* Copy non-space characters. */ |
76 | 178 | while (*s != '\0' && *s != ' ') { |
77 | 120 | if (*s == '\\') { |
78 | 0 | if (s[1] != '\0') { |
79 | 0 | archive_strappend_char(as, s[1]); |
80 | 0 | s += 2; |
81 | 0 | } else { |
82 | 0 | s++;/* Ignore this character.*/ |
83 | 0 | break; |
84 | 0 | } |
85 | 120 | } else if (*s == '"') { |
86 | 0 | ssize_t q = extract_quotation(as, s); |
87 | 0 | if (q < 0) |
88 | 0 | return (ARCHIVE_FAILED);/* Invalid sequence. */ |
89 | 0 | s += q; |
90 | 120 | } else { |
91 | 120 | archive_strappend_char(as, s[0]); |
92 | 120 | s++; |
93 | 120 | } |
94 | 120 | } |
95 | 58 | return ((ssize_t)(s - p)); |
96 | 58 | } |
97 | | |
98 | | /* |
99 | | * Set up command line arguments. |
100 | | * Returns ARCHIVE_OK if everything okay. |
101 | | * Returns ARCHIVE_FAILED if there is a lack of the `"' terminator or an |
102 | | * empty command line. |
103 | | * Returns ARCHIVE_FATAL if no memory. |
104 | | */ |
105 | | int |
106 | | __archive_cmdline_parse(struct archive_cmdline *data, const char *cmd) |
107 | 16 | { |
108 | 16 | struct archive_string as; |
109 | 16 | const char *p; |
110 | 16 | ssize_t al; |
111 | 16 | int r; |
112 | | |
113 | 16 | archive_string_init(&as); |
114 | | |
115 | | /* Get first argument as a command path. */ |
116 | 16 | al = get_argument(&as, cmd); |
117 | 16 | if (al < 0) { |
118 | 0 | r = ARCHIVE_FAILED;/* Invalid sequence. */ |
119 | 0 | goto exit_function; |
120 | 0 | } |
121 | 16 | if (archive_strlen(&as) == 0) { |
122 | 0 | r = ARCHIVE_FAILED;/* An empty command path. */ |
123 | 0 | goto exit_function; |
124 | 0 | } |
125 | 16 | free(data->path); |
126 | 16 | data->path = strdup(as.s); |
127 | 16 | if (data->path == NULL) { |
128 | 0 | r = ARCHIVE_FATAL; |
129 | 0 | goto exit_function; |
130 | 0 | } |
131 | 16 | p = strrchr(as.s, '/'); |
132 | 16 | if (p == NULL) |
133 | 16 | p = as.s; |
134 | 0 | else |
135 | 0 | p++; |
136 | 16 | r = cmdline_add_arg(data, p); |
137 | 16 | if (r != ARCHIVE_OK) |
138 | 0 | goto exit_function; |
139 | 16 | cmd += al; |
140 | | |
141 | 42 | for (;;) { |
142 | 42 | al = get_argument(&as, cmd); |
143 | 42 | if (al < 0) { |
144 | 0 | r = ARCHIVE_FAILED;/* Invalid sequence. */ |
145 | 0 | goto exit_function; |
146 | 0 | } |
147 | 42 | if (al == 0) |
148 | 16 | break; |
149 | 26 | cmd += al; |
150 | 26 | if (archive_strlen(&as) == 0 && *cmd == '\0') |
151 | 0 | break; |
152 | 26 | r = cmdline_add_arg(data, as.s); |
153 | 26 | if (r != ARCHIVE_OK) |
154 | 0 | goto exit_function; |
155 | 26 | } |
156 | 16 | r = ARCHIVE_OK; |
157 | 16 | exit_function: |
158 | 16 | archive_string_free(&as); |
159 | 16 | return (r); |
160 | 16 | } |
161 | | |
162 | | /* |
163 | | * Add an argument for the program. |
164 | | */ |
165 | | static int |
166 | | cmdline_add_arg(struct archive_cmdline *data, const char *arg) |
167 | 42 | { |
168 | 42 | char **newargv; |
169 | | |
170 | 42 | if (data->path == NULL) |
171 | 0 | return (ARCHIVE_FAILED); |
172 | | |
173 | 42 | newargv = realloc(data->argv, (data->argc + 2) * sizeof(char *)); |
174 | 42 | if (newargv == NULL) |
175 | 0 | return (ARCHIVE_FATAL); |
176 | 42 | data->argv = newargv; |
177 | 42 | data->argv[data->argc] = strdup(arg); |
178 | 42 | if (data->argv[data->argc] == NULL) |
179 | 0 | return (ARCHIVE_FATAL); |
180 | | /* Set the terminator of argv. */ |
181 | 42 | data->argv[++data->argc] = NULL; |
182 | 42 | return (ARCHIVE_OK); |
183 | 42 | } |
184 | | |
185 | | struct archive_cmdline * |
186 | | __archive_cmdline_allocate(void) |
187 | 16 | { |
188 | 16 | return (struct archive_cmdline *) |
189 | 16 | calloc(1, sizeof(struct archive_cmdline)); |
190 | 16 | } |
191 | | |
192 | | /* |
193 | | * Release the resources. |
194 | | */ |
195 | | int |
196 | | __archive_cmdline_free(struct archive_cmdline *data) |
197 | 16 | { |
198 | | |
199 | 16 | if (data) { |
200 | 16 | free(data->path); |
201 | 16 | if (data->argv != NULL) { |
202 | 16 | int i; |
203 | 58 | for (i = 0; data->argv[i] != NULL; i++) |
204 | 42 | free(data->argv[i]); |
205 | 16 | free(data->argv); |
206 | 16 | } |
207 | 16 | free(data); |
208 | 16 | } |
209 | 16 | return (ARCHIVE_OK); |
210 | 16 | } |
211 | | |