1231200Smm/*-
2231200Smm * Copyright (c) 2011 Tim Kientzle
3231200Smm * All rights reserved.
4231200Smm *
5231200Smm * Redistribution and use in source and binary forms, with or without
6231200Smm * modification, are permitted provided that the following conditions
7231200Smm * are met:
8231200Smm * 1. Redistributions of source code must retain the above copyright
9231200Smm *    notice, this list of conditions and the following disclaimer.
10231200Smm * 2. Redistributions in binary form must reproduce the above copyright
11231200Smm *    notice, this list of conditions and the following disclaimer in the
12231200Smm *    documentation and/or other materials provided with the distribution.
13231200Smm *
14231200Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15231200Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16231200Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17231200Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18231200Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19231200Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20231200Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21231200Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22231200Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23231200Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24231200Smm */
25231200Smm
26231200Smm#include "archive_platform.h"
27231200Smm__FBSDID("$FreeBSD$");
28231200Smm
29231200Smm#include "archive_options_private.h"
30231200Smm
31231200Smmstatic const char *
32231200Smmparse_option(const char **str,
33231200Smm    const char **mod, const char **opt, const char **val);
34231200Smm
35231200Smmint
36231200Smm_archive_set_option(struct archive *a,
37231200Smm    const char *m, const char *o, const char *v,
38231200Smm    int magic, const char *fn, option_handler use_option)
39231200Smm{
40231200Smm	const char *mp, *op, *vp;
41232153Smm	int r;
42231200Smm
43231200Smm	archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
44231200Smm
45231200Smm	mp = m != NULL && m[0] == '\0' ? NULL : m;
46231200Smm	op = o != NULL && o[0] == '\0' ? NULL : o;
47231200Smm	vp = v != NULL && v[0] == '\0' ? NULL : v;
48231200Smm
49231200Smm	if (op == NULL && vp == NULL)
50231200Smm		return (ARCHIVE_OK);
51232153Smm	if (op == NULL) {
52232153Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC, "Empty option");
53231200Smm		return (ARCHIVE_FAILED);
54232153Smm	}
55231200Smm
56232153Smm	r = use_option(a, mp, op, vp);
57232153Smm	if (r == ARCHIVE_WARN - 1) {
58232153Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
59232153Smm		    "Unknown module name: `%s'", mp);
60232153Smm		return (ARCHIVE_FAILED);
61232153Smm	}
62232153Smm	if (r == ARCHIVE_WARN) {
63232153Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
64232153Smm		    "Undefined option: `%s%s%s%s%s%s'",
65232153Smm		    vp?"":"!", mp?mp:"", mp?":":"", op, vp?"=":"", vp?vp:"");
66232153Smm		return (ARCHIVE_FAILED);
67232153Smm	}
68232153Smm	return (r);
69231200Smm}
70231200Smm
71231200Smmint
72231200Smm_archive_set_either_option(struct archive *a, const char *m, const char *o, const char *v,
73231200Smm    option_handler use_format_option, option_handler use_filter_option)
74231200Smm{
75231200Smm	int r1, r2;
76231200Smm
77231200Smm	if (o == NULL && v == NULL)
78231200Smm		return (ARCHIVE_OK);
79231200Smm	if (o == NULL)
80231200Smm		return (ARCHIVE_FAILED);
81231200Smm
82231200Smm	r1 = use_format_option(a, m, o, v);
83231200Smm	if (r1 == ARCHIVE_FATAL)
84231200Smm		return (ARCHIVE_FATAL);
85231200Smm
86231200Smm	r2 = use_filter_option(a, m, o, v);
87231200Smm	if (r2 == ARCHIVE_FATAL)
88231200Smm		return (ARCHIVE_FATAL);
89231200Smm
90248616Smm	if (r2 == ARCHIVE_WARN - 1)
91248616Smm		return r1;
92231200Smm	return r1 > r2 ? r1 : r2;
93231200Smm}
94231200Smm
95231200Smmint
96231200Smm_archive_set_options(struct archive *a, const char *options,
97231200Smm    int magic, const char *fn, option_handler use_option)
98231200Smm{
99248616Smm	int allok = 1, anyok = 0, ignore_mod_err = 0, r;
100231200Smm	char *data;
101231200Smm	const char *s, *mod, *opt, *val;
102231200Smm
103231200Smm	archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
104231200Smm
105231200Smm	if (options == NULL || options[0] == '\0')
106231200Smm		return ARCHIVE_OK;
107231200Smm
108231200Smm	data = (char *)malloc(strlen(options) + 1);
109231200Smm	strcpy(data, options);
110231200Smm	s = (const char *)data;
111231200Smm
112231200Smm	do {
113231200Smm		mod = opt = val = NULL;
114231200Smm
115231200Smm		parse_option(&s, &mod, &opt, &val);
116248616Smm		if (mod == NULL && opt != NULL &&
117248616Smm		    strcmp("__ignore_wrong_module_name__", opt) == 0) {
118248616Smm			/* Ignore module name error */
119248616Smm			if (val != NULL) {
120248616Smm				ignore_mod_err = 1;
121248616Smm				anyok = 1;
122248616Smm			}
123248616Smm			continue;
124248616Smm		}
125231200Smm
126231200Smm		r = use_option(a, mod, opt, val);
127231200Smm		if (r == ARCHIVE_FATAL) {
128231200Smm			free(data);
129231200Smm			return (ARCHIVE_FATAL);
130231200Smm		}
131232153Smm		if (r == ARCHIVE_FAILED && mod != NULL) {
132232153Smm			free(data);
133232153Smm			return (ARCHIVE_FAILED);
134232153Smm		}
135232153Smm		if (r == ARCHIVE_WARN - 1) {
136248616Smm			if (ignore_mod_err)
137248616Smm				continue;
138232153Smm			/* The module name is wrong. */
139232153Smm			archive_set_error(a, ARCHIVE_ERRNO_MISC,
140232153Smm			    "Unknown module name: `%s'", mod);
141232153Smm			free(data);
142232153Smm			return (ARCHIVE_FAILED);
143232153Smm		}
144232153Smm		if (r == ARCHIVE_WARN) {
145232153Smm			/* The option name is wrong. No-one used this. */
146232153Smm			archive_set_error(a, ARCHIVE_ERRNO_MISC,
147232153Smm			    "Undefined option: `%s%s%s'",
148232153Smm			    mod?mod:"", mod?":":"", opt);
149232153Smm			free(data);
150232153Smm			return (ARCHIVE_FAILED);
151232153Smm		}
152231200Smm		if (r == ARCHIVE_OK)
153231200Smm			anyok = 1;
154231200Smm		else
155231200Smm			allok = 0;
156231200Smm	} while (s != NULL);
157231200Smm
158231200Smm	free(data);
159231200Smm	return allok ? ARCHIVE_OK : anyok ? ARCHIVE_WARN : ARCHIVE_FAILED;
160231200Smm}
161231200Smm
162231200Smmstatic const char *
163231200Smmparse_option(const char **s, const char **m, const char **o, const char **v)
164231200Smm{
165231200Smm	const char *end, *mod, *opt, *val;
166231200Smm	char *p;
167231200Smm
168231200Smm	end = NULL;
169231200Smm	mod = NULL;
170231200Smm	opt = *s;
171231200Smm	val = "1";
172231200Smm
173231200Smm	p = strchr(opt, ',');
174231200Smm
175231200Smm	if (p != NULL) {
176231200Smm		*p = '\0';
177231200Smm		end = ((const char *)p) + 1;
178231200Smm	}
179231200Smm
180231200Smm	if (0 == strlen(opt)) {
181231200Smm		*s = end;
182231200Smm		*m = NULL;
183231200Smm		*o = NULL;
184231200Smm		*v = NULL;
185231200Smm		return end;
186231200Smm	}
187231200Smm
188231200Smm	p = strchr(opt, ':');
189231200Smm	if (p != NULL) {
190231200Smm		*p = '\0';
191231200Smm		mod = opt;
192231200Smm		opt = ++p;
193231200Smm	}
194231200Smm
195231200Smm	p = strchr(opt, '=');
196231200Smm	if (p != NULL) {
197231200Smm		*p = '\0';
198231200Smm		val = ++p;
199231200Smm	} else if (opt[0] == '!') {
200231200Smm		++opt;
201231200Smm		val = NULL;
202231200Smm	}
203231200Smm
204231200Smm	*s = end;
205231200Smm	*m = mod;
206231200Smm	*o = opt;
207231200Smm	*v = val;
208231200Smm
209231200Smm	return end;
210231200Smm}
211231200Smm
212