REPLAY.C

/*************************************************************/ 
/** **/
/** Microsoft RPC Examples **/
/** Dictionary Application **/
/** Copyright 1992 - 1998 Microsoft Corporation **/
/** **/
/*************************************************************/

/*************************************************************************/
/*** ***/
/*** Example dictionary using splay trees: ***/
/*** ***/
/*************************************************************************/

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

#include "replay.h" // header file generated by MIDL compiler
#include "dict0.h"
#include "util0.h"

#define TAB_STOPS 3

/*************************************************************************/
/*** Declarations (from replay.h) ***/
/*************************************************************************/

/*
typedef struct _Record {
short key; // RPC "generation"
[string] char* name; // contributor
} Record;

typedef struct _RecordTreeNode RecordTreeNode;

typedef struct _RecordTreeNode {
RecordTreeNode *left; // left child pointer
RecordTreeNode *right; // right child pointer
Record *item; // pointer to a Record structure
} RecordTreeNode;

typedef struct _RDict {
RecordTreeNode *root; // pointer to the root of a SAT
long size; // number of records in dictionary
} RDict;

// RDict is used for marshalling a complete dictionary.

typedef enum {
DICT_SUCCESS,
DICT_ITEM_ALREADY_PRESENT,
DICT_ITEM_NOT_FOUND,
DICT_FIRST_ITEM,
DICT_LAST_ITEM,
DICT_EMPTY_DICTIONARY,
DICT_NULL_ITEM
} VDict_Status;

typedef struct _DictState {
short ref_count; // for shared dictionaries
Record * curr_record; // for global iterators
} DictState;
*/

/*************************************************************************/
/*** Internal state access methods ***/
/*************************************************************************/

#define RDICT_CURR_RECORD(dict) (((DictState*)dict->state)->curr_record)

#define RDICT_REF_COUNT(dict) (((DictState*)dict->state)->ref_count)

#define RDICT_STATE(dict) (((RDict*)dict)->state)

static int active_dictionary = 0;

/*************************************************************************/
/*** Generic Dictionary Operations: (From dict0.h) ***/
/*** ***/
/*** Dictionary *Dict_New(Cmp_rec*, Splay*, print_rec*) ***/
/*** ***/
/*** Dict_Status Dict_Find(Dictionary*, Item*) ***/
/*** Dict_Status Dict_Next(Dictionary*, Item*) ***/
/*** Dict_Status Dict_Prev(Dictionary*, Item*) ***/
/*** Dict_Status Dict_Insert(Dictionary*, Item*) ***/
/*** Dict_Status Dict_Delete(Dictionary*, Item**) ***/
/*** ***/
/*** Item* DICT_CURR_ITEM(Dict*) ***/
/*************************************************************************/

/*************************************************************************/
/*** Virtual Dictionary Operations: (From replay.h) ***/
/*** ***/
/*** VDict_Status VDict_New(OUT VDict **) ***/
/*** ***/
/*** VDict_Status VDict_Find(IN VDict*, IN OUT Record**) ***/
/*** VDict_Status VDict_Next(IN VDict*, IN OUT Record**) ***/
/*** VDict_Status VDict_Prev(IN VDict*, IN OUT Record**) ***/
/*** VDict_Status VDict_Insert(IN VDict*, IN Record*) ***/
/*** VDict_Status VDict_Delete(IN VDict*, IN OUT Record**) ***/
/*** ***/
/*** VDict_Status VDict_Curr_Item(IN VDict*, OUT Record**); ***/
/*** VDict_Status VDict_Curr_Delete(IN VDict*, OUT Record**); ***/
/*** VDict_Status VDict_Curr_Next(IN VDict*, OUT Record**); ***/
/*** VDict_Status VDict_Curr_Prev(IN VDict*, OUT Record**); ***/
/*** ***/
/*** VDict_Status VDict_Get_Dict(IN VDict*, OUT RDict**) ***/
/*************************************************************************/

/*************************************************************************/
/*** context rundown routine ***/
/*************************************************************************/

void __RPC_USER VDict_rundown (VDict v_dict)
{
Dictionary * pdict = (Dictionary*) v_dict;
short count = --RDICT_REF_COUNT(pdict);

printf("# of remaining users of context: %d\n\n",
RDICT_REF_COUNT(pdict) );

if (RDICT_REF_COUNT(pdict) <= 0) {
printf("CLOSING CONTEXT\n\n");

// free the splay tree
RDict_Free_Dict(v_dict);

// free the dictionary object
free_state((DictState*) pdict->state);
MIDL_user_free(v_dict);
if (count == 0)
active_dictionary = 0;
}
}

// For now: need to allocate a new item record prior to operation,
// for all OUT and IN OUT arguments, as the callee stub will free
// storage allocated for such pointer parameters.
//
// Will be fixed by the introduction of [allocate(dont_free)]
// ACF pointer type and parameter attribute.

