/*******************************/
/*   sem_gen.c by IoDream      */
/* sem_server general function */
/*   Not released yet          */
/*       PUBLIC DOMAIN         */
/*******************************/

/* IoDream (IoDream@ifrance.com) */

/* C++ compilers friendly */
#ifdef __cplusplus
extern "C" {
#endif /*__cplusplus*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h> /* for strncmp, strlen */
#include "sem_gen.h"
#include "sem_debug.h"
#include "j_net.h" /* for j_net_read_* and j_net_write_all */

char *sem_req_txt[SEM_REQ_LAST] = {"CREATE", "DESTROY", "WAIT", "RELEASE", "RESET"};

/* Interface for j_net_read_max (look in j_net.h). */
ssize_t read_max(int fd, const void *dest, size_t len)
{
	return(j_net_read_max(fd, dest, len));
}

/* Interface for j_net_read_all (look in j_net.h). */
ssize_t read_all(int fd, const void *dest, size_t len)
{
	return(j_net_read_all(fd, dest, len));
}

/* Interface for j_net_write_all (look in j_net.h). */
ssize_t write_all(int fd, const void *source, size_t len)
{
	return(j_net_write_all(fd, source, len));
}


/* Lock the mutex fd (created by pipe). */
void lock_mutex(int fd[2])
{
	char temp;

	DEBUG_(printf("sem_gen-:  locking mutex\n");)
	if (read_all(fd[0], (void *) &temp, 1) < 0)
	{
		perror("lock_mutex-:  read_all()");
		exit(1);
	}
	DEBUG_(printf("sem_gen-:  out of locking mutex\n");)

	return;
}

/* Unlock the mutex fd (created by pipe). */
void unlock_mutex(int fd[2])
{
	char temp = 'l';

	DEBUG_(printf("sem_gen-:  unlocking mutex\n");)
	if (write_all(fd[1], (void *) &temp, 1) < 0)
	{
		perror("unlock_mutex-:  write_all()");
		exit(1);
	}
	DEBUG_(printf("sem_gen-:  out of unlocking mutex\n");)

	return;
}

/* Find the first item in the string *p_str_item, items are delimited by one or more chars.
   Return a pointer to it (in p_str) and its length (function return), a pointer to the next item (in *p_str_next). */
int next_item(char **p_str_item, char **p_str_next, char delim)
{
	int len = 0;

	if ((p_str_item == NULL) || (*p_str_item == NULL) || (p_str_next == NULL))
		return(0);

	/* Suppress leading delim chars */
	while ((**p_str_item == delim) && (**p_str_item != '\0'))
		++(*p_str_item);
	/* Calculate length */
	if (**p_str_item == '\0')
		return(0);
	*p_str_next = *p_str_item;
	while ((**p_str_next != delim) && (**p_str_next != '\0'))
		++(*p_str_next);
	len = (int) (*p_str_next - *p_str_item);
	/* Put p_str_next at the next item */
	while ((**p_str_next == delim) && (**p_str_next != '\0'))
		++(*p_str_next);

	return(len);
}

/* Parse the request string req and fill in id and pid.
   Return the order of the request (see enum sem_request), or -1 in case of failure.
   Note: if pid is NULL, no pid will be seeked. */
int parse_request(char *req, int *id, pid_t *pid)
{
	int len, i;
	char *item = req;
	char *p_aux;

	if ((len = next_item(&item, &p_aux, ' ')) == 0)
		return(-1);
	for (i = 0; i < SEM_REQ_LAST; ++i)
		if (strncmp(item, sem_req_txt[i], strlen(sem_req_txt[i])) == 0)
			break;
	if (i == SEM_REQ_LAST)
		return(-1);

	if (i < SEM_REQ_RESET)
	{
		item = p_aux;
		if ((len = next_item(&item, &p_aux, ' ')) == 0)
			return(-1);
		*id = atoi(item);
		if ((i == SEM_REQ_WAIT) && (pid != NULL))
		{
			item = p_aux;
			if ((len = next_item(&item, &p_aux, ' ')) == 0)
				return(-1);
			*pid = (pid_t) atoi(item);
			if (*pid == 0)
				return(-1);
		}
	}
	return(i);
}

/* C++ compilers friendly */
#ifdef __cplusplus
}
#endif /*__cplusplus*/
