2004-02-24 00:41:20 +01:00
|
|
|
/* the Music Player Daemon (MPD)
|
2006-07-14 21:37:45 +02:00
|
|
|
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
|
2004-02-24 00:41:20 +01:00
|
|
|
* This project's homepage is: http://www.musicpd.org
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "list.h"
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
2006-07-14 21:13:51 +02:00
|
|
|
static void makeListNodesArray(List * list) {
|
2004-02-24 00:41:20 +01:00
|
|
|
ListNode * node = list->firstNode;
|
|
|
|
long i;
|
|
|
|
|
2004-11-15 18:24:57 +01:00
|
|
|
if(!list->numberOfNodes) return;
|
|
|
|
|
2004-11-15 19:35:23 +01:00
|
|
|
list->nodesArray = realloc(list->nodesArray,
|
|
|
|
sizeof(ListNode *)*list->numberOfNodes);
|
2004-02-24 00:41:20 +01:00
|
|
|
|
|
|
|
for(i=0;i<list->numberOfNodes;i++) {
|
|
|
|
list->nodesArray[i] = node;
|
|
|
|
node = node->nextNode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-14 21:13:51 +02:00
|
|
|
static void freeListNodesArray(List * list) {
|
2004-11-15 18:24:57 +01:00
|
|
|
if(!list->nodesArray) return;
|
2004-02-24 00:41:20 +01:00
|
|
|
free(list->nodesArray);
|
|
|
|
list->nodesArray = NULL;
|
|
|
|
}
|
|
|
|
|
2004-11-11 03:59:16 +01:00
|
|
|
List * makeList(ListFreeDataFunc * freeDataFunc, int strdupKeys) {
|
2004-02-24 00:41:20 +01:00
|
|
|
List * list = malloc(sizeof(List));
|
|
|
|
|
|
|
|
assert(list!=NULL);
|
|
|
|
|
2006-03-16 07:41:48 +01:00
|
|
|
list->sorted = 0;
|
2004-02-24 00:41:20 +01:00
|
|
|
list->firstNode = NULL;
|
|
|
|
list->lastNode = NULL;
|
|
|
|
list->freeDataFunc = freeDataFunc;
|
|
|
|
list->numberOfNodes = 0;
|
|
|
|
list->nodesArray = NULL;
|
2004-11-11 03:59:16 +01:00
|
|
|
list->strdupKeys = strdupKeys;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2004-11-15 20:29:20 +01:00
|
|
|
ListNode * insertInListBeforeNode(List * list, ListNode * beforeNode, int pos, char * key, void * data)
|
2004-04-10 04:55:27 +02:00
|
|
|
{
|
|
|
|
ListNode * node;
|
|
|
|
|
|
|
|
assert(list!=NULL);
|
|
|
|
assert(key!=NULL);
|
|
|
|
/*assert(data!=NULL);*/
|
|
|
|
|
|
|
|
node = malloc(sizeof(ListNode));
|
|
|
|
assert(node!=NULL);
|
|
|
|
|
2004-11-15 19:35:23 +01:00
|
|
|
node->nextNode = beforeNode;
|
|
|
|
if(beforeNode==list->firstNode) {
|
|
|
|
if(list->firstNode==NULL) {
|
|
|
|
assert(list->lastNode==NULL);
|
|
|
|
list->lastNode = node;
|
2004-04-10 04:55:27 +02:00
|
|
|
}
|
|
|
|
else {
|
2004-11-15 19:35:23 +01:00
|
|
|
assert(list->lastNode!=NULL);
|
|
|
|
assert(list->lastNode->nextNode==NULL);
|
|
|
|
list->firstNode->prevNode = node;
|
|
|
|
}
|
|
|
|
node->prevNode = NULL;
|
|
|
|
list->firstNode = node;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(beforeNode) {
|
2004-11-15 18:24:57 +01:00
|
|
|
node->prevNode = beforeNode->prevNode;
|
|
|
|
beforeNode->prevNode = node;
|
2004-04-11 02:52:05 +02:00
|
|
|
}
|
2004-11-15 19:35:23 +01:00
|
|
|
else {
|
|
|
|
node->prevNode = list->lastNode;
|
|
|
|
list->lastNode = node;
|
|
|
|
}
|
|
|
|
node->prevNode->nextNode = node;
|
|
|
|
}
|
2004-11-11 03:59:16 +01:00
|
|
|
|
2004-11-15 19:35:23 +01:00
|
|
|
if(list->strdupKeys) node->key = strdup(key);
|
|
|
|
else node->key = key;
|
2004-11-11 03:59:16 +01:00
|
|
|
|
2004-11-15 19:35:23 +01:00
|
|
|
node->data = data;
|
2004-04-10 04:55:27 +02:00
|
|
|
|
2004-11-15 19:35:23 +01:00
|
|
|
list->numberOfNodes++;
|
2004-11-15 18:24:57 +01:00
|
|
|
|
2004-11-15 20:29:20 +01:00
|
|
|
if(list->sorted) {
|
|
|
|
list->nodesArray = realloc(list->nodesArray,
|
|
|
|
list->numberOfNodes*sizeof(ListNode *));
|
|
|
|
if(node == list->lastNode) {
|
|
|
|
list->nodesArray[list->numberOfNodes-1] = node;
|
|
|
|
}
|
|
|
|
else if(pos < 0) makeListNodesArray(list);
|
|
|
|
else {
|
|
|
|
memmove(list->nodesArray+pos+1, list->nodesArray+pos,
|
|
|
|
sizeof(ListNode *)*
|
|
|
|
(list->numberOfNodes-pos-1));
|
|
|
|
list->nodesArray[pos] = node;
|
|
|
|
}
|
|
|
|
}
|
2004-11-15 18:24:57 +01:00
|
|
|
|
|
|
|
return node;
|
2004-04-10 04:55:27 +02:00
|
|
|
}
|
|
|
|
|
2004-11-11 03:59:16 +01:00
|
|
|
ListNode * insertInList(List * list, char * key, void * data) {
|
2004-02-24 00:41:20 +01:00
|
|
|
ListNode * node;
|
|
|
|
|
|
|
|
assert(list!=NULL);
|
|
|
|
assert(key!=NULL);
|
|
|
|
/*assert(data!=NULL);*/
|
|
|
|
|
|
|
|
node = malloc(sizeof(ListNode));
|
|
|
|
assert(node!=NULL);
|
|
|
|
|
|
|
|
if(list->nodesArray) freeListNodesArray(list);
|
|
|
|
|
|
|
|
if(list->firstNode==NULL) {
|
|
|
|
assert(list->lastNode==NULL);
|
|
|
|
list->firstNode = node;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
assert(list->lastNode!=NULL);
|
|
|
|
assert(list->lastNode->nextNode==NULL);
|
|
|
|
list->lastNode->nextNode = node;
|
|
|
|
}
|
2004-11-11 03:59:16 +01:00
|
|
|
|
|
|
|
if(list->strdupKeys) node->key = strdup(key);
|
|
|
|
else node->key = key;
|
|
|
|
|
2004-02-24 00:41:20 +01:00
|
|
|
node->data = data;
|
|
|
|
node->nextNode = NULL;
|
|
|
|
node->prevNode = list->lastNode;
|
|
|
|
|
|
|
|
list->lastNode = node;
|
|
|
|
|
|
|
|
list->numberOfNodes++;
|
|
|
|
|
2004-11-10 22:58:27 +01:00
|
|
|
return node;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int insertInListWithoutKey(List * list, void * data) {
|
|
|
|
ListNode * node;
|
|
|
|
|
|
|
|
assert(list!=NULL);
|
|
|
|
assert(data!=NULL);
|
|
|
|
|
|
|
|
node = malloc(sizeof(ListNode));
|
|
|
|
assert(node!=NULL);
|
|
|
|
|
|
|
|
if(list->nodesArray) freeListNodesArray(list);
|
|
|
|
|
|
|
|
if(list->firstNode==NULL) {
|
|
|
|
assert(list->lastNode==NULL);
|
|
|
|
list->firstNode = node;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
assert(list->lastNode!=NULL);
|
|
|
|
assert(list->lastNode->nextNode==NULL);
|
|
|
|
list->lastNode->nextNode = node;
|
|
|
|
}
|
|
|
|
|
|
|
|
node->key = NULL;
|
|
|
|
node->data = data;
|
|
|
|
node->nextNode = NULL;
|
|
|
|
node->prevNode = list->lastNode;
|
|
|
|
|
|
|
|
list->lastNode = node;
|
|
|
|
|
|
|
|
list->numberOfNodes++;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-07-14 21:13:51 +02:00
|
|
|
/* if _key_ is not found, *_node_ is assigned to the node before which
|
|
|
|
the info would be found */
|
2006-07-16 18:50:54 +02:00
|
|
|
int findNodeInList(List * list, char * key, ListNode ** node, int * pos) {
|
2004-11-15 20:29:20 +01:00
|
|
|
long high;
|
|
|
|
long low;
|
|
|
|
long cur;
|
|
|
|
ListNode * tmpNode;
|
|
|
|
int cmp;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
|
|
|
assert(list!=NULL);
|
|
|
|
|
2004-11-15 18:24:57 +01:00
|
|
|
if(list->sorted && list->nodesArray) {
|
2004-02-24 00:41:20 +01:00
|
|
|
high = list->numberOfNodes-1;
|
|
|
|
low = 0;
|
|
|
|
cur = high;
|
|
|
|
|
|
|
|
while(high>low) {
|
|
|
|
cur = (high+low)/2;
|
|
|
|
tmpNode = list->nodesArray[cur];
|
|
|
|
cmp = strcmp(tmpNode->key,key);
|
2004-11-15 18:24:57 +01:00
|
|
|
if(cmp==0) {
|
|
|
|
*node = tmpNode;
|
2004-11-15 20:29:20 +01:00
|
|
|
*pos = cur;
|
2004-11-15 18:24:57 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2004-02-24 00:41:20 +01:00
|
|
|
else if(cmp>0) high = cur;
|
|
|
|
else {
|
|
|
|
if(low==cur) break;
|
|
|
|
low = cur;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cur = high;
|
|
|
|
if(cur>=0) {
|
|
|
|
tmpNode = list->nodesArray[cur];
|
2004-11-15 18:24:57 +01:00
|
|
|
*node = tmpNode;
|
2004-11-15 20:29:20 +01:00
|
|
|
*pos = high;
|
|
|
|
cmp = tmpNode ? strcmp(tmpNode->key,key) : -1;
|
2004-11-15 18:24:57 +01:00
|
|
|
if( 0 == cmp ) return 1;
|
2004-11-15 18:40:48 +01:00
|
|
|
else if( cmp > 0) return 0;
|
2004-11-15 18:24:57 +01:00
|
|
|
else {
|
2004-11-15 20:29:20 +01:00
|
|
|
*pos = -1;
|
2004-11-15 18:24:57 +01:00
|
|
|
*node = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2004-11-15 20:29:20 +01:00
|
|
|
*pos = 0;
|
2004-11-15 18:24:57 +01:00
|
|
|
*node = list->firstNode;
|
|
|
|
return 0;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
tmpNode = list->firstNode;
|
|
|
|
|
|
|
|
while(tmpNode!=NULL && strcmp(tmpNode->key,key)!=0) {
|
|
|
|
tmpNode = tmpNode->nextNode;
|
|
|
|
}
|
|
|
|
|
2004-11-15 18:24:57 +01:00
|
|
|
*node = tmpNode;
|
|
|
|
if(tmpNode) return 1;
|
2004-11-10 22:58:27 +01:00
|
|
|
}
|
|
|
|
|
2004-11-15 18:24:57 +01:00
|
|
|
return 0;
|
2004-11-10 22:58:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int findInList(List * list, char * key, void ** data) {
|
2004-11-15 18:24:57 +01:00
|
|
|
ListNode * node;
|
2004-11-15 20:29:20 +01:00
|
|
|
int pos;
|
2004-11-10 22:58:27 +01:00
|
|
|
|
2004-11-15 20:29:20 +01:00
|
|
|
if(findNodeInList(list, key, &node, &pos)) {
|
2004-11-10 22:58:27 +01:00
|
|
|
if(data) *data = node->data;
|
|
|
|
return 1;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int deleteFromList(List * list,char * key) {
|
|
|
|
ListNode * tmpNode;
|
|
|
|
|
|
|
|
assert(list!=NULL);
|
|
|
|
|
|
|
|
tmpNode = list->firstNode;
|
|
|
|
|
|
|
|
while(tmpNode!=NULL && strcmp(tmpNode->key,key)!=0) {
|
|
|
|
tmpNode = tmpNode->nextNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(tmpNode!=NULL)
|
|
|
|
deleteNodeFromList(list,tmpNode);
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void deleteNodeFromList(List * list,ListNode * node) {
|
|
|
|
assert(list!=NULL);
|
|
|
|
assert(node!=NULL);
|
|
|
|
|
|
|
|
if(node->prevNode==NULL) {
|
|
|
|
list->firstNode = node->nextNode;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
node->prevNode->nextNode = node->nextNode;
|
|
|
|
}
|
|
|
|
if(node->nextNode==NULL) {
|
|
|
|
list->lastNode = node->prevNode;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
node->nextNode->prevNode = node->prevNode;
|
|
|
|
}
|
|
|
|
if(list->freeDataFunc) {
|
|
|
|
list->freeDataFunc(node->data);
|
|
|
|
}
|
2004-11-11 03:59:16 +01:00
|
|
|
|
|
|
|
if(list->strdupKeys) free(node->key);
|
2004-02-24 00:41:20 +01:00
|
|
|
free(node);
|
|
|
|
list->numberOfNodes--;
|
|
|
|
|
|
|
|
if(list->nodesArray) {
|
|
|
|
freeListNodesArray(list);
|
2004-11-15 18:24:57 +01:00
|
|
|
if(list->sorted) makeListNodesArray(list);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void freeList(void * list) {
|
|
|
|
ListNode * tmpNode;
|
|
|
|
ListNode * tmpNode2;
|
|
|
|
|
|
|
|
assert(list!=NULL);
|
|
|
|
|
|
|
|
tmpNode = ((List *)list)->firstNode;
|
|
|
|
|
|
|
|
if(((List *)list)->nodesArray) free(((List *)list)->nodesArray);
|
|
|
|
|
|
|
|
while(tmpNode!=NULL) {
|
|
|
|
tmpNode2 = tmpNode->nextNode;
|
2004-11-11 03:59:16 +01:00
|
|
|
if(((List *)list)->strdupKeys) free(tmpNode->key);
|
2004-02-24 00:41:20 +01:00
|
|
|
if(((List *)list)->freeDataFunc) {
|
|
|
|
((List *)list)->freeDataFunc(tmpNode->data);
|
|
|
|
}
|
|
|
|
free(tmpNode);
|
|
|
|
tmpNode = tmpNode2;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(list);
|
|
|
|
}
|
|
|
|
|
2006-07-14 21:13:51 +02:00
|
|
|
static void swapNodes(ListNode * nodeA, ListNode * nodeB) {
|
2004-02-24 00:41:20 +01:00
|
|
|
char * key;
|
|
|
|
void * data;
|
|
|
|
|
|
|
|
assert(nodeA!=NULL);
|
|
|
|
assert(nodeB!=NULL);
|
|
|
|
|
|
|
|
key = nodeB->key;
|
|
|
|
data = nodeB->data;
|
|
|
|
|
|
|
|
nodeB->key = nodeA->key;
|
|
|
|
nodeB->data = nodeA->data;
|
|
|
|
|
|
|
|
nodeA->key = key;
|
|
|
|
nodeA->data = data;
|
|
|
|
}
|
|
|
|
|
2006-07-14 21:13:51 +02:00
|
|
|
static void bubbleSort(ListNode ** nodesArray, long start, long end) {
|
2004-02-24 00:41:20 +01:00
|
|
|
long i;
|
|
|
|
long j;
|
|
|
|
ListNode * node;
|
|
|
|
|
|
|
|
if(start>=end) return;
|
|
|
|
|
|
|
|
for(j=start;j<end;j++) {
|
|
|
|
for(i=end-1;i>=start;i--) {
|
|
|
|
node = nodesArray[i];
|
|
|
|
if(strcmp(node->key,node->nextNode->key)>0) {
|
|
|
|
swapNodes(node,node->nextNode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-14 21:13:51 +02:00
|
|
|
static void quickSort(ListNode ** nodesArray, long start, long end) {
|
2004-02-24 00:41:20 +01:00
|
|
|
if(start>=end) return;
|
|
|
|
else if(end-start<5) bubbleSort(nodesArray,start,end);
|
|
|
|
else {
|
|
|
|
long i;
|
|
|
|
ListNode * node;
|
|
|
|
long pivot;
|
|
|
|
ListNode * pivotNode;
|
|
|
|
char * pivotKey;
|
|
|
|
|
2004-11-11 03:59:16 +01:00
|
|
|
List * startList = makeList(free, 0);
|
|
|
|
List * endList = makeList(free, 0);
|
2004-02-24 00:41:20 +01:00
|
|
|
long * startPtr = malloc(sizeof(long));
|
|
|
|
long * endPtr = malloc(sizeof(long));
|
|
|
|
*startPtr = start;
|
|
|
|
*endPtr = end;
|
|
|
|
insertInListWithoutKey(startList,(void *)startPtr);
|
|
|
|
insertInListWithoutKey(endList,(void *)endPtr);
|
|
|
|
|
|
|
|
while(startList->numberOfNodes) {
|
|
|
|
start = *((long *)startList->lastNode->data);
|
|
|
|
end = *((long *)endList->lastNode->data);
|
|
|
|
|
|
|
|
if(end-start<5) {
|
|
|
|
bubbleSort(nodesArray,start,end);
|
|
|
|
deleteNodeFromList(startList,startList->lastNode);
|
|
|
|
deleteNodeFromList(endList,endList->lastNode);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pivot = (start+end)/2;
|
|
|
|
pivotNode = nodesArray[pivot];
|
|
|
|
pivotKey = pivotNode->key;
|
|
|
|
|
|
|
|
for(i=pivot-1;i>=start;i--) {
|
|
|
|
node = nodesArray[i];
|
|
|
|
if(strcmp(node->key,pivotKey)>0) {
|
|
|
|
pivot--;
|
|
|
|
if(pivot>i) {
|
|
|
|
swapNodes(node,nodesArray[pivot]);
|
|
|
|
}
|
|
|
|
swapNodes(pivotNode,nodesArray[pivot]);
|
|
|
|
pivotNode = nodesArray[pivot];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for(i=pivot+1;i<=end;i++) {
|
|
|
|
node = nodesArray[i];
|
|
|
|
if(strcmp(pivotKey,node->key)>0) {
|
|
|
|
pivot++;
|
|
|
|
if(pivot<i) {
|
|
|
|
swapNodes(node,nodesArray[pivot]);
|
|
|
|
}
|
|
|
|
swapNodes(pivotNode,nodesArray[pivot]);
|
|
|
|
pivotNode = nodesArray[pivot];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
deleteNodeFromList(startList,startList->lastNode);
|
|
|
|
deleteNodeFromList(endList,endList->lastNode);
|
|
|
|
|
|
|
|
if(pivot-1-start>0) {
|
|
|
|
startPtr = malloc(sizeof(long));
|
|
|
|
endPtr = malloc(sizeof(long));
|
|
|
|
*startPtr = start;
|
|
|
|
*endPtr = pivot-1;
|
|
|
|
insertInListWithoutKey(startList,(void *)startPtr);
|
|
|
|
insertInListWithoutKey(endList,(void *)endPtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(end-pivot-1>0) {
|
|
|
|
startPtr = malloc(sizeof(long));
|
|
|
|
endPtr = malloc(sizeof(long));
|
|
|
|
*startPtr = pivot+1;
|
|
|
|
*endPtr = end;
|
|
|
|
insertInListWithoutKey(startList,(void *)startPtr);
|
|
|
|
insertInListWithoutKey(endList,(void *)endPtr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
freeList(startList);
|
|
|
|
freeList(endList);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void sortList(List * list) {
|
|
|
|
assert(list!=NULL);
|
|
|
|
|
2004-11-15 18:24:57 +01:00
|
|
|
list->sorted = 1;
|
|
|
|
|
2004-02-24 00:41:20 +01:00
|
|
|
if(list->numberOfNodes<2) return;
|
|
|
|
|
|
|
|
if(list->nodesArray) freeListNodesArray(list);
|
|
|
|
makeListNodesArray(list);
|
|
|
|
|
|
|
|
quickSort(list->nodesArray,0,list->numberOfNodes-1);
|
|
|
|
}
|