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