//-------------------------------------------------------------------
//	gambler.cpp
//
//	This program acts as a lottery-player client, using a shared
//	memory-segment to check the validity of a number-choice bet. 
//	Our server program (named 'lottery.cpp') needs to be running 
//	as a separate process.  Here a player is prompted to type in  
//	a 4-digit bet, which will be compared to the current winning
//	number, which is accessible through a shared memory-segment.
//	The program-pair illustrates the use of a UNIX semaphore-set 
//	to appropriately coordinate access by the writer and reader.
//	
//	Our lottery-and-gambler program-pair was inspired by a time-
//	server example in "Understanding UNIX/Linux Programming" by
//	Bruce Molay (Prentice-Hall, 2003), pp. 506-514. 
//
//	programmer: ALLAN CRUSE
//	written on: 13 OCT 2004
//-------------------------------------------------------------------

#include <stdio.h>	// for printf(), perror() 
#include <stdlib.h>	// for exit() 
#include <string.h>	// for strncmp()
#include <sys/shm.h>	// for shmget(), shmctl(), shmat(), etc
#include <sys/sem.h>	// for semget(), semctl(), semop(), etc
#include "myshmsem.h"	// for MY_MEM_KEY, MY_SEM_KEY, MEM_SIZE


int 	semset_id;	// holds handle to the semaphore set
int 	shmseg_id;	// holds handle to the shared memory
void	*shm_buffer;	// our pointer to the memory segment


void wait_and_lock( int semset_id )
{
	struct sembuf	actions[2];

	// wait for 0 on n_writers
	actions[0].sem_num = 1;
	actions[0].sem_flg = SEM_UNDO;
	actions[0].sem_op = 0;

	// then increment n_readers
	actions[1].sem_num = 0;
	actions[1].sem_flg = SEM_UNDO;
	actions[1].sem_op = +1;

	if ( semop( semset_id, actions, 2 ) < 0 )
		{ perror( "semop" ); exit(1); }
}






void release_lock( int semset_id )
{
	struct sembuf	actions[1];

	// decrement n_readers
	actions[0].sem_num = 0;
	actions[0].sem_flg = SEM_UNDO;
	actions[0].sem_op = -1;

	if ( semop( semset_id, actions, 1 ) < 0 )
		{ perror( "semop" ); exit(1); }
}


int main( int argc, char **argv )
{
	// create a shared memory segment
	shmseg_id = shmget( MY_MEM_KEY, MEM_SIZE, 0666 );
	if ( shmseg_id < 0 ) { perror( "shmget" ); exit(1); }

	// attach to it and obtain its address
	shm_buffer = shmat( shmseg_id, NULL, 0 );
	printf( "shm_buffer=%p \n", shm_buffer );

	// connect to semaphore-set with 2 semaphores
	semset_id = semget( MY_SEM_KEY, 2, 0 );
	if ( semset_id < 0 ) { perror( "semget" ); exit(1); }

	// prompt the player for lottery number choices
	printf( "\nType in your 4-digit bet: " );
	fflush( stdout );

	// obtain the player's bet
	char	mybet[ 5 ];
	scanf( "%4s", mybet );
	printf( "\nMy bet is %s \n", mybet );
	
	// read from shared memory contents to determine win/lose
	int	won;
	wait_and_lock( semset_id );
	printf( "current winning number is %s\n", shm_buffer );
	won = ( strncmp( (char*)shm_buffer, mybet, 4 ) == 0 );
	release_lock( semset_id );

	// detach this process from the shared memory segment
	shmdt( shm_buffer );

	// report lottery result to the player
	if ( won ) printf( "You win!\n" );
	else	printf( "You lose\n" );
}