1/*
2	Generic device list for use in drivers.
3	Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
4	Distributed under the terms of the MIT license.
5*/
6#include "DeviceList.h"
7#include <util/kernel_cpp.h>
8#include <stdlib.h>
9#include <string.h>
10#include <new>
11
12struct device_list_entry {
13	char *				name;
14	void *				device;
15	device_list_entry *	next;
16};
17
18
19DeviceList::DeviceList()
20	:	fDeviceList(NULL),
21		fDeviceCount(0),
22		fPublishList(NULL)
23{
24}
25
26
27DeviceList::~DeviceList()
28{
29	_FreePublishList();
30
31	device_list_entry *current = fDeviceList;
32	while (current) {
33		device_list_entry *next = current->next;
34		free(current->name);
35		delete current;
36		current = next;
37	}
38}
39
40
41status_t
42DeviceList::AddDevice(const char *name, void *device)
43{
44	device_list_entry *entry = new(std::nothrow) device_list_entry;
45	if (entry == NULL)
46		return B_NO_MEMORY;
47
48	entry->name = strdup(name);
49	if (entry->name == NULL) {
50		delete entry;
51		return B_NO_MEMORY;
52	}
53
54	entry->device = device;
55	entry->next = NULL;
56
57	if (fDeviceList == NULL)
58		fDeviceList = entry;
59	else {
60		device_list_entry *current = fDeviceList;
61		while (current) {
62			if (current->next == NULL) {
63				current->next = entry;
64				break;
65			}
66
67			current = current->next;
68		}
69	}
70
71	fDeviceCount++;
72	return B_OK;
73}
74
75
76status_t
77DeviceList::RemoveDevice(const char *name, void *device)
78{
79	if (name == NULL && device == NULL)
80		return B_BAD_VALUE;
81
82	device_list_entry *previous = NULL;
83	device_list_entry *current = fDeviceList;
84	while (current) {
85		if ((name != NULL && strcmp(current->name, name) == 0)
86			|| (device != NULL && current->device == device)) {
87			if (previous == NULL)
88				fDeviceList = current->next;
89			else
90				previous->next = current->next;
91
92			free(current->name);
93			delete current;
94			fDeviceCount--;
95			return B_OK;
96		}
97
98		previous = current;
99		current = current->next;
100	}
101
102	return B_ENTRY_NOT_FOUND;
103}
104
105
106void *
107DeviceList::FindDevice(const char *name, void *device)
108{
109	if (name == NULL && device == NULL)
110		return NULL;
111
112	device_list_entry *current = fDeviceList;
113	while (current) {
114		if ((name != NULL && strcmp(current->name, name) == 0)
115			|| (device != NULL && current->device == device))
116			return current->device;
117
118		current = current->next;
119	}
120
121	return NULL;
122}
123
124
125int32
126DeviceList::CountDevices(const char *baseName)
127{
128	if (baseName == NULL)
129		return fDeviceCount;
130
131	int32 count = 0;
132	int32 baseNameLength = strlen(baseName);
133	device_list_entry *current = fDeviceList;
134	while (current) {
135		if (strncmp(current->name, baseName, baseNameLength) == 0)
136			count++;
137
138		current = current->next;
139	}
140
141	return count;
142}
143
144
145void *
146DeviceList::DeviceAt(int32 index)
147{
148	device_list_entry *current = fDeviceList;
149	while (current) {
150		if (index-- == 0)
151			return current->device;
152
153		current = current->next;
154	}
155
156	return NULL;
157}
158
159
160const char **
161DeviceList::PublishDevices()
162{
163	_FreePublishList();
164
165	fPublishList = (char **)malloc((fDeviceCount + 1) * sizeof(char *));
166	if (fPublishList == NULL)
167		return NULL;
168
169	int32 index = 0;
170	device_list_entry *current = fDeviceList;
171	while (current) {
172		fPublishList[index++] = strdup(current->name);
173		current = current->next;
174	}
175
176	fPublishList[index] = NULL;
177	return (const char **)fPublishList;
178}
179
180
181void
182DeviceList::_FreePublishList()
183{
184	if (fPublishList == NULL)
185		return;
186
187	int32 index = 0;
188	while (fPublishList[index] != NULL) {
189		free(fPublishList[index]);
190		index++;
191	}
192
193	free(fPublishList);
194	fPublishList = NULL;
195}
196