/**************************************************************************
* VDict_New initializes a new dictionary if (1) a non shared dictionary
* was requested, or (2) a shared dictionary was requested, but no shared
* dictionary is currently active. There is at most one shared dictionary
* at any point in time.
*
* BUGBUG: shared dictionaries are *NOT* locked (by semaphore, to
* serialize access to them. They *should be, though...
**************************************************************************
*/

VDict_Status
VDict_New(
IN short shared_dict,
OUT VDict * v_dict
)
{
Dictionary * pdict0;
static Dictionary * pdict;

if (!active_dictionary || !shared_dict) {
// server side dictionary initialization
pdict0 = Dict_New(comp, tdSplay, printRecord);

// Initializes RDICT_CURR_RECORD(pdict0) to
// "minus infinity" in the order
((RDict*)pdict0)->state = allocate_state();

Init_dict(pdict0);
*v_dict = (VDict)pdict0;

if (shared_dict) {
printf("OPENING SHARED DICTIONARY CONTEXT!\n\n");
active_dictionary = 1;
pdict = pdict0;
RDICT_REF_COUNT(pdict)++;
} // else RDICT_REF_COUNT(pdict0) = 0;
}
else {
RDICT_REF_COUNT(pdict)++;
printf("# of users of shared context: %d\n\n", RDICT_REF_COUNT(pdict));
*v_dict = (VDict)pdict;
}

return(DICT_SUCCESS);
}

VDict_Status
VDict_Find(
IN VDict v_dict,
IN OUT Record ** item
)
{
Dictionary * pdict = (Dictionary*) (v_dict);
Dict_Status status;

status = Dict_Find(pdict, *item);
if ( (pdict == NULL) || DICT_EMPTY(pdict) ) {
*item = NULL;
}
else {
*item = DICT_CURR_ITEM(pdict);
*item = ItemDuplicate(*item);
}
return( (VDict_Status)status );
}

VDict_Status
VDict_Next(
IN VDict v_dict,
IN OUT Record ** item
)
// get successor of *item, and update *item to point to it
{
Dictionary * pdict = (Dictionary*) (v_dict);
Dict_Status status;

status = Dict_Next(pdict, *item);
if ( (pdict == NULL) || DICT_EMPTY(pdict) ) {
*item = NULL;
}
else {
if (*item == NULL)
ItemCopy(DICT_CURR_ITEM(pdict), RDICT_CURR_RECORD(pdict));
*item = DICT_CURR_ITEM(pdict);
}
*item = ItemDuplicate(*item);
return( (VDict_Status)status );
}

VDict_Status
VDict_Prev(
IN VDict v_dict,
IN OUT Record ** item
)
// get predecessor of *item, and update *item to point to it
{
Dictionary * pdict = (Dictionary*) (v_dict);
Dict_Status status;

status = Dict_Prev(pdict, *item);
if ( (pdict == NULL) || DICT_EMPTY(pdict) ) {
*item = NULL;
}
else {
if (*item == NULL)
ItemCopy(DICT_CURR_ITEM(pdict), RDICT_CURR_RECORD(pdict));
*item = DICT_CURR_ITEM(pdict);
}
*item = ItemDuplicate(*item);
return( (VDict_Status)status );
}

VDict_Status
VDict_Curr_Next(
IN VDict v_dict,
OUT Record ** item
)
// get successor of RDICT_CURR_RECORD(v_dict),
// and update *item to point to it (global iterator prev)
{
Dictionary * pdict = (Dictionary*) (v_dict);
Dict_Status status;

if ( (pdict == NULL) || DICT_EMPTY(pdict) ) {
status = EMPTY_DICTIONARY;
*item = NULL;
}
else {
status = Dict_Next(pdict, RDICT_CURR_RECORD(pdict));
ItemCopy(DICT_CURR_ITEM(pdict), RDICT_CURR_RECORD(pdict));
*item = DICT_CURR_ITEM(pdict);
}
*item = ItemDuplicate(*item);
return( (VDict_Status)status );
}

VDict_Status
VDict_Curr_Prev(
IN VDict v_dict,
OUT Record ** item
)
// get predecessor of RDICT_CURR_RECORD(v_dict),
// and update *item to point to it (global iterator prev)
{
Dictionary * pdict = (Dictionary*) (v_dict);
Dict_Status status;

if ( (pdict == NULL) || DICT_EMPTY(pdict) ) {
status = EMPTY_DICTIONARY;
*item = NULL;
}
else {
// update RDICT_CURR_RECORD(pdict)
status = Dict_Prev(pdict, RDICT_CURR_RECORD(pdict));
ItemCopy(DICT_CURR_ITEM(pdict), RDICT_CURR_RECORD(pdict));
*item = DICT_CURR_ITEM(pdict);
}
*item = ItemDuplicate(*item);
return( (VDict_Status)status );
}

