/*************************************************************************
Copyright © 1999-2002 Novell, Inc. All Rights Reserved. 

THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND 
TREATIES. USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE
AGREEMENT ACCOMPANYING THE SOFTWARE DEVELOPMENT KIT (SDK) THAT CONTAINS
THIS WORK. PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS
TO DEVELOPER A ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S
SAMPLE CODE IN ITS PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION
RIGHTS TO MARKET, DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT
OF DEVELOPER'S PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR
DEVELOPER'S CUSTOMERS WITH RESPECT TO THIS CODE.

***************************************************************************/
/*******************************************************************
* Name: somain.cpp
* Description: Unix-specific file for CSkeletonDriver
* Tabs: 4
*******************************************************************/


#include	<stdlib.h>
#include	<semaphore.h>
#include	<string.h>
#include	<errno.h>
#include	<time.h>
#include	"CSkeletonDriver.h"
#include	"SkeletonPublisher.h"
#include	"UTFConverter.h"
#include	"wcsfunc.h"

//time to sleep waiting for a semaphore in milliseconds
static const int	SLEEP_TIME = 50;
//++
//=========================================================================
// Purpose:
//		DirXML entry point for driver.
// Notes:
//		DirXML calls this function to get a driver instance.
//		This is the only function that MUST be exported from the module,
//		subject to platform considerations.
//=========================================================================
extern "C" DriverShim *
CreateDriver(void)
//--
{
	return new CSkeletonDriver();
}

//++
//=========================================================================
// Purpose:
//		Platform-specific code to create a semaphore.
// Notes:
//		Support for SkeletonPublisher
//=========================================================================
SEMAPHORE_HANDLE
SkeletonPublisher::createSemaphore()
//--
{
	sem_t	* gate = new sem_t;
	sem_init(gate,0,1);

	return (SEMAPHORE_HANDLE)gate;
}

//++
//=========================================================================
// Purpose:
//		Platform-specific code to wait on a semaphore (with timeout)
// Notes:
//		Support for SkeletonPublisher
//=========================================================================
void
SkeletonPublisher::waitSemaphore(
	SEMAPHORE_HANDLE semaphore,
	int timeoutInMilliseconds)
//--
{
	
	int	err;
	if (timeoutInMilliseconds == -1)
	{
		retry:
		//wait forever
		if ((err = sem_wait((sem_t *)semaphore)) == -1)
		{
			if (errno == EINTR)
			{
				goto retry;
			}
		}
	} else
	{
		struct timespec tDelay;
		int spinCount = timeoutInMilliseconds / SLEEP_TIME;
		do
		{
			if ((err = sem_trywait((sem_t *)semaphore)) != 0)
			{
				//50 milliseconds
				tDelay.tv_sec = 0;
				tDelay.tv_nsec = SLEEP_TIME * 1000 * 1000;
				nanosleep(&tDelay, NULL);
			}
			else
			{
				spinCount = 1;
			}
		} while (--spinCount > 0);
		
	}
}

//++
//=========================================================================
// Purpose:
//		Platform-specific code to signal a semaphore
// Notes:
//		Support for SkeletonPublisher
//=========================================================================
void
SkeletonPublisher::signalSemaphore(
	SEMAPHORE_HANDLE semaphore)
//--
{
	sem_post((sem_t *)semaphore);
}

//++
//=========================================================================
// Purpose:
//		Platform-specific code to destroy a semaphore created by
//		SkeletonPublisher::createSemaphore()
// Notes:
//		Support for SkeletonPublisher
//=========================================================================
void
SkeletonPublisher::destroySemaphore(
	SEMAPHORE_HANDLE semaphore)
//--
{
	sem_destroy((sem_t *)semaphore);
	delete	(sem_t *)semaphore;
}

//various UTF-16 functions needed  
size_t ustrlen(
	const unicode *ustr)
{
	size_t i = 0;
	while (*ustr) {i++; ustr++;}
	return i;
}

unicode *
ustrcat(
	unicode *udstr,
	const unicode *usstr)
{
	unicode *odst = udstr;
	while (*udstr) udstr++; 		/* get to end of string */
	while (*udstr++ = *usstr++);	/* copy source string */
	return odst;
}

unicode *
ustrcpy(
	unicode *udstr,
	const unicode *usstr)
{
	return (unicode *)memcpy(udstr, usstr, (ustrlen(usstr) + 1)*2);
}


int
ustrcmp(
	const unicode *ustr1,
	const unicode *ustr2)
{
	while (*ustr1 == *ustr2 && *ustr1)
	{
		ustr1++;
		ustr2++;
	}
	return *ustr1 - *ustr2;
}

unsigned long
ustrtoul(const unicode * s, const unicode ** ep, int base)
{
	char * utf8 = UTFConverter_16to8(s);
	char * end;
	unsigned long result = strtoul(utf8,&end,base);
	int offset = end - utf8;
	UTFConverter_free(utf8);
	*ep = s + offset;
	return	result;
}

int
ustricmp(const unicode * s1, const unicode * s2)
{
	char * utf81 = UTFConverter_16to8(s1);
	char * utf82 = UTFConverter_16to8(s2);
	int result = strcasecmp(utf81,utf82);
	UTFConverter_free(utf82);
	UTFConverter_free(utf81);
	return	result;
}
