/* Copyright (C) Boris Nikolaus, Germany, 1996-1997. All rights reserved. */
/* Copyright (C) Microsoft Corporation, 1997-1998. All rights reserved. */

#include "precomp.h"

/* get length of a singly linked list */
size_t SLlength(void *head, size_t offset)
{
    size_t nelem = 0;

    while (head) {
	/*LINTED*/
    	head = *(void **)((char *)head + offset);
	nelem++;
    }
    return nelem;
}

/* search for an element in a singly linked list */
int SLcontains(void *head, size_t offset, void *elem)
{
    while (head) {
	if (head == elem)
	    return 1;
	/*LINTED pointer cast may result in improper alignment*/
	head = *(void **)((char *)head + offset);
    }
    return 0;
}

/* copy elements of a singly linked list into an array */
void SLtoA(void *head, size_t offset, size_t elemsize, void **base, size_t *nelem)
{
    void *p;

    *nelem = SLlength(head, offset);
    if (!*nelem) {
    	*base = NULL;
	return;
    }
    p = *base = malloc(*nelem * elemsize);
    /*LINTED*/
    for (; head; head = *(void **)((char *)head + offset)) {
    	memcpy(p, head, elemsize);
	p = (void *)((char *)p + elemsize);
    }
}

/* copy pointers to elements of a singly linked list into an array */
void SLtoAP(void *head, size_t offset, void ***base, size_t *nelem)
{
    void **p;

    *nelem = SLlength(head, offset);
    if (!*nelem) {
    	*base = NULL;
	return;
    }
    p = *base = (void **)malloc(*nelem * sizeof(void *));
    /*LINTED*/
    for (; head; head = *(void **)((char *)head + offset)) {
    	*p++ = head;
    }
}

/* copy elements of an array into a singly linked list */
void AtoSL(void *base, size_t offset, size_t nelem, size_t elemsize, void **head)
{
    while (nelem--) {
    	*head = malloc(elemsize);
	memcpy(*head, base, elemsize);
	base = (void *)((char *)base + elemsize);
	/*LINTED*/
	head = (void **)((char *)*head + offset);
    }
    *head = NULL;
}

/* user defined compare function of qsortSL */
static int (*qsortSL_CmpFnCb)(const void *, const void *, void *);
static void *qsortSL_Context;

/* compare function of qsortSL */
static int __cdecl qsortSL_CmpFn(const void *p1, const void *p2)
{
    return qsortSL_CmpFnCb(*(void **)p1, *(void **)p2, qsortSL_Context);
}

/* sort a singly linked list */
void qsortSL(void **head, size_t offset, int (*cmpfn)(const void *, const void *, void *), void *context)
{
    void **base, **p;
    size_t nelem;

    SLtoAP(*head, offset, &base, &nelem);
    qsortSL_CmpFnCb = cmpfn;
    qsortSL_Context = context;
    qsort(base, nelem, sizeof(void *), qsortSL_CmpFn);
    p = base;
    while (nelem--) {
    	*head = *p++;
	/*LINTED*/
	head = (void **)((char *)*head + offset);
    }
    *head = NULL;
    free(base);
}