VDict_Status
VDict_Insert(
IN VDict v_dict,
IN Record * item
)
{
Dictionary * pdict = (Dictionary*) (v_dict);
Dict_Status status;
Record * rp = makeRecord(item->key, item->name);

status = Dict_Insert(pdict, rp); // No return value required.
return( (VDict_Status)status );
}

VDict_Status
VDict_Delete(
IN VDict v_dict,
IN OUT Record ** item
)
{
Dictionary * pdict = (Dictionary*) (v_dict);
Dict_Status status;

status = Dict_Delete(pdict, (void **)item);
// (*item) is returned by Dict_Delete!
return( (VDict_Status)status );
}

VDict_Status
VDict_Curr_Item(
IN VDict v_dict,
OUT Record ** item
)
{
Dictionary * pdict = (Dictionary*) (v_dict);
Dict_Status status;

if ( (pdict == NULL) || DICT_EMPTY(pdict) ) {
status = EMPTY_DICTIONARY;
*item = NULL;
}
else {
status = SUCCESS;
*item = DICT_CURR_ITEM(pdict);
}
*item = ItemDuplicate(*item);
return( (VDict_Status)status );
}

VDict_Status
VDict_Curr_Delete(
IN VDict v_dict,
OUT Record ** item
)
{
Dictionary * pdict = (Dictionary*) (v_dict);
Dict_Status status;

if ( (pdict == NULL) || DICT_EMPTY(pdict) ) {
status = EMPTY_DICTIONARY;
*item = NULL;
}
else {
*item = DICT_CURR_ITEM(pdict);
status = Dict_Delete( pdict, (void **)item );
}
return( (VDict_Status)status );
}

VDict_Status
VDict_Get_Dict(
IN VDict v_dict,
OUT RDict ** r_dict
)
// used to transmit the dictionary back to the callee
// (In this demo program - for printing on the client side)
{
Dictionary * pdict = (Dictionary*) (v_dict);

if (pdict == NULL) {
return(DICT_EMPTY_DICTIONARY);
}
else {
prinTree(0, 3, pdict->root, printRecord);

*r_dict = RDict_Duplicate((RDict*)pdict);
// Duplication is done to avoid freeing the tree by
// the callee stub. This is a temporary fix, until we
// implement [allocate(dont_free)]!

return(DICT_SUCCESS);
}
}

/*************************************************************************/
/*** Server Utility Functions ***/
/*************************************************************************/

void
Init_dict(Dictionary * dp)
{
Record* rp;

rp = makeRecord((short)0, "jack_smith"); Dict_Insert(dp, rp);
rp = makeRecord((short)0, "john_doe"); Dict_Insert(dp, rp);
rp = makeRecord((short)1, "steve_johnson"); Dict_Insert(dp, rp);
rp = makeRecord((short)2, "debbie_jones"); Dict_Insert(dp, rp);
rp = makeRecord((short)0, "mike_jacobs"); Dict_Insert(dp, rp);
rp = makeRecord((short)2, "bill_jackson"); Dict_Insert(dp, rp);
rp = makeRecord((short)0, "jane_doe"); Dict_Insert(dp, rp);
rp = makeRecord((short)1, "james_doe"); Dict_Insert(dp, rp);
rp = makeRecord((short)1, "jean_doe"); Dict_Insert(dp, rp);
rp = makeRecord((short)0, "joana_smith"); Dict_Insert(dp, rp);
rp = makeRecord((short)1, "michael_jones"); Dict_Insert(dp, rp);
rp = makeRecord((short)0, "dianne_jackson"); Dict_Insert(dp, rp);
rp = makeRecord((short)0, "jacob_jacobson"); Dict_Insert(dp, rp);

Dict_Print(dp, TAB_STOPS);
}

/*************************************************************************/
/*** Play oriented Functions ... ***/
/*** (used to empty the tree and replace it by a tree of integers ***/
/*************************************************************************/

VDict_Status
VDict_X_Dict(
IN VDict v_dict
)
// Empty the dictionary
{
RDict * prdict = (RDict*)v_dict;

if (DICT_EMPTY(prdict))
return(DICT_EMPTY_DICTIONARY);

RecordTreeNodeFree(prdict->root);
prdict->root = NULL;
return(DICT_SUCCESS);
}

VDict_Status
VDict_I_Dict(
IN VDict v_dict,
IN short size
)
// Insert integers from 3 to a specified upper bound into the tree
{
RDict * prdict = (RDict*)v_dict;
Dict_Status status;
short i;

// Insert (<num'>, "") for all num' s.t. 3 < num' < num
for (i=3; i < size; i++) {
status = VDict_Insert(prdict,
makeRecord(i, "<"));
}
return( (VDict_Status)status );
}