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