// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (C) 1993, 1994  Microsoft Corporation. All rights
// Reserved.
//
//  MODULE:  factlc.c
//
//  PURPOSE: RPC factorial program that demonstrates the use of the following:
//
//           a) Auto handles. There is not need to specify server names
//              or to write RPC client code to deal with binding and 
//              handles.The RPC stubs defines the handle and manages the
//              binding.
//           b) RPC Server/Client dynamic allocation of memory. The use
//              of reference pointers to pass arbitrary amounts and types
//              of data is shown.
//
//  FUNCTIONS:             
//    main                  - Main client procedure
//    ComputeFactorial      - Does remote procedure call
//    MIDL_user_allocate    - Allocates memory on the server address space
//    MIDL_user_free        - Deallocates memory on the server address space
//
//  COMMENTS:
//

#include <stdio.h>
#include <stdlib.h>

#include <rpc.h>
#include "factl.h"
#include "globals.h"


short status = 0;               // to save return code information 
unsigned char szN[BUF_SIZE]; 
unsigned char *pszResult;
unsigned char **ppszTmp;

void ComputeFactorial(char * szFactl);

void main(void)
{
    BOOL bDone = FALSE;

    printf("\n\nWelcome to the RPC factorial program\n\n");

    do 
    {
        printf("\n\nEnter integer to compute factorial ==> ");
        if ((gets(szN) != NULL) && (*szN != '\0') && (atol(szN) > 0) )
            ComputeFactorial(szN);
        printf("\n\nDo you want to stop computing factorials (y/n) ==> ");
        if ((gets(szN) != NULL) && (*szN == 'y'))
        {
            bDone = TRUE;    
        }                          
    } while (!bDone);    

    
    printf("\n\nDo you want to shutdown server RPC factorial provider (y/n) ==> ");
    if ((gets(szN) != NULL) && (*szN == 'y')) 
    {
        printf("\n\nThank you for using this program. Bye, bye now...\n\n");
        Shutdown();
    }

    exit(0);
}


//
//  FUNCTION: ComputeFactorial(char * szFactl)
//
//  PURPOSE: Calls RPC factl() procedure and handles error conditions.
//
//  PARAMETERS:
//    
//    szFactl     - pointer to ascii string contain interger to compute factorial
//  
//  RETURN VALUE:
// 
//    none.
//
//  COMMENTS:
//

void ComputeFactorial(char * szFactl)
{   
    RpcTryExcept
    {

#if defined(FACTL_DEBUG)
        printf("\nCalling remote fact() funtion with argument %s...\n",szFactl);
#endif
        pszResult = NULL;
        ppszTmp = &pszResult;
        status = factl(szFactl, ppszTmp);
        
        if (status == -1) 
        {
            printf("\nThe value you entered is invalid. "
                   "Valid numbers are integers from 1 to 12.\n");
        }
        else
        {
            printf("\nThe factorial of %s is %s.\n",szFactl, pszResult);
        }

        // free memory allocated by client stub

        midl_user_free(pszResult);


    }
    RpcExcept (TRUE)
    {
        printf("The call to factl() remote procedure failed.\n");
        printf("RPC error code %d.\n",RpcExceptionCode());
        exit(1);
    }
    RpcEndExcept;

}


//
//  FUNCTION: MIDL_user_allocate(size_t len)
//
//  PURPOSE: Client stub calls this function to allocate memory when
//           remote procedure receives parameters from server application.
//
//  PARAMETERS:
//    
//    len     - number of bytes to allocate
//  
//  RETURN VALUE:
// 
//    Returns pointer to allocated memory
//
//  COMMENTS:
//

void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len)
{

#if defined(FACTL_DEBUG)
    printf("\nDEBUG: Memory was allocated in the client address space.\n");
#endif

    return((void *)malloc(len));

}


//
//  FUNCTION: MIDL_user_free(size_t len)
//
//  PURPOSE: Client stub calls this function to free memory
//           allocated using MIDL_user_allocate().
//
//  PARAMETERS:
//    
//    ptr     - pointer to memory to deallocate.
//  
//  RETURN VALUE:
// 
//    None.
//
//  COMMENTS:
//


void __RPC_USER MIDL_user_free(void __RPC_FAR *ptr)
{
#if defined(FACTL_DEBUG) 
    printf("\nDEBUG: Memory was deallocated in the client address space.\n");
#endif

    free(ptr);
}                              
