1/*
2 * Copyright 2015, Axel D��rfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "SettingsParser.h"
8
9#include <string.h>
10
11#include <DriverSettingsMessageAdapter.h>
12
13
14class AbstractArgsConverter : public DriverSettingsConverter {
15public:
16	status_t ConvertEmptyFromDriverSettings(
17		const driver_parameter& parameter, const char* name, uint32 type,
18		BMessage& target)
19	{
20		if (parameter.parameter_count != 0 || strcmp(name, Name()) == 0)
21			return B_OK;
22
23		BMessage message;
24		return target.AddMessage(name, &message);
25	}
26
27protected:
28	status_t AddSubMessage(const driver_parameter& parameter, int32 index,
29		BMessage& target)
30	{
31		const char* condition = parameter.values[index];
32		BMessage args;
33		for (index++; index < parameter.value_count; index++) {
34			status_t status = args.AddString("args",
35				parameter.values[index]);
36			if (status != B_OK)
37				return status;
38		}
39		return target.AddMessage(condition, &args);
40	}
41
42	virtual const char* Name() = 0;
43};
44
45
46class ConditionConverter : public AbstractArgsConverter {
47public:
48	status_t ConvertFromDriverSettings(const driver_parameter& parameter,
49		const char* name, int32 index, uint32 type, BMessage& target)
50	{
51		BMessage message;
52		if (strcmp(parameter.name, "if") == 0) {
53			// Parse values directly following "if", with special
54			// handling for the "not" operator.
55			if (index != 0)
56				return B_OK;
57
58			BMessage* add = &target;
59			bool notOperator = parameter.value_count > 1
60				&& strcmp(parameter.values[0], "not") == 0;
61			if (notOperator) {
62				add = &message;
63				index++;
64			}
65
66			status_t status = AddSubMessage(parameter, index, *add);
67			if (status == B_OK && notOperator)
68				status = target.AddMessage("not", &message);
69
70			return status;
71		}
72		if (strcmp(parameter.name, "not") == 0) {
73			if (index != 0)
74				return B_OK;
75
76			return AddSubMessage(parameter, index, target);
77		}
78
79		message.AddString("args", parameter.values[index]);
80		return target.AddMessage(parameter.name, &message);
81	}
82
83	const char* Name()
84	{
85		return "if";
86	}
87};
88
89
90class EventConverter : public AbstractArgsConverter {
91public:
92	status_t ConvertFromDriverSettings(const driver_parameter& parameter,
93		const char* name, int32 index, uint32 type, BMessage& target)
94	{
95		BMessage message;
96		if (strcmp(parameter.name, "on") == 0) {
97			// Parse values directly following "on"
98			if (index != 0)
99				return B_OK;
100
101			return AddSubMessage(parameter, index, target);
102		}
103
104		message.AddString("args", parameter.values[index]);
105		return target.AddMessage(parameter.name, &message);
106	}
107
108	const char* Name()
109	{
110		return "on";
111	}
112};
113
114
115class RunConverter : public DriverSettingsConverter {
116public:
117	status_t ConvertFromDriverSettings(const driver_parameter& parameter,
118		const char* name, int32 index, uint32 type, BMessage& target)
119	{
120		if (parameter.parameter_count == 0)
121			return target.AddString("target", parameter.values[index]);
122
123		return B_NOT_SUPPORTED;
124	}
125
126	status_t ConvertEmptyFromDriverSettings(
127		const driver_parameter& parameter, const char* name, uint32 type,
128		BMessage& target)
129	{
130		if (parameter.parameter_count != 0)
131			return B_OK;
132
133		return target.AddString("target", name);
134	}
135};
136
137
138const static settings_template kConditionTemplate[] = {
139	{B_STRING_TYPE, NULL, NULL, true, new ConditionConverter()},
140	{B_MESSAGE_TYPE, "not", kConditionTemplate},
141	{B_MESSAGE_TYPE, "and", kConditionTemplate},
142	{B_MESSAGE_TYPE, "or", kConditionTemplate},
143	{0, NULL, NULL}
144};
145
146const static settings_template kEventTemplate[] = {
147	{B_STRING_TYPE, NULL, NULL, true, new EventConverter()},
148	{B_MESSAGE_TYPE, "and", kEventTemplate},
149	{B_MESSAGE_TYPE, "or", kEventTemplate},
150	{0, NULL, NULL}
151};
152
153const static settings_template kPortTemplate[] = {
154	{B_STRING_TYPE, "name", NULL, true},
155	{B_INT32_TYPE, "capacity", NULL},
156};
157
158const static settings_template kEnvTemplate[] = {
159	{B_STRING_TYPE, "from_script", NULL, true},
160	{B_STRING_TYPE, NULL, NULL},
161};
162
163const static settings_template kJobTemplate[] = {
164	{B_STRING_TYPE, "name", NULL, true},
165	{B_BOOL_TYPE, "disabled", NULL},
166	{B_STRING_TYPE, "launch", NULL},
167	{B_STRING_TYPE, "requires", NULL},
168	{B_BOOL_TYPE, "legacy", NULL},
169	{B_MESSAGE_TYPE, "port", kPortTemplate},
170	{B_MESSAGE_TYPE, "on", kEventTemplate},
171	{B_MESSAGE_TYPE, "if", kConditionTemplate},
172	{B_BOOL_TYPE, "no_safemode", NULL},
173	{B_BOOL_TYPE, "on_demand", NULL},
174	{B_MESSAGE_TYPE, "env", kEnvTemplate},
175	{0, NULL, NULL}
176};
177
178const static settings_template kTargetTemplate[] = {
179	{B_STRING_TYPE, "name", NULL, true},
180	{B_BOOL_TYPE, "reset", NULL},
181	{B_MESSAGE_TYPE, "on", kEventTemplate},
182	{B_MESSAGE_TYPE, "if", kConditionTemplate},
183	{B_BOOL_TYPE, "no_safemode", NULL},
184	{B_MESSAGE_TYPE, "env", kEnvTemplate},
185	{B_MESSAGE_TYPE, "job", kJobTemplate},
186	{B_MESSAGE_TYPE, "service", kJobTemplate},
187	{0, NULL, NULL}
188};
189
190const static settings_template kRunConditionalTemplate[] = {
191	{B_STRING_TYPE, NULL, NULL, true, new RunConverter()},
192	{0, NULL, NULL}
193};
194
195const static settings_template kRunTemplate[] = {
196	{B_STRING_TYPE, NULL, NULL, true, new RunConverter()},
197	{B_MESSAGE_TYPE, "if", kConditionTemplate},
198	{B_MESSAGE_TYPE, "then", kRunConditionalTemplate},
199	{B_MESSAGE_TYPE, "else", kRunConditionalTemplate},
200	{0, NULL, NULL}
201};
202
203const static settings_template kSettingsTemplate[] = {
204	{B_MESSAGE_TYPE, "target", kTargetTemplate},
205	{B_MESSAGE_TYPE, "job", kJobTemplate},
206	{B_MESSAGE_TYPE, "service", kJobTemplate},
207	{B_MESSAGE_TYPE, "run", kRunTemplate},
208	{0, NULL, NULL}
209};
210
211
212SettingsParser::SettingsParser()
213{
214}
215
216
217status_t
218SettingsParser::ParseFile(const char* path, BMessage& settings)
219{
220	DriverSettingsMessageAdapter adapter;
221	return adapter.ConvertFromDriverSettings(path, kSettingsTemplate, settings);
222}
223
224
225#ifdef TEST_HAIKU
226
227
228status_t
229SettingsParser::Parse(const char* text, BMessage& settings)
230{
231	void* driverSettings = parse_driver_settings_string(text);
232	if (driverSettings == NULL)
233		return B_BAD_VALUE;
234
235	DriverSettingsMessageAdapter adapter;
236	status_t status = adapter.ConvertFromDriverSettings(
237		*get_driver_settings(driverSettings), kSettingsTemplate, settings);
238
239	unload_driver_settings(driverSettings);
240	return status;
241}
242
243
244#endif	// TEST_HAIKU
245