⛏️ index : haiku.git

/*
	Generic device list for use in drivers.
	Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
	Distributed under the terms of the MIT license.
*/
#include "DeviceList.h"
#include <util/kernel_cpp.h>
#include <stdlib.h>
#include <string.h>
#include <new>

struct device_list_entry {
	char *				name;
	void *				device;
	device_list_entry *	next;
};


DeviceList::DeviceList()
	:	fDeviceList(NULL),
		fDeviceCount(0),
		fPublishList(NULL)
{
}


DeviceList::~DeviceList()
{
	_FreePublishList();

	device_list_entry *current = fDeviceList;
	while (current) {
		device_list_entry *next = current->next;
		free(current->name);
		delete current;
		current = next;
	}
}


status_t
DeviceList::AddDevice(const char *name, void *device)
{
	device_list_entry *entry = new(std::nothrow) device_list_entry;
	if (entry == NULL)
		return B_NO_MEMORY;

	entry->name = strdup(name);
	if (entry->name == NULL) {
		delete entry;
		return B_NO_MEMORY;
	}

	entry->device = device;
	entry->next = NULL;

	if (fDeviceList == NULL)
		fDeviceList = entry;
	else {
		device_list_entry *current = fDeviceList;
		while (current) {
			if (current->next == NULL) {
				current->next = entry;
				break;
			}

			current = current->next;
		}
	}

	fDeviceCount++;
	return B_OK;
}


status_t
DeviceList::RemoveDevice(const char *name, void *device)
{
	if (name == NULL && device == NULL)
		return B_BAD_VALUE;

	device_list_entry *previous = NULL;
	device_list_entry *current = fDeviceList;
	while (current) {
		if ((name != NULL && strcmp(current->name, name) == 0)
			|| (device != NULL && current->device == device)) {
			if (previous == NULL)
				fDeviceList = current->next;
			else
				previous->next = current->next;

			free(current->name);
			delete current;
			fDeviceCount--;
			return B_OK;
		}

		previous = current;
		current = current->next;
	}

	return B_ENTRY_NOT_FOUND;
}


void *
DeviceList::FindDevice(const char *name, void *device)
{
	if (name == NULL && device == NULL)
		return NULL;

	device_list_entry *current = fDeviceList;
	while (current) {
		if ((name != NULL && strcmp(current->name, name) == 0)
			|| (device != NULL && current->device == device))
			return current->device;

		current = current->next;
	}

	return NULL;
}


int32
DeviceList::CountDevices(const char *baseName)
{
	if (baseName == NULL)
		return fDeviceCount;

	int32 count = 0;
	int32 baseNameLength = strlen(baseName);
	device_list_entry *current = fDeviceList;
	while (current) {
		if (strncmp(current->name, baseName, baseNameLength) == 0)
			count++;

		current = current->next;
	}

	return count;
}


void *
DeviceList::DeviceAt(int32 index)
{
	device_list_entry *current = fDeviceList;
	while (current) {
		if (index-- == 0)
			return current->device;

		current = current->next;
	}

	return NULL;
}


const char **
DeviceList::PublishDevices()
{
	_FreePublishList();

	fPublishList = (char **)malloc((fDeviceCount + 1) * sizeof(char *));
	if (fPublishList == NULL)
		return NULL;

	int32 index = 0;
	device_list_entry *current = fDeviceList;
	while (current) {
		fPublishList[index++] = strdup(current->name);
		current = current->next;
	}

	fPublishList[index] = NULL;
	return (const char **)fPublishList;
}


void
DeviceList::_FreePublishList()
{
	if (fPublishList == NULL)
		return;

	int32 index = 0;
	while (fPublishList[index] != NULL) {
		free(fPublishList[index]);
		index++;
	}

	free(fPublishList);
	fPublishList = NULL;
}