xref: /haiku/src/system/libroot/os/driver_settings.cpp (revision 37c83f4e8f0fa07ed8aba7d581fba6e5240f6533)
185db3873SIngo Weinhold /*
285db3873SIngo Weinhold  * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de.
385db3873SIngo Weinhold  * This file may be used under the terms of the MIT License.
485db3873SIngo Weinhold  */
585db3873SIngo Weinhold 
685db3873SIngo Weinhold /*!	\brief Implements the driver settings API
785db3873SIngo Weinhold 	This file is used by three different components with different needs:
885db3873SIngo Weinhold 	  1) the boot loader
985db3873SIngo Weinhold 		Buffers a list of settings files to move over to the kernel - the
1085db3873SIngo Weinhold 		actual buffering is located in the boot loader directly, though.
1185db3873SIngo Weinhold 		Creates driver_settings structures out of those on demand only.
1285db3873SIngo Weinhold 	  2) the kernel
1385db3873SIngo Weinhold 		Maintains a list of settings so that no disk access is required
1485db3873SIngo Weinhold 		for known settings (such as those passed over from the boot
1585db3873SIngo Weinhold 		loader).
1685db3873SIngo Weinhold 	  3) libroot.so
1785db3873SIngo Weinhold 		Exports the parser to userland applications, so that they can
1885db3873SIngo Weinhold 		easily make use of driver_settings styled files.
1985db3873SIngo Weinhold 
2085db3873SIngo Weinhold 	The file has to be recompiled for every component separately, so that
2185db3873SIngo Weinhold 	it properly exports the required functionality (which is specified by
2285db3873SIngo Weinhold 	_BOOT_MODE for the boot loader, and _KERNEL_MODE for the kernel).
2385db3873SIngo Weinhold */
2485db3873SIngo Weinhold 
2585db3873SIngo Weinhold // The boot loader is compiled with kernel rules, but we want to explicitely
2685db3873SIngo Weinhold // differentiate between the two here.
2785db3873SIngo Weinhold #ifdef _BOOT_MODE
2885db3873SIngo Weinhold #	undef _KERNEL_MODE
2985db3873SIngo Weinhold #endif
3085db3873SIngo Weinhold 
31323b6546SOliver Tappe #include <directories.h>
3285db3873SIngo Weinhold #include <driver_settings.h>
3385db3873SIngo Weinhold #include <FindDirectory.h>
3485db3873SIngo Weinhold #include <OS.h>
3585db3873SIngo Weinhold 
3685db3873SIngo Weinhold #ifdef _KERNEL_MODE
3785db3873SIngo Weinhold #	include <KernelExport.h>
3885db3873SIngo Weinhold #	include <util/list.h>
3985db3873SIngo Weinhold #	include <lock.h>
4085db3873SIngo Weinhold #	include <kdriver_settings.h>
4185db3873SIngo Weinhold #	include <kernel.h>
4285db3873SIngo Weinhold #	include <boot/kernel_args.h>
4385db3873SIngo Weinhold #	include <boot_device.h>
4485db3873SIngo Weinhold #endif
4585db3873SIngo Weinhold #ifdef _BOOT_MODE
4685db3873SIngo Weinhold #	include <boot/kernel_args.h>
4785db3873SIngo Weinhold #	include <boot/stage2.h>
4885db3873SIngo Weinhold #endif
4985db3873SIngo Weinhold 
5085db3873SIngo Weinhold #include <stdlib.h>
5185db3873SIngo Weinhold #include <string.h>
5285db3873SIngo Weinhold #include <unistd.h>
5385db3873SIngo Weinhold #include <fcntl.h>
5485db3873SIngo Weinhold #include <ctype.h>
5585db3873SIngo Weinhold 
56*37c83f4eSIngo Weinhold #ifndef B_BUFFER_OVERFLOW
5785db3873SIngo Weinhold #	define B_BUFFER_OVERFLOW B_ERROR
5885db3873SIngo Weinhold #endif
5985db3873SIngo Weinhold 
6085db3873SIngo Weinhold #define SETTINGS_DIRECTORY "/kernel/drivers/"
6185db3873SIngo Weinhold #define SETTINGS_MAGIC		'DrvS'
6285db3873SIngo Weinhold 
6385db3873SIngo Weinhold // Those maximum values are independent from the implementation - they
6485db3873SIngo Weinhold // have been chosen to make the code more robust against bad files
6585db3873SIngo Weinhold #define MAX_SETTINGS_SIZE	32768
6685db3873SIngo Weinhold #define MAX_SETTINGS_LEVEL	8
6785db3873SIngo Weinhold 
6885db3873SIngo Weinhold #define CONTINUE_PARAMETER	1
6985db3873SIngo Weinhold #define NO_PARAMETER 2
7085db3873SIngo Weinhold 
7185db3873SIngo Weinhold 
7285db3873SIngo Weinhold typedef struct settings_handle {
7385db3873SIngo Weinhold #ifdef _KERNEL_MODE
7485db3873SIngo Weinhold 	list_link	link;
7585db3873SIngo Weinhold 	char		name[B_OS_NAME_LENGTH];
7685db3873SIngo Weinhold 	int32		ref_count;
7785db3873SIngo Weinhold #endif
7885db3873SIngo Weinhold 	int32		magic;
7985db3873SIngo Weinhold 	struct		driver_settings settings;
8085db3873SIngo Weinhold 	char		*text;
8185db3873SIngo Weinhold } settings_handle;
8285db3873SIngo Weinhold 
8385db3873SIngo Weinhold 
8485db3873SIngo Weinhold enum assignment_mode {
8585db3873SIngo Weinhold 	NO_ASSIGNMENT,
8685db3873SIngo Weinhold 	ALLOW_ASSIGNMENT,
8785db3873SIngo Weinhold 	IGNORE_ASSIGNMENT
8885db3873SIngo Weinhold };
8985db3873SIngo Weinhold 
9085db3873SIngo Weinhold 
9185db3873SIngo Weinhold #ifdef _KERNEL_MODE
9285db3873SIngo Weinhold static struct list sHandles;
9385db3873SIngo Weinhold static mutex sLock = MUTEX_INITIALIZER("driver settings");
9485db3873SIngo Weinhold #endif
9585db3873SIngo Weinhold 
9685db3873SIngo Weinhold 
9785db3873SIngo Weinhold //	#pragma mark - private functions
9885db3873SIngo Weinhold 
9985db3873SIngo Weinhold 
10085db3873SIngo Weinhold /*!
10185db3873SIngo Weinhold 	Returns true for any characters that separate parameters -
10285db3873SIngo Weinhold 	those are ignored in the input stream and won't be added
10385db3873SIngo Weinhold 	to any words.
10485db3873SIngo Weinhold */
10585db3873SIngo Weinhold static inline bool
10685db3873SIngo Weinhold is_parameter_separator(char c)
10785db3873SIngo Weinhold {
10885db3873SIngo Weinhold 	return c == '\n' || c == ';';
10985db3873SIngo Weinhold }
11085db3873SIngo Weinhold 
11185db3873SIngo Weinhold 
11285db3873SIngo Weinhold /** Indicates if "c" begins a new word or not.
11385db3873SIngo Weinhold  */
11485db3873SIngo Weinhold 
11585db3873SIngo Weinhold static inline bool
11685db3873SIngo Weinhold is_word_break(char c)
11785db3873SIngo Weinhold {
11885db3873SIngo Weinhold 	return isspace(c) || is_parameter_separator(c);
11985db3873SIngo Weinhold }
12085db3873SIngo Weinhold 
12185db3873SIngo Weinhold 
12285db3873SIngo Weinhold static inline bool
12385db3873SIngo Weinhold check_handle(settings_handle *handle)
12485db3873SIngo Weinhold {
12585db3873SIngo Weinhold 	if (handle == NULL
12685db3873SIngo Weinhold 		|| handle->magic != SETTINGS_MAGIC)
12785db3873SIngo Weinhold 		return false;
12885db3873SIngo Weinhold 
12985db3873SIngo Weinhold 	return true;
13085db3873SIngo Weinhold }
13185db3873SIngo Weinhold 
13285db3873SIngo Weinhold 
13385db3873SIngo Weinhold static driver_parameter *
13485db3873SIngo Weinhold get_parameter(settings_handle *handle, const char *name)
13585db3873SIngo Weinhold {
13685db3873SIngo Weinhold 	int32 i;
13785db3873SIngo Weinhold 	for (i = handle->settings.parameter_count; i-- > 0;) {
13885db3873SIngo Weinhold 		if (!strcmp(handle->settings.parameters[i].name, name))
13985db3873SIngo Weinhold 			return &handle->settings.parameters[i];
14085db3873SIngo Weinhold 	}
14185db3873SIngo Weinhold 	return NULL;
14285db3873SIngo Weinhold }
14385db3873SIngo Weinhold 
14485db3873SIngo Weinhold 
14585db3873SIngo Weinhold /*!
14685db3873SIngo Weinhold 	Returns the next word in the input buffer passed in via "_pos" - if
14785db3873SIngo Weinhold 	this function returns, it will bump the input position after the word.
14885db3873SIngo Weinhold 	It automatically cares about quoted strings and escaped characters.
14985db3873SIngo Weinhold 	If "allowNewLine" is true, it reads over comments to get to the next
15085db3873SIngo Weinhold 	word.
15185db3873SIngo Weinhold 	Depending on the "assignmentMode" parameter, the '=' sign is either
15285db3873SIngo Weinhold 	used as a work break, or not.
15385db3873SIngo Weinhold 	The input buffer will be changed to contain the word without quotes
15485db3873SIngo Weinhold 	or escaped characters and adds a terminating NULL byte. The "_word"
15585db3873SIngo Weinhold 	parameter will be set to the beginning of the word.
15685db3873SIngo Weinhold 	If the word is followed by a newline it will return B_OK, if white
15785db3873SIngo Weinhold 	spaces follows, it will return CONTINUE_PARAMETER.
15885db3873SIngo Weinhold */
15985db3873SIngo Weinhold static status_t
16085db3873SIngo Weinhold get_word(char **_pos, char **_word, int32 assignmentMode, bool allowNewLine)
16185db3873SIngo Weinhold {
16285db3873SIngo Weinhold 	char *pos = *_pos;
16385db3873SIngo Weinhold 	char quoted = 0;
16485db3873SIngo Weinhold 	bool newLine = false, end = false;
16585db3873SIngo Weinhold 	int escaped = 0;
16685db3873SIngo Weinhold 	bool charEscaped = false;
16785db3873SIngo Weinhold 
16885db3873SIngo Weinhold 	// Skip any white space and comments
16985db3873SIngo Weinhold 	while (pos[0]
17085db3873SIngo Weinhold 		&& ((allowNewLine && (isspace(pos[0]) || is_parameter_separator(pos[0])
17185db3873SIngo Weinhold 				|| pos[0] == '#'))
17285db3873SIngo Weinhold 			|| (!allowNewLine && (pos[0] == '\t' || pos[0] == ' '))
17385db3873SIngo Weinhold 			|| (assignmentMode == ALLOW_ASSIGNMENT && pos[0] == '='))) {
17485db3873SIngo Weinhold 		// skip any comment lines
17585db3873SIngo Weinhold 		if (pos[0] == '#') {
17685db3873SIngo Weinhold 			while (pos[0] && pos[0] != '\n')
17785db3873SIngo Weinhold 				pos++;
17885db3873SIngo Weinhold 		}
17985db3873SIngo Weinhold 		pos++;
18085db3873SIngo Weinhold 	}
18185db3873SIngo Weinhold 
18285db3873SIngo Weinhold 	if (pos[0] == '}' || pos[0] == '\0') {
18385db3873SIngo Weinhold 		// if we just read some white space before an end of a
18485db3873SIngo Weinhold 		// parameter, this is just no parameter at all
18585db3873SIngo Weinhold 		*_pos = pos;
18685db3873SIngo Weinhold 		return NO_PARAMETER;
18785db3873SIngo Weinhold 	}
18885db3873SIngo Weinhold 
18985db3873SIngo Weinhold 	// Read in a word - might contain escaped (\) spaces, or it
19085db3873SIngo Weinhold 	// might also be quoted (" or ').
19185db3873SIngo Weinhold 
19285db3873SIngo Weinhold 	if (pos[0] == '"' || pos[0] == '\'') {
19385db3873SIngo Weinhold 		quoted = pos[0];
19485db3873SIngo Weinhold 		pos++;
19585db3873SIngo Weinhold 	}
19685db3873SIngo Weinhold 	*_word = pos;
19785db3873SIngo Weinhold 
19885db3873SIngo Weinhold 	while (pos[0]) {
19985db3873SIngo Weinhold 		if (charEscaped)
20085db3873SIngo Weinhold 			charEscaped = false;
20185db3873SIngo Weinhold 		else if (pos[0] == '\\') {
20285db3873SIngo Weinhold 			charEscaped = true;
20385db3873SIngo Weinhold 			escaped++;
20485db3873SIngo Weinhold 		} else if ((!quoted && (is_word_break(pos[0])
20585db3873SIngo Weinhold 				|| (assignmentMode != IGNORE_ASSIGNMENT && pos[0] == '=')))
20685db3873SIngo Weinhold 			|| (quoted && pos[0] == quoted))
20785db3873SIngo Weinhold 			break;
20885db3873SIngo Weinhold 
20985db3873SIngo Weinhold 		pos++;
21085db3873SIngo Weinhold 	}
21185db3873SIngo Weinhold 
21285db3873SIngo Weinhold 	// "String exceeds line" - missing end quote
21385db3873SIngo Weinhold 	if (quoted && pos[0] != quoted)
21485db3873SIngo Weinhold 		return B_BAD_DATA;
21585db3873SIngo Weinhold 
21685db3873SIngo Weinhold 	// last character is a backslash
21785db3873SIngo Weinhold 	if (charEscaped)
21885db3873SIngo Weinhold 		return B_BAD_DATA;
21985db3873SIngo Weinhold 
22085db3873SIngo Weinhold 	end = pos[0] == '\0';
22185db3873SIngo Weinhold 	newLine = is_parameter_separator(pos[0]) || end;
22285db3873SIngo Weinhold 	pos[0] = '\0';
22385db3873SIngo Weinhold 
22485db3873SIngo Weinhold 	// Correct name if there were any escaped characters
22585db3873SIngo Weinhold 	if (escaped) {
22685db3873SIngo Weinhold 		char *word = *_word;
22785db3873SIngo Weinhold 		int offset = 0;
22885db3873SIngo Weinhold 		while (word <= pos) {
22985db3873SIngo Weinhold 			if (word[0] == '\\') {
23085db3873SIngo Weinhold 				offset--;
23185db3873SIngo Weinhold 				word++;
23285db3873SIngo Weinhold 			}
23385db3873SIngo Weinhold 			word[offset] = word[0];
23485db3873SIngo Weinhold 			word++;
23585db3873SIngo Weinhold 		}
23685db3873SIngo Weinhold 	}
23785db3873SIngo Weinhold 
23885db3873SIngo Weinhold 	if (end) {
23985db3873SIngo Weinhold 		*_pos = pos;
24085db3873SIngo Weinhold 		return B_OK;
24185db3873SIngo Weinhold 	}
24285db3873SIngo Weinhold 
24385db3873SIngo Weinhold 	// Scan for next beginning word, open brackets, or comment start
24485db3873SIngo Weinhold 
24585db3873SIngo Weinhold 	pos++;
24685db3873SIngo Weinhold 	while (true) {
24785db3873SIngo Weinhold 		*_pos = pos;
24885db3873SIngo Weinhold 		if (!pos[0])
24985db3873SIngo Weinhold 			return B_NO_ERROR;
25085db3873SIngo Weinhold 
25185db3873SIngo Weinhold 		if (is_parameter_separator(pos[0])) {
25285db3873SIngo Weinhold 			// an open bracket '{' could follow after the first
25385db3873SIngo Weinhold 			// newline, but not later
25485db3873SIngo Weinhold 			if (newLine)
25585db3873SIngo Weinhold 				return B_NO_ERROR;
25685db3873SIngo Weinhold 
25785db3873SIngo Weinhold 			newLine = true;
25885db3873SIngo Weinhold 		} else if (pos[0] == '{' || pos[0] == '}' || pos[0] == '#')
25985db3873SIngo Weinhold 			return B_NO_ERROR;
26085db3873SIngo Weinhold 		else if (!isspace(pos[0]))
26185db3873SIngo Weinhold 			return newLine ? B_NO_ERROR : CONTINUE_PARAMETER;
26285db3873SIngo Weinhold 
26385db3873SIngo Weinhold 		pos++;
26485db3873SIngo Weinhold 	}
26585db3873SIngo Weinhold }
26685db3873SIngo Weinhold 
26785db3873SIngo Weinhold 
26885db3873SIngo Weinhold static status_t
26985db3873SIngo Weinhold parse_parameter(struct driver_parameter *parameter, char **_pos, int32 level)
27085db3873SIngo Weinhold {
27185db3873SIngo Weinhold 	char *pos = *_pos;
27285db3873SIngo Weinhold 	status_t status;
27385db3873SIngo Weinhold 
27485db3873SIngo Weinhold 	// initialize parameter first
27585db3873SIngo Weinhold 	memset(parameter, 0, sizeof(struct driver_parameter));
27685db3873SIngo Weinhold 
27785db3873SIngo Weinhold 	status = get_word(&pos, &parameter->name, NO_ASSIGNMENT, true);
27885db3873SIngo Weinhold 	if (status == CONTINUE_PARAMETER) {
27985db3873SIngo Weinhold 		while (status == CONTINUE_PARAMETER) {
28085db3873SIngo Weinhold 			char **newArray, *value;
28185db3873SIngo Weinhold 			status = get_word(&pos, &value, parameter->value_count == 0
28285db3873SIngo Weinhold 				? ALLOW_ASSIGNMENT : IGNORE_ASSIGNMENT, false);
28385db3873SIngo Weinhold 			if (status < B_OK)
28485db3873SIngo Weinhold 				break;
28585db3873SIngo Weinhold 
28685db3873SIngo Weinhold 			// enlarge value array and save the value
28785db3873SIngo Weinhold 
28885db3873SIngo Weinhold 			newArray = (char**)realloc(parameter->values,
28985db3873SIngo Weinhold 				(parameter->value_count + 1) * sizeof(char *));
29085db3873SIngo Weinhold 			if (newArray == NULL)
29185db3873SIngo Weinhold 				return B_NO_MEMORY;
29285db3873SIngo Weinhold 
29385db3873SIngo Weinhold 			parameter->values = newArray;
29485db3873SIngo Weinhold 			parameter->values[parameter->value_count++] = value;
29585db3873SIngo Weinhold 		}
29685db3873SIngo Weinhold 	}
29785db3873SIngo Weinhold 
29885db3873SIngo Weinhold 	*_pos = pos;
29985db3873SIngo Weinhold 	return status;
30085db3873SIngo Weinhold }
30185db3873SIngo Weinhold 
30285db3873SIngo Weinhold 
30385db3873SIngo Weinhold static status_t
30485db3873SIngo Weinhold parse_parameters(struct driver_parameter **_parameters, int *_count,
30585db3873SIngo Weinhold 	char **_pos, int32 level)
30685db3873SIngo Weinhold {
30785db3873SIngo Weinhold 	if (level > MAX_SETTINGS_LEVEL)
30885db3873SIngo Weinhold 		return B_LINK_LIMIT;
30985db3873SIngo Weinhold 
31085db3873SIngo Weinhold 	while (true) {
31185db3873SIngo Weinhold 		struct driver_parameter parameter;
31285db3873SIngo Weinhold 		struct driver_parameter *newArray;
31385db3873SIngo Weinhold 		status_t status;
31485db3873SIngo Weinhold 
31585db3873SIngo Weinhold 		status = parse_parameter(&parameter, _pos, level);
31685db3873SIngo Weinhold 		if (status < B_OK)
31785db3873SIngo Weinhold 			return status;
31885db3873SIngo Weinhold 
31985db3873SIngo Weinhold 		if (status != NO_PARAMETER) {
32085db3873SIngo Weinhold 			driver_parameter *newParameter;
32185db3873SIngo Weinhold 
32285db3873SIngo Weinhold 			newArray = (driver_parameter*)realloc(*_parameters, (*_count + 1)
32385db3873SIngo Weinhold 				* sizeof(struct driver_parameter));
32485db3873SIngo Weinhold 			if (newArray == NULL)
32585db3873SIngo Weinhold 				return B_NO_MEMORY;
32685db3873SIngo Weinhold 
32785db3873SIngo Weinhold 			memcpy(&newArray[*_count], &parameter, sizeof(struct driver_parameter));
32885db3873SIngo Weinhold 			newParameter = &newArray[*_count];
32985db3873SIngo Weinhold 
33085db3873SIngo Weinhold 			*_parameters = newArray;
33185db3873SIngo Weinhold 			(*_count)++;
33285db3873SIngo Weinhold 
33385db3873SIngo Weinhold 			// check for level beginning and end
33485db3873SIngo Weinhold 			if (**_pos == '{') {
33585db3873SIngo Weinhold 				// if we go a level deeper, just start all over again...
33685db3873SIngo Weinhold 				(*_pos)++;
33785db3873SIngo Weinhold 				status = parse_parameters(&newParameter->parameters,
33885db3873SIngo Weinhold 							&newParameter->parameter_count, _pos, level + 1);
33985db3873SIngo Weinhold 				if (status < B_OK)
34085db3873SIngo Weinhold 					return status;
34185db3873SIngo Weinhold 			}
34285db3873SIngo Weinhold 		}
34385db3873SIngo Weinhold 
34485db3873SIngo Weinhold 		if ((**_pos == '}' && level > 0)
34585db3873SIngo Weinhold 			|| (**_pos == '\0' && level == 0)) {
34685db3873SIngo Weinhold 			// take the closing bracket from the stack
34785db3873SIngo Weinhold 			(*_pos)++;
34885db3873SIngo Weinhold 			return B_OK;
34985db3873SIngo Weinhold 		}
35085db3873SIngo Weinhold 
35185db3873SIngo Weinhold 		// obviously, something has gone wrong
35285db3873SIngo Weinhold 		if (**_pos == '}' || **_pos == '\0')
35385db3873SIngo Weinhold 			return B_ERROR;
35485db3873SIngo Weinhold 	}
35585db3873SIngo Weinhold }
35685db3873SIngo Weinhold 
35785db3873SIngo Weinhold 
35885db3873SIngo Weinhold static status_t
35985db3873SIngo Weinhold parse_settings(settings_handle *handle)
36085db3873SIngo Weinhold {
36185db3873SIngo Weinhold 	char *text = handle->text;
36285db3873SIngo Weinhold 
36385db3873SIngo Weinhold 	memset(&handle->settings, 0, sizeof(struct driver_settings));
36485db3873SIngo Weinhold 
36585db3873SIngo Weinhold 	// empty settings are allowed
36685db3873SIngo Weinhold 	if (text == NULL)
36785db3873SIngo Weinhold 		return B_OK;
36885db3873SIngo Weinhold 
36985db3873SIngo Weinhold 	return parse_parameters(&handle->settings.parameters,
37085db3873SIngo Weinhold 		&handle->settings.parameter_count, &text, 0);
37185db3873SIngo Weinhold }
37285db3873SIngo Weinhold 
37385db3873SIngo Weinhold 
37485db3873SIngo Weinhold static void
37585db3873SIngo Weinhold free_parameter(struct driver_parameter *parameter)
37685db3873SIngo Weinhold {
37785db3873SIngo Weinhold 	int32 i;
37885db3873SIngo Weinhold 	for (i = parameter->parameter_count; i-- > 0;)
37985db3873SIngo Weinhold 		free_parameter(&parameter->parameters[i]);
38085db3873SIngo Weinhold 
38185db3873SIngo Weinhold 	free(parameter->parameters);
38285db3873SIngo Weinhold 	free(parameter->values);
38385db3873SIngo Weinhold }
38485db3873SIngo Weinhold 
38585db3873SIngo Weinhold 
38685db3873SIngo Weinhold static void
38785db3873SIngo Weinhold free_settings(settings_handle *handle)
38885db3873SIngo Weinhold {
38985db3873SIngo Weinhold 	int32 i;
39085db3873SIngo Weinhold 	for (i = handle->settings.parameter_count; i-- > 0;)
39185db3873SIngo Weinhold 		free_parameter(&handle->settings.parameters[i]);
39285db3873SIngo Weinhold 
39385db3873SIngo Weinhold 	free(handle->settings.parameters);
39485db3873SIngo Weinhold 	free(handle->text);
39585db3873SIngo Weinhold 	free(handle);
39685db3873SIngo Weinhold }
39785db3873SIngo Weinhold 
39885db3873SIngo Weinhold 
39985db3873SIngo Weinhold static settings_handle *
40085db3873SIngo Weinhold new_settings(char *buffer, const char *driverName)
40185db3873SIngo Weinhold {
40285db3873SIngo Weinhold 	settings_handle *handle = (settings_handle*)malloc(sizeof(settings_handle));
40385db3873SIngo Weinhold 	if (handle == NULL)
40485db3873SIngo Weinhold 		return NULL;
40585db3873SIngo Weinhold 
40685db3873SIngo Weinhold 	handle->magic = SETTINGS_MAGIC;
40785db3873SIngo Weinhold 	handle->text = buffer;
40885db3873SIngo Weinhold 
40985db3873SIngo Weinhold #ifdef _KERNEL_MODE
41085db3873SIngo Weinhold 	handle->ref_count = 1;
41185db3873SIngo Weinhold 	strlcpy(handle->name, driverName, sizeof(handle->name));
41285db3873SIngo Weinhold #endif
41385db3873SIngo Weinhold 
41485db3873SIngo Weinhold 	if (parse_settings(handle) == B_OK)
41585db3873SIngo Weinhold 		return handle;
41685db3873SIngo Weinhold 
41785db3873SIngo Weinhold 	free(handle);
41885db3873SIngo Weinhold 	return NULL;
41985db3873SIngo Weinhold }
42085db3873SIngo Weinhold 
42185db3873SIngo Weinhold 
42285db3873SIngo Weinhold static settings_handle *
42385db3873SIngo Weinhold load_driver_settings_from_file(int file, const char *driverName)
42485db3873SIngo Weinhold {
42585db3873SIngo Weinhold 	struct stat stat;
42685db3873SIngo Weinhold 
42785db3873SIngo Weinhold 	// Allocate a buffer and read the whole file into it.
42885db3873SIngo Weinhold 	// We will keep this buffer in memory, until the settings
42985db3873SIngo Weinhold 	// are unloaded.
43085db3873SIngo Weinhold 	// The driver_parameter::name field will point directly
43185db3873SIngo Weinhold 	// to this buffer.
43285db3873SIngo Weinhold 
43385db3873SIngo Weinhold 	if (fstat(file, &stat) < B_OK)
43485db3873SIngo Weinhold 		return NULL;
43585db3873SIngo Weinhold 
43685db3873SIngo Weinhold 	if (stat.st_size > B_OK && stat.st_size < MAX_SETTINGS_SIZE) {
43785db3873SIngo Weinhold 		char *text = (char *)malloc(stat.st_size + 1);
43885db3873SIngo Weinhold 		if (text != NULL && read(file, text, stat.st_size) == stat.st_size) {
43985db3873SIngo Weinhold 			settings_handle *handle;
44085db3873SIngo Weinhold 
44185db3873SIngo Weinhold 			text[stat.st_size] = '\0';
44285db3873SIngo Weinhold 				// make sure the string is null terminated
44385db3873SIngo Weinhold 				// to avoid misbehaviour
44485db3873SIngo Weinhold 
44585db3873SIngo Weinhold 			handle = new_settings(text, driverName);
44685db3873SIngo Weinhold 			if (handle != NULL) {
44785db3873SIngo Weinhold 				// everything went fine!
44885db3873SIngo Weinhold 				return handle;
44985db3873SIngo Weinhold 			}
45085db3873SIngo Weinhold 
45185db3873SIngo Weinhold 			free(handle);
45285db3873SIngo Weinhold 		}
45385db3873SIngo Weinhold 		// "text" might be NULL here, but that's allowed
45485db3873SIngo Weinhold 		free(text);
45585db3873SIngo Weinhold 	}
45685db3873SIngo Weinhold 
45785db3873SIngo Weinhold 	return NULL;
45885db3873SIngo Weinhold }
45985db3873SIngo Weinhold 
46085db3873SIngo Weinhold 
46185db3873SIngo Weinhold static bool
46285db3873SIngo Weinhold put_string(char **_buffer, size_t *_bufferSize, char *string)
46385db3873SIngo Weinhold {
46485db3873SIngo Weinhold 	size_t length, reserved, quotes;
46585db3873SIngo Weinhold 	char *buffer = *_buffer, c;
46685db3873SIngo Weinhold 	bool quoted;
46785db3873SIngo Weinhold 
46885db3873SIngo Weinhold 	if (string == NULL)
46985db3873SIngo Weinhold 		return true;
47085db3873SIngo Weinhold 
47185db3873SIngo Weinhold 	for (length = reserved = quotes = 0; (c = string[length]) != '\0'; length++) {
47285db3873SIngo Weinhold 		if (c == '"')
47385db3873SIngo Weinhold 			quotes++;
47485db3873SIngo Weinhold 		else if (is_word_break(c))
47585db3873SIngo Weinhold 			reserved++;
47685db3873SIngo Weinhold 	}
47785db3873SIngo Weinhold 	quoted = reserved || quotes;
47885db3873SIngo Weinhold 
47985db3873SIngo Weinhold 	// update _bufferSize in any way, so that we can chain several
48085db3873SIngo Weinhold 	// of these calls without having to check the return value
48185db3873SIngo Weinhold 	// everytime
48285db3873SIngo Weinhold 	*_bufferSize -= length + (quoted ? 2 + quotes : 0);
48385db3873SIngo Weinhold 
48485db3873SIngo Weinhold 	if (*_bufferSize <= 0)
48585db3873SIngo Weinhold 		return false;
48685db3873SIngo Weinhold 
48785db3873SIngo Weinhold 	if (quoted)
48885db3873SIngo Weinhold 		*(buffer++) = '"';
48985db3873SIngo Weinhold 
49085db3873SIngo Weinhold 	for (;(c = string[0]) != '\0'; string++) {
49185db3873SIngo Weinhold 		if (c == '"')
49285db3873SIngo Weinhold 			*(buffer++) = '\\';
49385db3873SIngo Weinhold 
49485db3873SIngo Weinhold 		*(buffer++) = c;
49585db3873SIngo Weinhold 	}
49685db3873SIngo Weinhold 
49785db3873SIngo Weinhold 	if (quoted)
49885db3873SIngo Weinhold 		*(buffer++) = '"';
49985db3873SIngo Weinhold 
50085db3873SIngo Weinhold 	buffer[0] = '\0';
50185db3873SIngo Weinhold 
50285db3873SIngo Weinhold 	// update the buffer position
50385db3873SIngo Weinhold 	*_buffer = buffer;
50485db3873SIngo Weinhold 
50585db3873SIngo Weinhold 	return true;
50685db3873SIngo Weinhold }
50785db3873SIngo Weinhold 
50885db3873SIngo Weinhold 
50985db3873SIngo Weinhold static bool
51085db3873SIngo Weinhold put_chars(char **_buffer, size_t *_bufferSize, const char *chars)
51185db3873SIngo Weinhold {
51285db3873SIngo Weinhold 	char *buffer = *_buffer;
51385db3873SIngo Weinhold 	size_t length;
51485db3873SIngo Weinhold 
51585db3873SIngo Weinhold 	if (chars == NULL)
51685db3873SIngo Weinhold 		return true;
51785db3873SIngo Weinhold 
51885db3873SIngo Weinhold 	length = strlen(chars);
51985db3873SIngo Weinhold 	*_bufferSize -= length;
52085db3873SIngo Weinhold 
52185db3873SIngo Weinhold 	if (*_bufferSize <= 0)
52285db3873SIngo Weinhold 		return false;
52385db3873SIngo Weinhold 
52485db3873SIngo Weinhold 	memcpy(buffer, chars, length);
52585db3873SIngo Weinhold 	buffer += length;
52685db3873SIngo Weinhold 	buffer[0] = '\0';
52785db3873SIngo Weinhold 
52885db3873SIngo Weinhold 	// update the buffer position
52985db3873SIngo Weinhold 	*_buffer = buffer;
53085db3873SIngo Weinhold 
53185db3873SIngo Weinhold 	return true;
53285db3873SIngo Weinhold }
53385db3873SIngo Weinhold 
53485db3873SIngo Weinhold 
53585db3873SIngo Weinhold static bool
53685db3873SIngo Weinhold put_char(char **_buffer, size_t *_bufferSize, char c)
53785db3873SIngo Weinhold {
53885db3873SIngo Weinhold 	char *buffer = *_buffer;
53985db3873SIngo Weinhold 
54085db3873SIngo Weinhold 	*_bufferSize -= 1;
54185db3873SIngo Weinhold 
54285db3873SIngo Weinhold 	if (*_bufferSize <= 0)
54385db3873SIngo Weinhold 		return false;
54485db3873SIngo Weinhold 
54585db3873SIngo Weinhold 	buffer[0] = c;
54685db3873SIngo Weinhold 	buffer[1] = '\0';
54785db3873SIngo Weinhold 
54885db3873SIngo Weinhold 	// update the buffer position
54985db3873SIngo Weinhold 	*_buffer = buffer + 1;
55085db3873SIngo Weinhold 
55185db3873SIngo Weinhold 	return true;
55285db3873SIngo Weinhold }
55385db3873SIngo Weinhold 
55485db3873SIngo Weinhold 
55585db3873SIngo Weinhold static void
55685db3873SIngo Weinhold put_level_space(char **_buffer, size_t *_bufferSize, int32 level)
55785db3873SIngo Weinhold {
55885db3873SIngo Weinhold 	while (level-- > 0)
55985db3873SIngo Weinhold 		put_char(_buffer, _bufferSize, '\t');
56085db3873SIngo Weinhold }
56185db3873SIngo Weinhold 
56285db3873SIngo Weinhold 
563a5270963SIngo Weinhold static void
56485db3873SIngo Weinhold put_parameter(char **_buffer, size_t *_bufferSize,
56585db3873SIngo Weinhold 	struct driver_parameter *parameter, int32 level, bool flat)
56685db3873SIngo Weinhold {
56785db3873SIngo Weinhold 	int32 i;
56885db3873SIngo Weinhold 
56985db3873SIngo Weinhold 	if (!flat)
57085db3873SIngo Weinhold 		put_level_space(_buffer, _bufferSize, level);
57185db3873SIngo Weinhold 
57285db3873SIngo Weinhold 	put_string(_buffer, _bufferSize, parameter->name);
57385db3873SIngo Weinhold 	if (flat && parameter->value_count > 0)
57485db3873SIngo Weinhold 		put_chars(_buffer, _bufferSize, " =");
57585db3873SIngo Weinhold 
57685db3873SIngo Weinhold 	for (i = 0; i < parameter->value_count; i++) {
57785db3873SIngo Weinhold 		put_char(_buffer, _bufferSize, ' ');
57885db3873SIngo Weinhold 		put_string(_buffer, _bufferSize, parameter->values[i]);
57985db3873SIngo Weinhold 	}
58085db3873SIngo Weinhold 
58185db3873SIngo Weinhold 	if (parameter->parameter_count > 0) {
58285db3873SIngo Weinhold 		put_chars(_buffer, _bufferSize, " {");
58385db3873SIngo Weinhold 		if (!flat)
58485db3873SIngo Weinhold 			put_char(_buffer, _bufferSize, '\n');
58585db3873SIngo Weinhold 
58685db3873SIngo Weinhold 		for (i = 0; i < parameter->parameter_count; i++) {
58785db3873SIngo Weinhold 			put_parameter(_buffer, _bufferSize, &parameter->parameters[i],
58885db3873SIngo Weinhold 				level + 1, flat);
58985db3873SIngo Weinhold 
59085db3873SIngo Weinhold 			if (parameter->parameters[i].parameter_count == 0)
59185db3873SIngo Weinhold 				put_chars(_buffer, _bufferSize, flat ? "; " : "\n");
59285db3873SIngo Weinhold 		}
59385db3873SIngo Weinhold 
59485db3873SIngo Weinhold 		if (!flat)
59585db3873SIngo Weinhold 			put_level_space(_buffer, _bufferSize, level);
59685db3873SIngo Weinhold 		put_chars(_buffer, _bufferSize, flat ? "}" : "}\n");
59785db3873SIngo Weinhold 	}
59885db3873SIngo Weinhold }
59985db3873SIngo Weinhold 
60085db3873SIngo Weinhold 
60185db3873SIngo Weinhold //	#pragma mark - Kernel only functions
60285db3873SIngo Weinhold 
60385db3873SIngo Weinhold 
60485db3873SIngo Weinhold #ifdef _KERNEL_MODE
60585db3873SIngo Weinhold static settings_handle *
60685db3873SIngo Weinhold find_driver_settings(const char *name)
60785db3873SIngo Weinhold {
60885db3873SIngo Weinhold 	settings_handle *handle = NULL;
60985db3873SIngo Weinhold 
61085db3873SIngo Weinhold 	ASSERT_LOCKED_MUTEX(&sLock);
61185db3873SIngo Weinhold 
61285db3873SIngo Weinhold 	while ((handle = (settings_handle*)list_get_next_item(&sHandles, handle))
61385db3873SIngo Weinhold 			!= NULL) {
61485db3873SIngo Weinhold 		if (!strcmp(handle->name, name))
61585db3873SIngo Weinhold 			return handle;
61685db3873SIngo Weinhold 	}
61785db3873SIngo Weinhold 
61885db3873SIngo Weinhold 	return NULL;
61985db3873SIngo Weinhold }
62085db3873SIngo Weinhold 
62185db3873SIngo Weinhold 
62285db3873SIngo Weinhold status_t
62385db3873SIngo Weinhold driver_settings_init(kernel_args *args)
62485db3873SIngo Weinhold {
62585db3873SIngo Weinhold 	struct driver_settings_file *settings = args->driver_settings;
62685db3873SIngo Weinhold 
62785db3873SIngo Weinhold 	// Move the preloaded driver settings over to the kernel
62885db3873SIngo Weinhold 
62985db3873SIngo Weinhold 	list_init(&sHandles);
63085db3873SIngo Weinhold 
63185db3873SIngo Weinhold 	while (settings != NULL) {
63285db3873SIngo Weinhold 		settings_handle *handle
63385db3873SIngo Weinhold 			= (settings_handle*)malloc(sizeof(settings_handle));
63485db3873SIngo Weinhold 		if (handle == NULL)
63585db3873SIngo Weinhold 			return B_NO_MEMORY;
63685db3873SIngo Weinhold 
63785db3873SIngo Weinhold 		if (settings->size != 0) {
63885db3873SIngo Weinhold 			handle->text = (char*)malloc(settings->size + 1);
63985db3873SIngo Weinhold 			if (handle->text == NULL) {
64085db3873SIngo Weinhold 				free(handle);
64185db3873SIngo Weinhold 				return B_NO_MEMORY;
64285db3873SIngo Weinhold 			}
64385db3873SIngo Weinhold 
64485db3873SIngo Weinhold 			memcpy(handle->text, settings->buffer, settings->size);
64585db3873SIngo Weinhold 			handle->text[settings->size] = '\0';
64685db3873SIngo Weinhold 				// null terminate the buffer
64785db3873SIngo Weinhold 		} else
64885db3873SIngo Weinhold 			handle->text = NULL;
64985db3873SIngo Weinhold 
65085db3873SIngo Weinhold 		strlcpy(handle->name, settings->name, sizeof(handle->name));
65185db3873SIngo Weinhold 		handle->settings.parameters = NULL;
65285db3873SIngo Weinhold 		handle->settings.parameter_count = 0;
65385db3873SIngo Weinhold 		handle->magic = 0;
65485db3873SIngo Weinhold 			// this triggers parsing the settings when they are actually used
65585db3873SIngo Weinhold 
65685db3873SIngo Weinhold 		if (!strcmp(handle->name, B_SAFEMODE_DRIVER_SETTINGS)) {
65785db3873SIngo Weinhold 			// These settings cannot be reloaded, so we better don't throw
65885db3873SIngo Weinhold 			// them away.
65985db3873SIngo Weinhold 			handle->ref_count = 1;
66085db3873SIngo Weinhold 		} else
66185db3873SIngo Weinhold 			handle->ref_count = 0;
66285db3873SIngo Weinhold 
66385db3873SIngo Weinhold 		list_add_item(&sHandles, handle);
66485db3873SIngo Weinhold 
66585db3873SIngo Weinhold 		settings = settings->next;
66685db3873SIngo Weinhold 	}
66785db3873SIngo Weinhold 
66885db3873SIngo Weinhold 	return B_OK;
66985db3873SIngo Weinhold }
67085db3873SIngo Weinhold #endif
67185db3873SIngo Weinhold 
67285db3873SIngo Weinhold 
67385db3873SIngo Weinhold //	#pragma mark - public API
67485db3873SIngo Weinhold 
67585db3873SIngo Weinhold 
67685db3873SIngo Weinhold status_t
67785db3873SIngo Weinhold unload_driver_settings(void *_handle)
67885db3873SIngo Weinhold {
67985db3873SIngo Weinhold 	settings_handle *handle = (settings_handle *)_handle;
68085db3873SIngo Weinhold 	if (!check_handle(handle))
68185db3873SIngo Weinhold 		return B_BAD_VALUE;
68285db3873SIngo Weinhold 
68385db3873SIngo Weinhold #ifdef _KERNEL_MODE
68485db3873SIngo Weinhold 	mutex_lock(&sLock);
68585db3873SIngo Weinhold 	if (--handle->ref_count == 0 && gBootDevice > 0) {
68685db3873SIngo Weinhold 		// don't unload an handle when /boot is not available
68785db3873SIngo Weinhold 		list_remove_link(&handle->link);
68885db3873SIngo Weinhold 	} else
68985db3873SIngo Weinhold 		handle = NULL;
69085db3873SIngo Weinhold 	mutex_unlock(&sLock);
69185db3873SIngo Weinhold #endif
69285db3873SIngo Weinhold 
69385db3873SIngo Weinhold 	if (handle != NULL)
69485db3873SIngo Weinhold 		free_settings(handle);
69585db3873SIngo Weinhold 
69685db3873SIngo Weinhold 	return B_OK;
69785db3873SIngo Weinhold }
69885db3873SIngo Weinhold 
69985db3873SIngo Weinhold 
70085db3873SIngo Weinhold void *
70185db3873SIngo Weinhold load_driver_settings(const char *driverName)
70285db3873SIngo Weinhold {
70385db3873SIngo Weinhold 	settings_handle *handle;
70485db3873SIngo Weinhold 	int file = -1;
70585db3873SIngo Weinhold 
70685db3873SIngo Weinhold 	if (driverName == NULL)
70785db3873SIngo Weinhold 		return NULL;
70885db3873SIngo Weinhold 
70985db3873SIngo Weinhold #ifdef _KERNEL_MODE
71085db3873SIngo Weinhold 	// see if we already have these settings loaded
71185db3873SIngo Weinhold 	mutex_lock(&sLock);
71285db3873SIngo Weinhold 	handle = find_driver_settings(driverName);
71385db3873SIngo Weinhold 	if (handle != NULL && handle->ref_count == 0 && gBootDevice > 0) {
71485db3873SIngo Weinhold 		// A handle with a zero ref_count should be unloaded if /boot is
71585db3873SIngo Weinhold 		// available.
71685db3873SIngo Weinhold 		list_remove_link(&handle->link);
71785db3873SIngo Weinhold 		free_settings(handle);
71885db3873SIngo Weinhold 	} else if (handle != NULL) {
71985db3873SIngo Weinhold 		handle->ref_count++;
72085db3873SIngo Weinhold 
72185db3873SIngo Weinhold 		// we got it, now let's see if it already has been parsed
72285db3873SIngo Weinhold 		if (handle->magic != SETTINGS_MAGIC) {
72385db3873SIngo Weinhold 			handle->magic = SETTINGS_MAGIC;
72485db3873SIngo Weinhold 
72585db3873SIngo Weinhold 			if (parse_settings(handle) != B_OK) {
72685db3873SIngo Weinhold 				// no valid settings, let's cut down its memory requirements
72785db3873SIngo Weinhold 				free(handle->text);
72885db3873SIngo Weinhold 				handle->text = NULL;
72985db3873SIngo Weinhold 				handle = NULL;
73085db3873SIngo Weinhold 			}
73185db3873SIngo Weinhold 		}
73285db3873SIngo Weinhold 		mutex_unlock(&sLock);
73385db3873SIngo Weinhold 		return handle;
73485db3873SIngo Weinhold 	}
73585db3873SIngo Weinhold 
73685db3873SIngo Weinhold 	// we are allowed to call the driver settings pretty early in the boot process
73785db3873SIngo Weinhold 	if (gKernelStartup) {
73885db3873SIngo Weinhold 		mutex_unlock(&sLock);
73985db3873SIngo Weinhold 		return NULL;
74085db3873SIngo Weinhold 	}
74185db3873SIngo Weinhold #endif	// _KERNEL_MODE
74285db3873SIngo Weinhold #ifdef _BOOT_MODE
74385db3873SIngo Weinhold 	// see if we already have these settings loaded
74485db3873SIngo Weinhold 	{
74585db3873SIngo Weinhold 		struct driver_settings_file *settings = gKernelArgs.driver_settings;
74685db3873SIngo Weinhold 		while (settings != NULL) {
74785db3873SIngo Weinhold 			if (!strcmp(settings->name, driverName)) {
74885db3873SIngo Weinhold 				// we have it - since the buffer is clobbered, we have to
74985db3873SIngo Weinhold 				// copy its contents, though
75085db3873SIngo Weinhold 				char *text = (char*)malloc(settings->size + 1);
75185db3873SIngo Weinhold 				if (text == NULL)
75285db3873SIngo Weinhold 					return NULL;
75385db3873SIngo Weinhold 
75485db3873SIngo Weinhold 				memcpy(text, settings->buffer, settings->size + 1);
75585db3873SIngo Weinhold 				return new_settings(text, driverName);
75685db3873SIngo Weinhold 			}
75785db3873SIngo Weinhold 			settings = settings->next;
75885db3873SIngo Weinhold 		}
75985db3873SIngo Weinhold 	}
76085db3873SIngo Weinhold #endif	// _BOOT_MODE
76185db3873SIngo Weinhold 
76285db3873SIngo Weinhold 	// open the settings from the standardized location
76385db3873SIngo Weinhold 	if (driverName[0] != '/') {
76485db3873SIngo Weinhold 		char path[B_FILE_NAME_LENGTH + 64];
76585db3873SIngo Weinhold 
76685db3873SIngo Weinhold #ifdef _BOOT_MODE
767323b6546SOliver Tappe 		strcpy(path, kUserSettingsDirectory);
76885db3873SIngo Weinhold #else
76985db3873SIngo Weinhold 		// TODO: use B_COMMON_SETTINGS_DIRECTORY instead!
77085db3873SIngo Weinhold 		if (find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, path,
77185db3873SIngo Weinhold 				sizeof(path)) == B_OK)
77285db3873SIngo Weinhold #endif
77385db3873SIngo Weinhold 		{
77485db3873SIngo Weinhold 			strlcat(path, SETTINGS_DIRECTORY, sizeof(path));
77585db3873SIngo Weinhold 			strlcat(path, driverName, sizeof(path));
77685db3873SIngo Weinhold 		}
77785db3873SIngo Weinhold 
77885db3873SIngo Weinhold 		file = open(path, O_RDONLY);
77985db3873SIngo Weinhold 	} else
78085db3873SIngo Weinhold 		file = open(driverName, O_RDONLY);
78185db3873SIngo Weinhold 
78285db3873SIngo Weinhold 	if (file < B_OK) {
78385db3873SIngo Weinhold #ifdef _KERNEL_MODE
78485db3873SIngo Weinhold 		mutex_unlock(&sLock);
78585db3873SIngo Weinhold #endif
78685db3873SIngo Weinhold 		return NULL;
78785db3873SIngo Weinhold 	}
78885db3873SIngo Weinhold 
78985db3873SIngo Weinhold 	handle = load_driver_settings_from_file(file, driverName);
79085db3873SIngo Weinhold 
79185db3873SIngo Weinhold #ifdef _KERNEL_MODE
79285db3873SIngo Weinhold 	if (handle != NULL)
79385db3873SIngo Weinhold 		list_add_item(&sHandles, handle);
79485db3873SIngo Weinhold 	mutex_unlock(&sLock);
79585db3873SIngo Weinhold #endif
79685db3873SIngo Weinhold 
79785db3873SIngo Weinhold 	close(file);
79885db3873SIngo Weinhold 	return (void *)handle;
79985db3873SIngo Weinhold }
80085db3873SIngo Weinhold 
80185db3873SIngo Weinhold 
80285db3873SIngo Weinhold /** Loads a driver settings file using the full path, instead of
80385db3873SIngo Weinhold  *	only defining the leaf name (as load_driver_settings() does).
80485db3873SIngo Weinhold  *	I am not sure if this function is really necessary - I would
80585db3873SIngo Weinhold  *	probably prefer something like a search order (if it's not
80685db3873SIngo Weinhold  *	an absolute path):
80785db3873SIngo Weinhold  *		~/config/settings/kernel/driver
80885db3873SIngo Weinhold  *		current directory
80985db3873SIngo Weinhold  *	That would render this function useless.
81085db3873SIngo Weinhold  */
81185db3873SIngo Weinhold 
81285db3873SIngo Weinhold #if 0
81385db3873SIngo Weinhold void *
81485db3873SIngo Weinhold load_driver_settings_from_path(const char *path)
81585db3873SIngo Weinhold {
81685db3873SIngo Weinhold 	settings_handle *handle;
81785db3873SIngo Weinhold 	int file;
81885db3873SIngo Weinhold 
81985db3873SIngo Weinhold 	if (path == NULL)
82085db3873SIngo Weinhold 		return NULL;
82185db3873SIngo Weinhold 
82285db3873SIngo Weinhold 	file = open(path, O_RDONLY);
82385db3873SIngo Weinhold 	if (file < B_OK)
82485db3873SIngo Weinhold 		return NULL;
82585db3873SIngo Weinhold 
82685db3873SIngo Weinhold 	handle = load_driver_settings_from_file(file);
82785db3873SIngo Weinhold 
82885db3873SIngo Weinhold 	close(file);
82985db3873SIngo Weinhold 	return (void *)handle;
83085db3873SIngo Weinhold }
83185db3873SIngo Weinhold #endif
83285db3873SIngo Weinhold 
83385db3873SIngo Weinhold 
83485db3873SIngo Weinhold /*!
83585db3873SIngo Weinhold 	Returns a new driver_settings handle that has the parsed contents
83685db3873SIngo Weinhold 	of the passed string.
83785db3873SIngo Weinhold 	You can get an empty driver_settings object when you pass NULL as
83885db3873SIngo Weinhold 	the "settingsString" parameter.
83985db3873SIngo Weinhold */
84085db3873SIngo Weinhold void *
84185db3873SIngo Weinhold parse_driver_settings_string(const char *settingsString)
84285db3873SIngo Weinhold {
84385db3873SIngo Weinhold 	// we simply copy the whole string to use it as our internal buffer
84485db3873SIngo Weinhold 	char *text = strdup(settingsString);
84585db3873SIngo Weinhold 	if (settingsString == NULL || text != NULL) {
84685db3873SIngo Weinhold 		settings_handle *handle
84785db3873SIngo Weinhold 			= (settings_handle*)malloc(sizeof(settings_handle));
84885db3873SIngo Weinhold 		if (handle != NULL) {
84985db3873SIngo Weinhold 			handle->magic = SETTINGS_MAGIC;
85085db3873SIngo Weinhold 			handle->text = text;
85185db3873SIngo Weinhold 
85285db3873SIngo Weinhold 			if (parse_settings(handle) == B_OK)
85385db3873SIngo Weinhold 				return handle;
85485db3873SIngo Weinhold 
85585db3873SIngo Weinhold 			free(handle);
85685db3873SIngo Weinhold 		}
85785db3873SIngo Weinhold 		free(text);
85885db3873SIngo Weinhold 	}
85985db3873SIngo Weinhold 
86085db3873SIngo Weinhold 	return NULL;
86185db3873SIngo Weinhold }
86285db3873SIngo Weinhold 
86385db3873SIngo Weinhold 
86485db3873SIngo Weinhold /*!
86585db3873SIngo Weinhold 	This function prints out a driver settings structure to a human
86685db3873SIngo Weinhold 	readable string.
86785db3873SIngo Weinhold 	It's either in standard style or the single line style speficied
86885db3873SIngo Weinhold 	by the "flat" parameter.
86985db3873SIngo Weinhold 	If the buffer is too small to hold the string, B_BUFFER_OVERFLOW
87085db3873SIngo Weinhold 	is returned, and the needed amount of bytes if placed in the
87185db3873SIngo Weinhold 	"_bufferSize" parameter.
87285db3873SIngo Weinhold 	If the "handle" parameter is not a valid driver settings handle, or
87385db3873SIngo Weinhold 	the "buffer" parameter is NULL, B_BAD_VALUE is returned.
87485db3873SIngo Weinhold */
87585db3873SIngo Weinhold status_t
87685db3873SIngo Weinhold get_driver_settings_string(void *_handle, char *buffer, size_t *_bufferSize,
87785db3873SIngo Weinhold 	bool flat)
87885db3873SIngo Weinhold {
87985db3873SIngo Weinhold 	settings_handle *handle = (settings_handle *)_handle;
88085db3873SIngo Weinhold 	size_t bufferSize = *_bufferSize;
88185db3873SIngo Weinhold 	int32 i;
88285db3873SIngo Weinhold 
88385db3873SIngo Weinhold 	if (!check_handle(handle) || !buffer || *_bufferSize == 0)
88485db3873SIngo Weinhold 		return B_BAD_VALUE;
88585db3873SIngo Weinhold 
88685db3873SIngo Weinhold 	for (i = 0; i < handle->settings.parameter_count; i++) {
88785db3873SIngo Weinhold 		put_parameter(&buffer, &bufferSize, &handle->settings.parameters[i],
88885db3873SIngo Weinhold 			0, flat);
88985db3873SIngo Weinhold 	}
89085db3873SIngo Weinhold 
89185db3873SIngo Weinhold 	*_bufferSize -= bufferSize;
89285db3873SIngo Weinhold 	return bufferSize >= 0 ? B_OK : B_BUFFER_OVERFLOW;
89385db3873SIngo Weinhold }
89485db3873SIngo Weinhold 
89585db3873SIngo Weinhold 
89685db3873SIngo Weinhold /*!
89785db3873SIngo Weinhold 	Matches the first value of the parameter matching "keyName" with a set
89885db3873SIngo Weinhold 	of boolean values like 1/true/yes/on/enabled/...
89985db3873SIngo Weinhold 	Returns "unknownValue" if the parameter could not be found or doesn't
90085db3873SIngo Weinhold 	have any valid boolean setting, and "noArgValue" if the parameter
90185db3873SIngo Weinhold 	doesn't have any values.
90285db3873SIngo Weinhold 	Also returns "unknownValue" if the handle passed in was not valid.
90385db3873SIngo Weinhold */
90485db3873SIngo Weinhold bool
90585db3873SIngo Weinhold get_driver_boolean_parameter(void *_handle, const char *keyName,
90685db3873SIngo Weinhold 	bool unknownValue, bool noArgValue)
90785db3873SIngo Weinhold {
90885db3873SIngo Weinhold 	settings_handle *handle = (settings_handle*)_handle;
90985db3873SIngo Weinhold 	driver_parameter *parameter;
91085db3873SIngo Weinhold 	char *boolean;
91185db3873SIngo Weinhold 
91285db3873SIngo Weinhold 	if (!check_handle(handle))
91385db3873SIngo Weinhold 		return unknownValue;
91485db3873SIngo Weinhold 
91585db3873SIngo Weinhold 	// check for the parameter
91685db3873SIngo Weinhold 	if ((parameter = get_parameter(handle, keyName)) == NULL)
91785db3873SIngo Weinhold 		return unknownValue;
91885db3873SIngo Weinhold 
91985db3873SIngo Weinhold 	// check for the argument
92085db3873SIngo Weinhold 	if (parameter->value_count <= 0)
92185db3873SIngo Weinhold 		return noArgValue;
92285db3873SIngo Weinhold 
92385db3873SIngo Weinhold 	boolean = parameter->values[0];
92485db3873SIngo Weinhold 	if (!strcmp(boolean, "1")
92585db3873SIngo Weinhold 		|| !strcasecmp(boolean, "true")
92685db3873SIngo Weinhold 		|| !strcasecmp(boolean, "yes")
92785db3873SIngo Weinhold 		|| !strcasecmp(boolean, "on")
92885db3873SIngo Weinhold 		|| !strcasecmp(boolean, "enable")
92985db3873SIngo Weinhold 		|| !strcasecmp(boolean, "enabled"))
93085db3873SIngo Weinhold 		return true;
93185db3873SIngo Weinhold 
93285db3873SIngo Weinhold 	if (!strcmp(boolean, "0")
93385db3873SIngo Weinhold 		|| !strcasecmp(boolean, "false")
93485db3873SIngo Weinhold 		|| !strcasecmp(boolean, "no")
93585db3873SIngo Weinhold 		|| !strcasecmp(boolean, "off")
93685db3873SIngo Weinhold 		|| !strcasecmp(boolean, "disable")
93785db3873SIngo Weinhold 		|| !strcasecmp(boolean, "disabled"))
93885db3873SIngo Weinhold 		return false;
93985db3873SIngo Weinhold 
94085db3873SIngo Weinhold 	// if no known keyword is found, "unknownValue" is returned
94185db3873SIngo Weinhold 	return unknownValue;
94285db3873SIngo Weinhold }
94385db3873SIngo Weinhold 
94485db3873SIngo Weinhold 
94585db3873SIngo Weinhold const char *
94685db3873SIngo Weinhold get_driver_parameter(void *_handle, const char *keyName,
94785db3873SIngo Weinhold 	const char *unknownValue, const char *noArgValue)
94885db3873SIngo Weinhold {
94985db3873SIngo Weinhold 	settings_handle* handle = (settings_handle*)_handle;
95085db3873SIngo Weinhold 	struct driver_parameter *parameter;
95185db3873SIngo Weinhold 
95285db3873SIngo Weinhold 	if (!check_handle(handle))
95385db3873SIngo Weinhold 		return unknownValue;
95485db3873SIngo Weinhold 
95585db3873SIngo Weinhold 	// check for the parameter
95685db3873SIngo Weinhold 	if ((parameter = get_parameter(handle, keyName)) == NULL)
95785db3873SIngo Weinhold 		return unknownValue;
95885db3873SIngo Weinhold 
95985db3873SIngo Weinhold 	// check for the argument
96085db3873SIngo Weinhold 	if (parameter->value_count <= 0)
96185db3873SIngo Weinhold 		return noArgValue;
96285db3873SIngo Weinhold 
96385db3873SIngo Weinhold 	return parameter->values[0];
96485db3873SIngo Weinhold }
96585db3873SIngo Weinhold 
96685db3873SIngo Weinhold 
96785db3873SIngo Weinhold const driver_settings *
96885db3873SIngo Weinhold get_driver_settings(void *handle)
96985db3873SIngo Weinhold {
97085db3873SIngo Weinhold 	if (!check_handle((settings_handle*)handle))
97185db3873SIngo Weinhold 		return NULL;
97285db3873SIngo Weinhold 
97385db3873SIngo Weinhold 	return &((settings_handle *)handle)->settings;
97485db3873SIngo Weinhold }
97585db3873SIngo Weinhold 
97685db3873SIngo Weinhold 
97785db3873SIngo Weinhold // this creates an alias of the above function
97885db3873SIngo Weinhold // unload_driver_settings() is the same as delete_driver_settings()
97985db3873SIngo Weinhold extern "C" __typeof(unload_driver_settings) delete_driver_settings
98085db3873SIngo Weinhold 	__attribute__((alias ("unload_driver_settings")));
98185db3873SIngo Weinhold 
982