/*
$Header: /cvsroot/arsperl/ARSperl/supportrev.c,v 1.30 2007/09/13 22:50:25 tstapff Exp $

    ARSperl - An ARS v2 - v5 / Perl5 Integration Kit

    Copyright (C) 1995-2003
	Joel Murphy, jmurphy@acsu.buffalo.edu
        Jeff Murphy, jcmurphy@acsu.buffalo.edu

    This program is free software; you can redistribute it and/or modify
    it under the terms as Perl itself.

    Refer to the file called "Artistic" that accompanies the source distribution
    of ARSperl (or the one that accompanies the source distribution of Perl
    itself) for a full description.

    Comments to:  arsperl@arsperl.org
                  (this is a *mailing list* and you must be
                   a subscriber before posting)

    Home Page: http://www.arsperl.org


*/

/* NAME
 *   supportrev.c
 *
 * DESCRIPTION
 *   this file contains routines that are useful for translating
 *   (ars)perl "data structures" (if you will) back into ARS C data structures.
 *   since we'll be working on converting user-supplied data (versus server
 *   supplied data) about half of all the code in this file is error checking
 *   code.
 */

#define __supportrev_c_

#include "support.h"
#include "supportrev.h"
#include "supportrev_generated.h"


/* #if defined(malloc) && defined(_WIN32)
 #undef malloc
 #undef calloc
 #undef realloc
 #undef free
#endif */


/*
 * forward declarations
 */

static int 
rev_ARActiveLinkActionList_helper(ARControlStruct * ctrl, HV * h,
				  ARActiveLinkActionList * al,
				  int idx);
static int 
rev_ARDisplayStruct_helper(ARControlStruct * ctrl,
			   HV * h, char *k, ARDisplayStruct * d);
static int 
rev_ARValueStructStr2Type(ARControlStruct * ctrl,
			  char *type, unsigned int *n);
static int 
rev_ARValueStructKW2KN(ARControlStruct * ctrl,
		       char *keyword, unsigned int *n);
static int 
rev_ARValueStructDiary(ARControlStruct * ctrl,
		       HV * h, char *k, char **d);
static int 
rev_ARAssignFieldStruct_helper(ARControlStruct * ctrl,
			       HV * h, ARAssignFieldStruct * m);
static int 
rev_ARAssignFieldStructStr2NMO(ARControlStruct * ctrl,
			       char *s, unsigned int *nmo);
static int 
rev_ARAssignFieldStructStr2MMO(ARControlStruct * ctrl,
			       char *s, unsigned int *mmo);
static int 
rev_ARStatHistoryValue_helper(ARControlStruct * ctrl,
			      HV * h, ARStatHistoryValue * s);
static int 
rev_ARArithOpAssignStruct_helper(ARControlStruct * ctrl,
				 HV * h, ARArithOpAssignStruct * s);
static int 
rev_ARArithOpAssignStructStr2OP(ARControlStruct * ctrl,
				char *c, unsigned int *o);
static int 
rev_ARFunctionAssignStructStr2FCODE(ARControlStruct * ctrl,
				    char *c, unsigned int *o);
static int 
rev_ARAssignStruct_helper(ARControlStruct * ctrl,
			  HV * h, ARAssignStruct * m);
static int 
rev_ARActiveLinkMacroStruct_helper(ARControlStruct * ctrl, HV * h,
				   ARActiveLinkMacroStruct * m);
static int 
rev_ARAssignList_helper(ARControlStruct * ctrl,
			HV * h, ARFieldAssignList * m, int i);

#if AR_EXPORT_VERSION >= 3
static int 
rev_ARByteListStr2Type(ARControlStruct * ctrl,
		       char *ts, unsigned long *tv);
static int 
rev_ARCoordList_helper(ARControlStruct * ctrl,
		       HV * h, ARCoordList * m, int idx);
static int 
rev_ARPropList_helper(ARControlStruct * ctrl,
		      HV * h, ARPropList * m, int idx);
#endif




/* ROUTINE
 *   revTypeName(TypeMapStruct *tms, char *type)
 *
 * DESCRIPTION
 *   given a typemapstruct and a string, return the 
 *   enumeration value if string exists in struct.
 *
 * RETURNS
 *   >=0 on success
 *   TYPEMAP_LAST on failure
 */

unsigned int
revTypeName(TypeMapStruct *t, char *type) 
{
	if(type && *type && t) {
		int i = 0;
		while((t[i].number != TYPEMAP_LAST) && strcmp(t[i].name, type))
			i++;
		return t[i].number;
	}
	return TYPEMAP_LAST;
}

/* ROUTINE
 *   strcpyHVal(hash, key, buffer, bufferLen)
 *
 * DESCRIPTION
 *   given a hash (HV *), a key, a pre-allocated buffer and
 *   the length of that buffer, retrieve the value from the hash
 *   (assuming it is a string value [PV]) and place it in the buffer.
 *
 * NOTES
 *   if value of hash is truncate at len bytes if it exceeds len.
 *   b, once filled in, will be null terminated.
 *
 * RETURNS
 *    0 on success
 *   -1 on failure and pushes some info in the error hash
 *   -2 on warning and pushes some info into the error hash
 *
 */

int
strcpyHVal(HV * h, char *k, char *b, int len)
{
	SV            **val;

	if (!b) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "strcpyHVal: char buffer parameter is NULL");
		return -1;
	}
	if (!h) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "strcpyHVal: hash parameter is NULL");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {
				if (SvPOK(*val)) {
					strncpy(b, SvPV(*val, PL_na), len);
					b[len] = 0;
					return 0;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "strcpyHVal: hash value is not a string");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				"strcpyHVal: hv_fetch returned null. key:");
				ARError_add(AR_RETURN_WARNING, AP_ERR_CONTINUE,
					    k ? k : "[key null]");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "strcpyHVal: key doesn't exist. key specified in next message:");
			ARError_add(AR_RETURN_WARNING, AP_ERR_CONTINUE,
				    k ? k : "[key null]");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "strcpyHVal: first argument is not a hash");
	return -1;
}

/* same as above routine, but it will allocate (malloc()) the appropriate
 * amount of memory. calling routine is responsible for free()ing it later on
 */

int
strmakHVal(HV * h, char *k, char **b)
{
	/* b must be a pointer to a pointer */

	if (!b && !*b) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "strmakHVal: char buffer parameter is invalid");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			SV            **val = hv_fetch(h,  k, strlen(k) , 0);
			STRLEN          len;

			if (val && *val) {
				if (SvPOK(*val)) {
					char           *pvchar = SvPV(*val, len);
					*b = MALLOCNN(SvCUR(*val) + 1);
					strcpy(*b, pvchar);
					*(*b + len) = 0;
					return 0;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "strmakHVal: hash value is not a string");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				      "strmakHVal: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "strmakHVal: key doesn't exist. key:");
			ARError_add(AR_RETURN_WARNING, AP_ERR_CONTINUE,
				    k ? k : "n/a");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "strmakHVal: first argument is not a hash");
	return -1;
}

/* ROUTINE
 *   intcpyHVal(hash, key, buffer)
 *
 * DESCRIPTION
 *   given a hash (HV *), a key, and a pre-allocated buffer,
 *   retrieve the value from the hash
 *   (assuming it is a integer value [IV]) and place it in the buffer.
 *
 * RETURNS
 *    0 on success
 *   -1 on failure and pushes some info in the error hash
 *   -2 on warning and pushes some info into the error hash
 */

int
intcpyHVal(HV * h, char *k, int *b)
{
	SV            **val;

	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {
				if (SvIOK(*val)) {
					*b = (int) SvIV(*val);
					return 0;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "intcpyHVal: hash value is not an integer");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				      "intcpyHVal: hv_fetch returned null");
				return -2;
			}
		} else
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "intcpyHVal: key doesn't exist");
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "intcpyHVal: first argument is not a hash");
	return -1;
}

/* ROUTINE
 *   uintcpyHVal(hash, key, buffer)
 *
 * DESCRIPTION
 *   given a hash (HV *), a key, and a pre-allocated buffer,
 *   retrieve the value from the hash
 *   (assuming it is a integer value [IV]) and place it in the buffer.
 *
 * RETURNS
 *    0 on success
 *   -1 on failure and pushes some info in the error hash
 *   -2 on warning and pushes some info into the error hash
 */

#if AR_EXPORT_VERSION >= 4
int
boolcpyHVal(HV * h, char *k, ARBoolean * b)
{
	SV            **val;

	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {
				if (SvIOK(*val)) {
					*b = (unsigned int) SvIV(*val);
					if (*b == 0)
						*b = FALSE;
					else
						*b = TRUE;
					return 0;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "boolcpyHVal: hash value is not an integer");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				     "boolcpyHVal: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "boolcpyHVal: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "boolcpyHVal: first argument is not a hash");
	return -1;
}
#endif

int
uintcpyHVal(HV * h, char *k, unsigned int *b)
{
	SV            **val;

	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {
				if (SvIOK(*val)) {
					*b = (unsigned int) SvIV(*val);
					return 0;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "uintcpyHVal: hash value is not an integer");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				     "uintcpyHVal: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "uintcpyHVal: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "uintcpyHVal: first argument is not a hash");
	return -1;
}

/* ROUTINE
 *   longcpyHVal(hash, key, buffer)
 *
 * DESCRIPTION
 *   given a hash (HV *), a key, and a pre-allocated buffer,
 *   retrieve the value from the hash
 *   (assuming it is a integer value [IV]) and place it in the buffer.
 *
 * RETURNS
 *    0 on success
 *   -1 on failure and pushes some info in the error hash
 *   -2 on warning and pushes some info into the error hash
 */

int
longcpyHVal(HV * h, char *k, long *b)
{
	SV            **val;

	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {
				if (SvIOK(*val)) {
					*b = (long) SvIV(*val);
					return 0;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "longcpyHVal: hash value is not an integer");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				     "longcpyHVal: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "longcpyHVal: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "longcpyHVal: first argument is not a hash");
	return -1;
}

int
ulongcpyHVal(HV * h, char *k, unsigned long *b)
{
	SV            **val;

	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {
				if (SvIOK(*val)) {
					*b = (unsigned long) SvIV(*val);
					return 0;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "ulongcpyHVal: hash value is not an integer");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "ulongcpyHVal: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "ulongcpyHVal: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "ulongcpyHVal: first argument is not a hash");
	return -1;
}

/* ROUTINE
 *   rev_ARDisplayList(hash, key, displayStruct)
 *
 * DESCRIPTION
 *   Given a hash and key whose corresponding value is
 *   what perl_ARList() constructed, deconstruct it back
 *   into a displayList.
 *
 *   perl_ARList should have constructed a list of hash references
 *   each containing keys: displayTag, x, y, option, label and type.
 *
 * RETURNS
 *   0 on success
 *  -1 on failure
 *  -2 on warning
 */

int
rev_ARDisplayList(ARControlStruct * ctrl, HV * h, char *k, ARDisplayList * d)
{
	SV            **val;
	int             i;

	if (!d) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARDisplayList: DisplayList param is NULL");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/* hash value should be an array reference */

				if (SvTYPE(SvRV(*val)) == SVt_PVAV) {
					AV             *ar = (AV *) SvRV((SV *) * val);

					/*
					 * allocate space for display
					 * structure list
					 */

					d->numItems = av_len(ar) + 1;
					if (d->numItems == 0)
						return 0;	/* nothing to do */
					d->displayList = MALLOCNN(sizeof(ARDisplayStruct) * d->numItems);

					/*
					 * iterate over the array, grabbing
					 * each hash reference out of it and
					 * passing that to a helper routine
					 * to fill in the DisplayList
					 * structure
					 */

					for (i = 0; i <= av_len(ar); i++) {
						SV            **av_hv = av_fetch(ar, i, 0);

						if (av_hv && *av_hv && (SvTYPE(SvRV(*av_hv)) == SVt_PVHV)) {
							if (rev_ARDisplayStruct(ctrl, (HV *) SvRV(*av_hv),
										&(d->displayList[i])) != 0)
								return -1;
						} else
							ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
								    "rev_ARDisplayList: inner array value is not a hash reference");
					}
					return 0;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARDisplayList: hash value is not an array reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				"rev_ARDisplayList: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "rev_ARDisplayList: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			 "rev_ARDisplayList: first argument is not a hash");
	return -1;
}

/* ROUTINE
 *   rev_ARDisplayStruct_helper(hv, key, displayStruct)
 *
 * DESCRIPTION
 *   a helper routine (wrapper)
 */

static int
rev_ARDisplayStruct_helper(ARControlStruct * ctrl, HV * h, char *k, ARDisplayStruct * d)
{
	SV            **val;

	if (!d) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		   "rev_ARDisplayStruct_helper: DisplayList param is NULL");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/* hash value should be an hash reference */

				if (SvTYPE(SvRV(*val)) == SVt_PVHV) {
					if (rev_ARDisplayStruct(ctrl, (HV *) SvRV(*val), d) != 0)
						return -1;
					return 0;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARDisplayStruct_helper: hash value is not an array reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
					    "rev_ARDisplayStruct_helper: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
			   "rev_ARDisplayStruct_helper: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		"rev_ARDisplayStruct_helper: first argument is not a hash");
	return -1;
}

/* ROUTINE
 *   rev_ARDisplayStruct(hv, displayStruct)
 *
 * DESCRIPTION
 *   given a hash that contains displaystruct keys
 *   and an empty (preallocated) displaystruct, fill
 *   in the display struct.
 */

int
rev_ARDisplayStruct(ARControlStruct * ctrl, HV * h, ARDisplayStruct * d)
{
	int             rv = 0, rv2 = 0;
	char            buf[1024];

	rv += strcpyHVal(h, "displayTag", d->displayTag, sizeof(ARNameType));
	rv += strcpyHVal(h, "label", d->label, sizeof(ARNameType));
	rv += intcpyHVal(h, "x", &(d->x));
	rv += intcpyHVal(h, "y", &(d->y));
	rv += uintcpyHVal(h, "length", &(d->length));
	rv += uintcpyHVal(h, "numRows", &(d->numRows));

	/* variables that need some decoding before we store them */

	/*
	 * "option" will be either "VISIBLE" or "HIDDEN" default: Visible
	 */

	if ((rv2 = strcpyHVal(h, "option", buf, sizeof(buf))) == 0) {
		if (strncasecmp(buf, "HIDDEN", sizeof(buf)) == 0)
			d->option = AR_DISPLAY_OPT_HIDDEN;
		else
			d->option = AR_DISPLAY_OPT_VISIBLE;
	} else
		rv += rv2;

	/*
	 * "labelLocation" will be either "Left" or "Top" default: Left
	 */

	if ((rv2 = strcpyHVal(h, "labelLocation", buf, sizeof(buf))) == 0) {
		if (strncasecmp(buf, "Top", sizeof(buf)) == 0)
			d->labelLocation = AR_DISPLAY_LABEL_TOP;
		else
			d->labelLocation = AR_DISPLAY_LABEL_LEFT;
	} else
		rv += rv2;

	/*
	 * "type" will be one of: NONE, TEXT, NUMTEXT, CHECKBOX, CHOICE,
	 * BUTTON default: NONE
	 */

	if ((rv2 = strcpyHVal(h, "type", buf, sizeof(buf))) == 0) {
		if (strncasecmp(buf, "TEXT", sizeof(buf)) == 0)
			d->type = AR_DISPLAY_TYPE_TEXT;
		else if (strncasecmp(buf, "NUMTEXT", sizeof(buf)) == 0)
			d->type = AR_DISPLAY_TYPE_NUMTEXT;
		else if (strncasecmp(buf, "CHECKBOX", sizeof(buf)) == 0)
			d->type = AR_DISPLAY_TYPE_CHECKBOX;
		else if (strncasecmp(buf, "CHOICE", sizeof(buf)) == 0)
			d->type = AR_DISPLAY_TYPE_CHOICE;
		else if (strncasecmp(buf, "BUTTON", sizeof(buf)) == 0)
			d->type = AR_DISPLAY_TYPE_BUTTON;
		else
			d->type = AR_DISPLAY_TYPE_NONE;
	} else
		rv += rv2;

	return rv;
}

/* ROUTINE
 *   rev_ARInternalIdList(hv, key, idliststruct)
 *
 * DESCRIPTION
 *   given a hash, a key and an empty idliststruct,
 *   pull out the hash value and populate the structure.
 *
 * RETURNS
 *   0 on success
 *  -1 on failure
 *  -2 on warning
 */

int
rev_ARInternalIdList(ARControlStruct * ctrl, HV * h, char *k, ARInternalIdList * il)
{

	if (!il || !h || !k) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARInternalIdList: required param is NULL");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			SV            **val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/* hash value should be an array reference */

				if (SvTYPE(SvRV(*val)) == SVt_PVAV) {
					AV             *ar = (AV *) SvRV((SV *) * val);
					int             i;

					/*
					 * allocate space for display
					 * structure list
					 */

					il->numItems = av_len(ar) + 1;
					if (il->numItems == 0)
						return 0;	/* nothing to do */
					il->internalIdList = MALLOCNN(sizeof(ARInternalId) * il->numItems);

					/*
					 * iterate over the array, grabbing
					 * each integer out of it and placing
					 * into the idlist.
					 */

					for (i = 0; i <= av_len(ar); i++) {
						SV            **aval = av_fetch(ar, i, 0);
						if (aval && *aval && SvIOK(*aval)) {
							il->internalIdList[i] = SvIV(*aval);
						} else {
							ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
								    "rev_ARInternalIdList: array value is not an integer.");
							return -1;
						}
					}
					return 0;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARInternalIdList: hash value is not an array reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
					    "rev_ARInternalIdList: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				 "rev_ARInternalIdList: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		      "rev_ARInternalIdList: first argument is not a hash");
	return -1;
}

/* ROUTINE
 *   rev_ARActiveLinkActionList(hv, key, actionliststruct)
 *
 * DESCRIPTION
 *   given a hash, a key and an empty actionlist,
 *   pull out the hash value and populate the structure.
 *
 * RETURNS
 *   0 on success
 *  -1 on failure
 *  -2 on warning
 */

int
rev_ARActiveLinkActionList(ARControlStruct * ctrl, HV * h, char *k, ARActiveLinkActionList * al)
{
	SV            **val;
	int             i;

	if (!al) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		   "rev_ARActiveLinkActionList: DisplayList param is NULL");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/* hash value should be an array reference */

				if (SvTYPE(SvRV(*val)) == SVt_PVAV) {
					AV             *ar = (AV *) SvRV((SV *) * val);

					/*
					 * allocate space for action
					 * structure list
					 */

					al->numItems = av_len(ar) + 1;
					if (al->numItems == 0)
						return 0;	/* nothing to do */

					al->actionList = MALLOCNN(sizeof(ARActiveLinkActionStruct) * al->numItems);

					/*
					 * iterate over the array, grabbing
					 * each hash reference out of it and
					 * passing that to a helper routine
					 * to fill in the ActionList
					 * structure. one action per array
					 * item.
					 */

					for (i = 0; i <= av_len(ar); i++) {
						SV            **av_hv = av_fetch(ar, i, 0);

						if (av_hv && *av_hv && (SvTYPE(SvRV(*av_hv)) == SVt_PVHV)) {
							if (rev_ARActiveLinkActionList_helper(ctrl,
											      (HV *) SvRV(*av_hv), al, i) != 0)
								return -1;
						} else
							ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
								    "rev_ARActiveLinkActionList: inner array value is not a hash reference");
					}
					return 0;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARActiveLinkActionList: hash value is not an array reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
					    "rev_ARActiveLinkActionList: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
			   "rev_ARActiveLinkActionList: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		"rev_ARActiveLinkActionList: first argument is not a hash");
	return -1;
}

/* helper routine to above routine. does the actual data copying once
 * main routine has verified that everything is OK.
 */

static int
rev_ARActiveLinkActionList_helper(ARControlStruct * ctrl, HV * h, ARActiveLinkActionList * al, int idx)
{
	int             rv = 0;

	/*
	 * test each has value in turn, first one that is defined, copy in
	 * and return. DDE: not implemented.
	 */

	if (hv_exists(h,  "process", strlen("process") )) {
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_PROCESS;
		rv += strmakHVal(h, "process", &(al->actionList[idx].u.process));
	} else if (hv_exists(h,  "macro", strlen("macro") )) {
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_MACRO;
		rv += rev_ARActiveLinkMacroStruct(ctrl, h, "macro",
					    &(al->actionList[idx].u.macro));
	} else if (hv_exists(h,  "assign_fields", strlen("assign_fields") )) {
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_FIELDS;
#if AR_EXPORT_VERSION >= 8L
		rv += rev_ARSetFieldsActionStruct(ctrl, h, "assign_fields",
					&(al->actionList[idx].u.setFields));
#else
		rv += rev_ARFieldAssignList(ctrl, h, "assign_fields",
					&(al->actionList[idx].u.fieldList));
#endif
	} else if (hv_exists(h,  "message", strlen("message") )) {
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_MESSAGE;
#if AR_EXPORT_VERSION >= 4
		rv += rev_ARMessageStruct(ctrl, h, "message",
					  &(al->actionList[idx].u.message));
#else
		rv += rev_ARStatusStruct(ctrl, h, "message",
					 &(al->actionList[idx].u.message));
#endif
	} else if (hv_exists(h,  "characteristics", strlen("characteristics") )) {
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_SET_CHAR;
		rv += rev_ARFieldCharacteristics(ctrl, h, "characteristics",
				  &(al->actionList[idx].u.characteristics));

	} else if (hv_exists(h,  "fieldp", strlen("fieldp") )) {
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_FIELDP;
#if AR_EXPORT_VERSION >= 8L
		rv += rev_ARPushFieldsActionStruct(ctrl, h, "fieldp",
				  &(al->actionList[idx].u.pushFields));
#else
		rv += rev_ARPushFieldsList(ctrl, h, "fieldp",
				  &(al->actionList[idx].u.pushFieldsList));
#endif

	} else if (hv_exists(h,  "openDlg", strlen("openDlg") )) {
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_OPENDLG;
		rv += rev_AROpenDlgStruct(ctrl, h, "openDlg",
				  &(al->actionList[idx].u.openDlg));

	} else if (hv_exists(h,  "closeWnd", strlen("closeWnd") )) {
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_CLOSEWND;
		rv += rev_ARCloseWndStruct(ctrl, h, "closeWnd",
				  &(al->actionList[idx].u.closeWnd));

	} else if (hv_exists(h,  "commitChanges", strlen("commitChanges") )) {
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_COMMITC;
		rv += rev_ARCommitChangesStruct(ctrl, h, "commitChanges",
				  &(al->actionList[idx].u.commitChanges));

	} else if (hv_exists(h,  "callGuide", strlen("callGuide") )) {
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_CALLGUIDE;
		rv += rev_ARCallGuideStruct(ctrl, h, "callGuide",
				  &(al->actionList[idx].u.callGuide));

	} else if (hv_exists(h,  "exitGuide", strlen("exitGuide") )) {
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_EXITGUIDE;
		rv += rev_ARExitGuideStruct(ctrl, h, "exitGuide",
				  &(al->actionList[idx].u.exitGuide));

	} else if (hv_exists(h,  "gotoGuideLabel", strlen("gotoGuideLabel") )) {
		SV **val;
		al->actionList[idx].u.gotoGuide.label = NULL;
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_GOTOGUIDELABEL;
		val = hv_fetch( h, "gotoGuideLabel", strlen("gotoGuideLabel"), 0 );
		if( val && *val ){
			al->actionList[idx].u.gotoGuide.label = strdup( SvPV_nolen(*val) );
		}
		if( al->actionList[idx].u.gotoGuide.label == NULL ){
			rv += -1;
		}

	} else if (hv_exists(h,  "gotoAction", strlen("gotoAction") )) {
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_GOTOACTION;
		rv += rev_ARGotoActionStruct(ctrl, h, "gotoAction",
				  &(al->actionList[idx].u.gotoAction));

	} else if (hv_exists(h,  "waitAction", strlen("waitAction") )) {
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_WAIT;
		rv += rev_ARWaitStruct(ctrl, h, "waitAction",
				  &(al->actionList[idx].u.waitAction));

	} else if (hv_exists(h,  "dde", strlen("dde") )) {
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_DDE;
		rv += rev_ARDDEStruct(ctrl, h, "dde",
				  &(al->actionList[idx].u.dde));

	} else if (hv_exists(h,  "sqlCommand", strlen("sqlCommand") )) {
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_SQL;
		rv += rev_ARSQLStruct(ctrl, h, "sqlCommand",
				  &(al->actionList[idx].u.sqlCommand));

	} else if (hv_exists(h,  "automation", strlen("automation") )) {
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_AUTO;
		rv += rev_ARAutomationStruct(ctrl, h, "automation",
				  &(al->actionList[idx].u.automation));

	} else if (hv_exists(h,  "none", strlen("none") )) {
		al->actionList[idx].action = AR_ACTIVE_LINK_ACTION_NONE;
	} else {
		rv = -1;
	}

	return rv;
}

/* ROUTINE
 *   rev_ARFieldAssignList(hash, key, assignList)
 *
 * DESCRIPTION
 *   the hash value is an array of hashes. interate over them
 *   and fill in the assignList structure.
 *
 * RETURNS
 *   0 on success
 *  -1 on failure
 *  -2 on warning
 */

int
rev_ARFieldAssignList(ARControlStruct * ctrl, HV * h, char *k, ARFieldAssignList * m)
{
	SV            **val;
	int             i;

	if (!m) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		    "rev_ARFieldAssignList: FieldAssignList param is NULL");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/* hash value should be an array reference */

				if (SvTYPE(SvRV(*val)) == SVt_PVAV) {
					AV             *ar = (AV *) SvRV((SV *) * val);

					/*
					 * allocate space for field assign
					 * structure list
					 */

					m->numItems = av_len(ar) + 1;
					if (m->numItems == 0)
						return 0;	/* nothing to do */
					m->fieldAssignList = MALLOCNN(sizeof(ARFieldAssignStruct) * m->numItems);

					/*
					 * iterate over the array, grabbing
					 * each hash reference out of it and
					 * passing that to a helper routine
					 * to fill in the ActionList
					 * structure. one action per array
					 * item.
					 */

					for (i = 0; i <= av_len(ar); i++) {
						SV            **av_hv = av_fetch(ar, i, 0);

						if (av_hv && *av_hv && (SvTYPE(SvRV(*av_hv)) == SVt_PVHV)) {
							if (rev_ARAssignList_helper(ctrl, (HV *) SvRV(*av_hv), m, i) != 0)
								return -1;
						} else
							ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
								    "rev_ARFieldAssignList: inner array value is not a hash reference");
					}
					return 0;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARFieldAssignList: hash value is not an array reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
					    "rev_ARFieldAssignList: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				"rev_ARFieldAssignList: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		     "rev_ARFieldAssignList: first argument is not a hash");
	return -1;
}

static int
rev_ARAssignList_helper(ARControlStruct * ctrl, HV * h, ARFieldAssignList * m, int i)
{
	int             rv = 0;

	rv += ulongcpyHVal(h, "fieldId", &(m->fieldAssignList[i].fieldId));
	rv += rev_ARAssignStruct(ctrl, h, "assignment",
				 &(m->fieldAssignList[i].assignment));

	return rv;
}

int
rev_ARAssignStruct(ARControlStruct * ctrl, HV * h, char *k, ARAssignStruct * m)
{
	if (!m || !h || !k) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		    "rev_ARAssignStruct: invalid (NULL) parameter");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			SV            **val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/* hash value should be a hash reference */

				if (SvTYPE(SvRV(*val)) == SVt_PVHV) {
					HV             *a = (HV *) SvRV((SV *) * val);
					return rev_ARAssignStruct_helper(ctrl, a, m);
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARAssignStruct: hash value is not an array reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
					    "rev_ARAssignStruct: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
			   "rev_ARAssignStruct: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		"rev_ARAssignStruct: first argument is not a hash");
	return -1;
}

static int
rev_ARAssignStruct_helper(ARControlStruct * ctrl, HV * h, ARAssignStruct * m)
{
	int             rv = 0;

	/*
	 * test each key in turn, first one that is defined, copy in and
	 * return. DDE: not implemented.
	 */

	if (hv_exists(h,  "process", strlen("process") )) {
		m->assignType = AR_ASSIGN_TYPE_PROCESS;
		rv += strmakHVal(h, "process", &(m->u.process));
	} else if (hv_exists(h,  "value", strlen("value") )) {
		m->assignType = AR_ASSIGN_TYPE_VALUE;
		rv += rev_ARValueStruct(ctrl, h, "value", "valueType", &(m->u.value));
	}
	/*
	 * note. the below union members are pointers. so we will allocate
	 * space for them and then call the subroutine to populate them with
	 * data. (with the exception of 'process' whose subroutine will do
	 * the allocating for us)
	 */

	else if (hv_exists(h,  "field", strlen("field") )) {
		m->assignType = AR_ASSIGN_TYPE_FIELD;
		m->u.field = MALLOCNN(sizeof(ARAssignFieldStruct));
		rv += rev_ARAssignFieldStruct(ctrl, h, "field", m->u.field);
	} else if (hv_exists(h,  "arith", strlen("arith") )) {
		m->assignType = AR_ASSIGN_TYPE_ARITH;
		m->u.arithOp = MALLOCNN(sizeof(ARArithOpAssignStruct));
		rv += rev_ARArithOpAssignStruct(ctrl, h, "arith", m->u.arithOp);
	} else if (hv_exists(h,  "function", strlen("function") )) {
		m->assignType = AR_ASSIGN_TYPE_FUNCTION;
		m->u.function = MALLOCNN(sizeof(ARFunctionAssignStruct));
		rv += rev_ARFunctionAssignStruct(ctrl, h, "function", m->u.function);
	}
#if AR_EXPORT_VERSION >= 3
	else if (hv_exists(h,  "sql", strlen("sql") )) {
		m->assignType = AR_ASSIGN_TYPE_SQL;
		m->u.sql = (ARAssignSQLStruct*) MALLOCNN(sizeof(ARAssignSQLStruct));
		rv += rev_ARAssignSQLStruct(ctrl, h, "sql", m->u.sql);
	}
#endif
	else if (hv_exists(h,  "none", strlen("none") )) {
		m->assignType = AR_ASSIGN_TYPE_NONE;
	} else {
		rv = -1;
	}

	return rv;
}

#if AR_EXPORT_VERSION >= 3
int
rev_ARAssignSQLStruct(ARControlStruct * ctrl, HV * h, char *k, ARAssignSQLStruct * s)
{
	SV            **h_sv = hv_fetch(h,  k, strlen(k) , 0);
	SV            **svp;
	HV             *hr;
	int             rv = 0;
	/* STRLEN       len; */


	/* dereference the hash key and extract it */

	if (SvROK(*h_sv) && SvTYPE(SvRV(*h_sv)) == SVt_PVHV) {
		hr = (HV *) SvRV(*h_sv);
	} else {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARAssignSQLStruct: hash key 'sql' doesn't contain a hash reference.");
		return -1;
	}

	/* make sure the hash contains the keys we need */

	if (!(hv_exists(hr, "server", 6) &&
	      hv_exists(hr, "sqlCommand", 10) &&
	      hv_exists(hr, "valueIndex", 10) &&
	      hv_exists(hr, "noMatchOption", 13) &&
	      hv_exists(hr, "multiMatchOption", 16))) {

		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		      "rev_ARAssignSQLStruct: required hash key not found");
		return -1;
	}
	/* copy the key values into the buffer */

	rv += strcpyHVal(hr, "server", s->server, AR_MAX_SERVER_SIZE + 1);

	/*
	svp = hv_fetch(hr,  "sqlCommand", strlen("sqlCommand") , 0);
	SvPV(*svp, len);
	*/

	rv += strmakHVal( hr, "sqlCommand", &(s->sqlCommand) );

	rv += uintcpyHVal(hr, "valueIndex", &(s->valueIndex));
	svp = hv_fetch(hr,  "noMatchOption", strlen("noMatchOption") , 0);
	if (svp && *svp) {
		char           *c = SvPV(*svp, PL_na);
		if (rev_ARAssignFieldStructStr2NMO(ctrl, c, &(s->noMatchOption)) != 0) {
			s->noMatchOption = AR_NO_MATCH_ERROR;
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "rev_ARAssignSQLStruct: unknown noMatchOption string:");
			ARError_add(AR_RETURN_WARNING, AP_ERR_CONTINUE,
				    c);
		}
	}
	svp = hv_fetch(hr,  "multiMatchOption", strlen("multiMatchOption") , 0);
	if (svp && *svp) {
		char           *c = SvPV(*svp, PL_na);
		if (rev_ARAssignFieldStructStr2MMO(ctrl, c, &(s->multiMatchOption)) != 0) {
			s->multiMatchOption = AR_MULTI_MATCH_ERROR;
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "rev_ARAssignSQLStruct: unknown multiMatchOption string:");
			ARError_add(AR_RETURN_WARNING, AP_ERR_CONTINUE,
				    c);
		}
	}
	return rv;
}
#endif				/* ARS 3.x */

/* ROUTINE
 *   rev_ARValueStruct(hash, value-key, type-key, valueStruct)
 *
 * DESCRIPTION
 *   given a hash that contains a key that points to a list of values
 *   and a key that contains a value and another key that describes
 *   the (ars) datatype of that value, populate the given valueStruct.
 *
 * RETURNS
 *   0 on success
 *  -1 on failure
 *  -2 on warning
 */

int
rev_ARValueStruct(ARControlStruct * ctrl, HV * h, char *k, char *t, ARValueStruct * m)
{
	SV            **val, **type;

	if (!m || !h || !k || !t) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARValueStruct: invalid (NULL) parameter");
		return -1;
	}
	/*
	 * extract the value of the key, determine what datatype it is and
	 * fill in the value struct.
	 */

	val = hv_fetch(h,  k, strlen(k) , 0);
	type = hv_fetch(h,  t, strlen(t) , 0);
	if (val && *val && type && *type && SvPOK(*type)) {
		char           *tp = SvPV(*type, PL_na), 
		               *vp = SvPV(*val,  PL_na);


		int len;
		char *str;
		str = SvPV( *val, len );
		if( len > 0 && str[0] == '\0' ){
			m->dataType = AR_DATA_TYPE_KEYWORD;
			if (rev_ARValueStructKW2KN(ctrl, str, &(m->u.keyNum)) == -1) return -1;
			return 0;
		}

		(void) rev_ARValueStructStr2Type(ctrl, tp, &(m->dataType));
		switch (m->dataType) {
		case AR_DATA_TYPE_NULL:
			m->u.intVal = 0;
			break;
		case AR_DATA_TYPE_KEYWORD:
			if (rev_ARValueStructKW2KN(ctrl, vp, &(m->u.keyNum)) == -1)
				return -1;
			break;
		case AR_DATA_TYPE_INTEGER:
			m->u.intVal = SvIV(*val);
			break;
		case AR_DATA_TYPE_REAL:
			m->u.realVal = SvNV(*val);
			break;
		case AR_DATA_TYPE_CHAR:
			if (strmakHVal(h, k, &(m->u.charVal)) == -1)
				return -1;
			break;
		case AR_DATA_TYPE_DIARY:
			if (rev_ARValueStructDiary(ctrl, h, k, &(m->u.diaryVal)) == -1)
				return -1;
			break;
		case AR_DATA_TYPE_ENUM:
			m->u.enumVal = (unsigned long) SvIV(*val);
			break;
		case AR_DATA_TYPE_TIME:
			m->u.timeVal = (ARTimestamp) SvIV(*val);
			break;
		case AR_DATA_TYPE_BITMASK:
			m->u.maskVal = (unsigned long) SvIV(*val);
			break;
#if AR_EXPORT_VERSION >= 3
		case AR_DATA_TYPE_BYTES:
			m->u.byteListVal = (ARByteList *) MALLOCNN(sizeof(ARByteList));
			if (rev_ARByteList(ctrl, h, k, m->u.byteListVal) == -1)
				return -1;
			break;
		case AR_DATA_TYPE_JOIN:
			return -1;	/* FIX: implement */
			break;
		case AR_DATA_TYPE_TRIM:
			return -1;	/* FIX: implement */
			break;
		case AR_DATA_TYPE_CONTROL:
			return -1;	/* FIX: implement */
			break;
		case AR_DATA_TYPE_COORDS:
			m->u.coordListVal = (ARCoordList *) MALLOCNN(sizeof(ARCoordList));
			if (rev_ARCoordList(ctrl, h, k, m->u.coordListVal) == -1)
				return -1;
			break;
		case AR_DATA_TYPE_ULONG:
			m->u.ulongVal = (unsigned long) SvIV(*val);
			break;
#endif
#if AR_EXPORT_VERSION >= 4
		case AR_DATA_TYPE_DECIMAL:
			if (strmakHVal(h, k, &(m->u.decimalVal)) == -1)
				return -1;
			break;
#endif
#if AR_EXPORT_VERSION >= 7
		case AR_DATA_TYPE_DATE:
			m->u.dateVal = SvIV(*val);
			break;
		case AR_DATA_TYPE_TIME_OF_DAY:
			m->u.timeOfDayVal = (ARTime) SvIV(*val);
			break;
		case AR_DATA_TYPE_CURRENCY:
			m->u.currencyVal = (ARCurrencyStruct*) MALLOCNN(sizeof(ARCurrencyStruct));
			if( sv_to_ARCurrencyStruct(ctrl,*val,m->u.currencyVal) == -1 )
				return -1;
			break;
		case AR_DATA_TYPE_DISPLAY:
			if (strmakHVal(h, k, &(m->u.charVal)) == -1)
				return -1;
			break;
#endif
		default:
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "rev_ARValueStruct: unknown data type:");
			ARError_add(AR_RETURN_WARNING, AP_ERR_CONTINUE,
				    tp);
			return -2;
		}
		return 0;
	}
	ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
		 "rev_ARValueStruct: hash value(s) were invalid for keys:");
	ARError_add(AR_RETURN_WARNING, AP_ERR_CONTINUE, k);
	ARError_add(AR_RETURN_WARNING, AP_ERR_CONTINUE, t);
	return -2;
}

static int
rev_ARValueStructStr2Type(ARControlStruct * ctrl, char *type, unsigned int *n)
{
	int             i = 0;

	if (type && *type) {
		for (i = 0; DataTypeMap[i].number != TYPEMAP_LAST; i++)
			if (strcasecmp(type,  DataTypeMap[i].name) == 0)
				break;
		if (DataTypeMap[i].number != TYPEMAP_LAST) {
			*n = DataTypeMap[i].number;
			return 0;
		}
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		       "rev_ARValueStructStr2Type: type given is unknown:");
		ARError_add(AR_RETURN_ERROR, AP_ERR_CONTINUE,
			    type);
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARValueStructStr2Type: type param is NULL");
	return -1;
}

static int
rev_ARValueStructKW2KN(ARControlStruct * ctrl, char *keyword, unsigned int *n)
{
	int             i;

	if (keyword && (*keyword == '\0')) {
		for (i = 0; KeyWordMap[i].number != TYPEMAP_LAST; i++) {
			if (compmem(keyword, KeyWordMap[i].name, KeyWordMap[i].len) == 0)
				break;
		}
		if (KeyWordMap[i].number != TYPEMAP_LAST) {
			*n = KeyWordMap[i].number;
			return 0;
		}
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		       "rev_ARValueStructKW2KN: keyword given is unknown:");
		ARError_add(AR_RETURN_ERROR, AP_ERR_CONTINUE,
			    keyword);
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARValueStructKW2KN: keyword param is NULL");

	return -1;
}

static int
rev_ARValueStructDiary(ARControlStruct * ctrl, HV * h, char *k, char **d)
{
	if (!h || !k || !d) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			"rev_ARValueStructDiary: invalid (NULL) parameter");
		return -1;
	}
	if (hv_exists(h,  k, strlen(k) )) {
		SV            **hr = hv_fetch(h,  k, strlen(k) , 0);
		if (hr && *hr && SvROK(*hr) && (SvTYPE(*hr) == SVt_PVHV)) {
			HV             *h2 = (HV *) SvRV(*hr);
			char           *user = (char *) NULL, *value = (char *) NULL;
			ARTimestamp     timestamp = 0;
			int             rv = 0;

			/* fetch the keys: timestamp, user and value */

			rv += strmakHVal(h2, "user", &user);
			rv += strmakHVal(h2, "value", &value);
			rv += longcpyHVal(h2, "timestamp", &timestamp);

			if (rv == 0) {
				int             blen = strlen(user) + strlen(value) + 2 + 12;
				char           *buf = (char *) MALLOCNN(blen);
				sprintf(buf, "%d\003%s\003%s", (int)timestamp, user, value);
				*d = buf;
				if (user)
					AP_FREE(user);
				if (value)
					AP_FREE(value);
				return 0;
			}
		} else if (hr && *hr && SvOK(*hr)) {
			char *buf = SvPV_nolen(*hr); 
			*d = strdup( buf ); 
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "rev_ARValueStructDiary: non-hashref variant used");
			return 0;
		} else {
			ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
				    "rev_ARValueStructDiary: hash value is not hash ref for key:");
			ARError_add(AR_RETURN_ERROR, AP_ERR_CONTINUE,
				    k);
		}
	} else {
		ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
			 "rev_ARValueStructDiary: hash key doesn't exist:");
		ARError_add(AR_RETURN_WARNING, AP_ERR_CONTINUE,
			    k);
		return -2;
	}
	return -1;
}

#if AR_EXPORT_VERSION >= 3
int
rev_ARByteList(ARControlStruct * ctrl, HV * h, char *k, ARByteList * b)
{
	if (!h || !k || !b) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARByteList: invalid (NULL) parameter");
		return -1;
	}
	if (hv_exists(h,  k, strlen(k) )) {
		SV            **hr = hv_fetch(h,  k, strlen(k) , 0);
		if (hr && *hr && SvROK(*hr) && (SvTYPE(SvRV(*hr)) == SVt_PVHV)) {
			HV             *h2 = (HV *) SvRV(*hr);

			if ( hv_exists(h2, "type", strlen("type")) && hv_exists(h2, "value", strlen("value")) ) {
				SV            **tv = hv_fetch(h2,  "type", strlen("type") , 0);
				SV            **vv = hv_fetch(h2,  "value", strlen("value") , 0);

				/* we are expecting two PV's */

				if (SvPOK(*tv) && SvPOK(*vv)) {
					char           *typeString = SvPV(*tv, PL_na);	/* SvPV is a macro */
					char           *byteString = SvPV(*vv, PL_na);
					int             byteLen = SvCUR(*vv);

					if (rev_ARByteListStr2Type(ctrl, typeString, &(b->type)) == -1)
						return -1;
					b->numItems = byteLen;
					b->bytes = MALLOCNN(byteLen + 1);	/* don't want FreeAR..
										 * to whack us */
					copymem(b->bytes, byteString, byteLen);
					return 0;
				}
			} else {
				ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
					    "rev_ARByteList: required keys (type and value) not found in inner hash.");
			}
		} else {
			ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
				    "rev_ARByteList: hash value is not hash ref for key:");
			ARError_add(AR_RETURN_ERROR, AP_ERR_CONTINUE,
				    k ? k : "[key null]");
			printf( "SvTYPE = %d\n", SvTYPE(*hr) );
		}
	} else {
		ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
			    "rev_ARByteList: hash key doesn't exist:");
		ARError_add(AR_RETURN_WARNING, AP_ERR_CONTINUE,
			    k ? k : "[key null]");
		return -2;
	}
	return -1;
}

static int
rev_ARByteListStr2Type(ARControlStruct * ctrl, char *ts, unsigned long *tv)
{
	int             i = 0;

	if (ts && *ts && tv) {
		for (i = 0; ByteListTypeMap[i].number != TYPEMAP_LAST; i++)
			if (strncasecmp(ts,  ByteListTypeMap[i].name, strlen(ByteListTypeMap[i].name) ) == 0)
				break;
		if (ByteListTypeMap[i].number != TYPEMAP_LAST) {
			*tv = ByteListTypeMap[i].number;
			return 0;
		}
	}
	return -1;
}

int
rev_ARCoordList(ARControlStruct * ctrl, HV * h, char *k, ARCoordList * m)
{
	SV            **val;
	int             i;

	if (!m) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			  "rev_ARCoordList: FieldAssignList param is NULL");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/* hash value should be an array reference */

				if (SvTYPE(SvRV(*val)) == SVt_PVAV) {
					AV             *ar = (AV *) SvRV((SV *) * val);

					/*
					 * allocate space for field assign
					 * structure list
					 */

					m->numItems = av_len(ar) + 1;
					if (m->numItems == 0)
						return 0;	/* nothing to do */
					m->coords = MALLOCNN(sizeof(ARCoordStruct) * m->numItems);

					/*
					 * iterate over the array, grabbing
					 * each hash reference out of it and
					 * passing that to a helper routine
					 * to fill in the Coord structure.
					 */

					for (i = 0; i <= av_len(ar); i++) {
						SV            **av_hv = av_fetch(ar, i, 0);

						if (av_hv && *av_hv && (SvTYPE(SvRV(*av_hv)) == SVt_PVHV)) {
							if (rev_ARCoordList_helper(ctrl, (HV *) SvRV(*av_hv), m, i) != 0)
								return -1;
						} else
							ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
								    "rev_ARCoordList: inner array value is not a hash reference");
					}
					return 0;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARCoordList: hash value is not an array reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				 "rev_ARCoordList: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "rev_ARCoordList: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARCoordList: first argument is not a hash");
	return -1;
}

static int
rev_ARCoordList_helper(ARControlStruct * ctrl, HV * h, ARCoordList * m, int idx)
{
	if ( hv_exists(h,"x",strlen("x")) && hv_exists(h,"y",strlen("y")) ) {
		SV            **xv = hv_fetch(h,  "x", strlen("x") , 0);
		SV            **yv = hv_fetch(h,  "y", strlen("y") , 0);

		if (SvIOK(*xv) && SvIOK(*yv)) {
			m->coords[idx].x = (long) SvIV(*xv);
			m->coords[idx].y = (long) SvIV(*yv);
			return 0;
		} else
			ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			"rev_ARCoordList_helper: coord values are not IV's");
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		"rev_ARCoordList_helper: hash keys (x and y) do not exist.");

	return -1;
}
#endif				/* 3.x */

/* ROUTINE
 *   rev_ARAssignFieldStruct(hash, key, assignfieldstruct)
 *
 * DESCRIPTION
 *   hash{key} = hash ref to "assign field struct" (ds_afs.html)
 *   extract info from hash ref, populate struct, return.
 *
 * RETURNS
 *   0 on success
 *  -1 on failure
 *  -2 on warning
 */

int
rev_ARAssignFieldStruct(ARControlStruct * ctrl, HV * h, char *k, ARAssignFieldStruct * m)
{
	if (!m || !h || !k) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		       "rev_ARAssignFieldStruct: invalid (NULL) parameter");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			SV            **val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/* hash value should be a hash reference */

				if (SvTYPE(SvRV(*val)) == SVt_PVHV) {
					HV             *h2 = (HV *) SvRV((SV *) * val);
					/*
					 * extract vals from hash ref and
					 * populate structure
					 */
					return rev_ARAssignFieldStruct_helper(ctrl, h2, m);
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARAssignFieldStruct: hash value is not a hash reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
					    "rev_ARAssignFieldStruct: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
			      "rev_ARAssignFieldStruct: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		   "rev_ARAssignFieldStruct: first argument is not a hash");
	return -1;
}

static int
rev_ARAssignFieldStruct_helper(ARControlStruct * ctrl, HV * h, ARAssignFieldStruct * m)
{
	ARQualifierStruct *qp;
	SV            **qpsv, **svp;

	if (!(hv_exists(h, "server", 6) &&
	      hv_exists(h, "schema", 6) &&
	      hv_exists(h, "qualifier", 9) &&
#if AR_EXPORT_VERSION >= 3
	      hv_exists(h, "noMatchOption", 13) &&
	      hv_exists(h, "multiMatchOption", 16) &&
#endif
	      (hv_exists(h, "fieldId", 7)        ||
	       hv_exists(h, "currencyField", 13) ||
	       hv_exists(h, "statHistory", 11) ))
		) {

		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARAssignFieldStruct_helper: required hash key not found");
		return -1;
	}
	strcpyHVal(h, "server", m->server, AR_MAX_SERVER_SIZE + 1);
	strcpyHVal(h, "schema", m->schema, sizeof(ARNameType));

	if (hv_exists(h, "fieldId", 7)) {
		m->tag = AR_FIELD;
		if (ulongcpyHVal(h, "fieldId", &(m->u.fieldId)) != 0)
			return -1;
	} else if (hv_exists(h, "statHistory", 11)) {
		m->tag = AR_STAT_HISTORY;
		if (rev_ARStatHistoryValue(ctrl, h, "statHistory", &(m->u.statHistory)) != 0)
			return -1;
#if AR_EXPORT_VERSION >= 7L
	} else if (hv_exists(h, "currencyField", 13)) {
		m->tag = AR_CURRENCY_FLD;
		m->u.currencyField = MALLOCNN(sizeof(ARCurrencyPartStruct));
		if (rev_ARCurrencyPartStruct(ctrl, h, "currencyField", m->u.currencyField) != 0)
			return -1;
#endif
	}else{
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
				"rev_ARAssignFieldStruct_helper: invalid assign type");
		return -1;
	}

#if AR_EXPORT_VERSION >= 3
	svp = hv_fetch(h,  "noMatchOption", strlen("noMatchOption") , 0);
	if (svp && *svp) {
		char           *c = SvPV(*svp, PL_na);
		if (rev_ARAssignFieldStructStr2NMO(ctrl, c, &(m->noMatchOption)) != 0)
			m->noMatchOption = AR_NO_MATCH_ERROR;
	}
	svp = hv_fetch(h,  "multiMatchOption", strlen("multiMatchOption") , 0);
	if (svp && *svp) {
		char           *c = SvPV(*svp, PL_na);
		if (rev_ARAssignFieldStructStr2MMO(ctrl, c, &(m->multiMatchOption)) != 0)
			m->multiMatchOption = AR_MULTI_MATCH_ERROR;
	}
#endif

	/*
	 * extract and duplicate the qualifier struct. if we don't duplicate
	 * it and simply reference it, FreeARyaddayadda() will free what the
	 * reference points to and this could lead to badness if the user
	 * tries to access the qual struct later on.
	 */

	qpsv = hv_fetch(h,  "qualifier", strlen("qualifier") , 0);
	if (qpsv && *qpsv && SvROK(*qpsv)) {
		if (sv_derived_from(*qpsv, "ARQualifierStructPtr")) {
			qp = (ARQualifierStruct *) SvIV((SV *) SvRV(*qpsv));

			if (dup_qualifier2(ctrl, qp, &(m->qualifier), 0) != (ARQualifierStruct *) NULL) {
				return 0;
			}else{
				ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
					    "rev_ARAssignFieldStruct_helper: dup_qualifier2() failed");
				return -1;
			}
		} else
			ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
				    "rev_ARAssignFieldStruct_helper: qualifier key of type ARQualifierStructPtr");

	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARAssignFieldStruct_helper: qualifier key is not a reference");

	return -1;
}

static int
rev_ARAssignFieldStructStr2NMO(ARControlStruct * ctrl, char *s, unsigned int *nmo)
{
	if (s && *s) {
		int             i;
		for (i = 0; NoMatchOptionMap[i].number != TYPEMAP_LAST; i++)
			if (strcasecmp(NoMatchOptionMap[i].name, s) == 0)
				break;
		if (NoMatchOptionMap[i].number != TYPEMAP_LAST) {
			*nmo = NoMatchOptionMap[i].number;
			return 0;
		}
	}
	return -1;
}

static int
rev_ARAssignFieldStructStr2MMO(ARControlStruct * ctrl, char *s, unsigned int *mmo)
{
	if (s && *s) {
		int             i;
		for (i = 0; MultiMatchOptionMap[i].number != TYPEMAP_LAST; i++)
			if (strcasecmp(MultiMatchOptionMap[i].name, s) == 0)
				break;
		if (MultiMatchOptionMap[i].number != TYPEMAP_LAST) {
			*mmo = MultiMatchOptionMap[i].number;
			return 0;
		}
	}
	return -1;
}

/* ROUTINE
 *   rev_ARStatHistoryValue(hash, key, stathistvaluestruct)
 *
 * DESCRIPTION
 *   given a hash/key that contains a ref to a status history hash structure,
 *   extract the info from the hash ref and populate the give stathist struct.
 *
 * RETURNS
 *   0 on success
 *  -1 on failure
 *  -2 on warning
 */

int
rev_ARStatHistoryValue(ARControlStruct * ctrl, HV * h, char *k, ARStatHistoryValue * s)
{
	if (!s || !h || !k) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			"rev_ARStatHistoryValue: invalid (NULL) parameter");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			SV            **val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/* hash value should be a hash reference */

				if (SvTYPE(SvRV(*val)) == SVt_PVHV) {
					HV             *h2 = (HV *) SvRV((SV *) * val);
					/*
					 * extract vals from hash ref and
					 * populate structure
					 */
					return rev_ARStatHistoryValue_helper(ctrl, h2, s);
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARStatHistoryValue: hash value is not a hash reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
					    "rev_ARStatHistoryValue: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
			       "rev_ARStatHistoryValue: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		    "rev_ARStatHistoryValue: first argument is not a hash");
	return -1;
}

static int
rev_ARStatHistoryValue_helper(ARControlStruct * ctrl, HV * h, ARStatHistoryValue * s)
{
	if (!(hv_exists(h, "userOrTime", 10) && hv_exists(h, "enumVal", 7))) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARAssignFieldStruct_helper: required hash key not found");
		return -1;
	}
	if (ulongcpyHVal(h, "enumVal", &(s->enumVal)) != 0)
		return -1;
	if (uintcpyHVal(h, "userOrTime", &(s->userOrTime)) != 0)
		return -1;

	return 0;
}

/* ROUTINE
 *   rev_ARArithOpAssignStruct(hash, key, arithopstruct)
 *
 * DESCRIPTION
 *   this routine will populate the arithopstruct with the information
 *   contained in the hash ref that is the value of the hash/key given.
 *
 * RETURNS
 *   0 on success
 *  -1 on failure
 *  -2 on warning
 */

int
rev_ARArithOpAssignStruct(ARControlStruct * ctrl,
			  HV * h, char *k, ARArithOpAssignStruct * s)
{
	if (!s || !h || !k) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		     "rev_ARArithOpAssignStruct: invalid (NULL) parameter");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			SV            **val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/* hash value should be a hash reference */

				if (SvTYPE(SvRV(*val)) == SVt_PVHV) {
					HV             *h2 = (HV *) SvRV((SV *) * val);
					/*
					 * extract vals from hash ref and
					 * populate structure
					 */
					return rev_ARArithOpAssignStruct_helper(ctrl, h2, s);
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARArithOpAssignStruct: hash value is not a hash reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
					    "rev_ARArithOpAssignStruct: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
			    "rev_ARArithOpAssignStruct: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		 "rev_ARArithOpAssignStruct: first argument is not a hash");
	return -1;
}

static int
rev_ARArithOpAssignStruct_helper(ARControlStruct * ctrl,
				 HV * h, ARArithOpAssignStruct * s)
{
	SV            **svp;

	if (!hv_exists(h, "oper", 4)) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARArithOpAssignStruct_helper: hash does not contain required key 'oper'.");
		return -1;
	}
	/* decode the operation type */

	svp = hv_fetch(h,  "oper", strlen("oper") , 0);
	if (svp && *svp) {
		char           *c = SvPV(*svp, PL_na);
		if (rev_ARArithOpAssignStructStr2OP(ctrl, c, &(s->operation)) != 0)
			return -1;
	}
	/*
	 * if oper is 'negate' then we only are interested in the 'left'
	 * side. else we expect to get both side. call rev_ARAssignStruct()
	 * to fill it the structure.
	 */

	if( s->operation == AR_ARITH_OP_SUBTRACT && ! hv_exists(h,"left",4) ){
		s->operation = AR_ARITH_OP_NEGATE;
	}

	if (s->operation == AR_ARITH_OP_NEGATE) {
		if (hv_exists(h, "right", 5))
			return rev_ARAssignStruct(ctrl, h, "right", &(s->operandRight));
		else {
			ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
				    "rev_ARArithOpAssignStructStr2OP: operation 'negate' ('-') requires 'left' key.");
			return -1;
		}
	}
	/* other operations require both left and right */

	if (!(hv_exists(h, "left", 4) && hv_exists(h, "right", 5))) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARArithOpAssignStruct_helper: 'left' AND 'right' keys are required.");
		return -1;
	}
	if (rev_ARAssignStruct(ctrl, h, "left", &(s->operandLeft)) == -1)
		return -1;
	return rev_ARAssignStruct(ctrl, h, "right", &(s->operandRight));
}

static int
rev_ARArithOpAssignStructStr2OP(ARControlStruct * ctrl, char *c, unsigned int *o)
{
	int             i;
	for (i = 0; ArithOpMap[i].number != TYPEMAP_LAST; i++)
		if (strcasecmp(ArithOpMap[i].name, c) == 0)
			break;
	if (ArithOpMap[i].number == TYPEMAP_LAST) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		"rev_ARArithOpAssignStructStr2OP: unknown operation word:");
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL, c);
		return -1;
	}
	*o = ArithOpMap[i].number;
	return 0;
}

/* ROUTINE
 *   rev_ARFunctionAssignStruct(hash, key, functionassignstruct)
 *
 * DESCRIPTION
 *   unpack the function assign perl structure from the hash/key pair
 *   (it will be a hash ref) and populate the functionassignstruct
 *
 * RETURNS
 *   0 on success
 *  -1 on failure
 *  -2 on warning
 */

int
rev_ARFunctionAssignStruct(ARControlStruct * ctrl,
			   HV * h, char *k, ARFunctionAssignStruct * s)
{
	if (!s || !h || !k) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		    "rev_ARFunctionAssignStruct: invalid (NULL) parameter");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			SV            **val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/* hash value should be an array reference */

				if (SvTYPE(SvRV(*val)) == SVt_PVAV) {
					AV             *a = (AV *) SvRV((SV *) * val);
					SV            **aval;
					int             i;

					if (av_len(a) < 0) {
						ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
							    "rev_ARFunctionAssignStruct: array must have at least 1 element.");
						return -1;
					}
					aval = av_fetch(a, 0, 0);	/* fetch function name */
					if (aval && *aval && SvPOK(*aval)) {	/* must be a string */
						char           *fn = SvPV(*aval, PL_na);
						if (rev_ARFunctionAssignStructStr2FCODE(ctrl, fn, &(s->functionCode)) == -1)
							return -1;
					} else {
						ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
							    "rev_ARFunctionAssignStruct: first element of array must be a string function name.");
						return -1;
					}

					/*
					 * loop over remaining array elements
					 * and populate the parameterList
					 */

					s->numItems = av_len(a);	/* no +1 in this case */
					if (s->numItems == 0)
						return 0;	/* nothing to do */
					s->parameterList = (ARAssignStruct *) MALLOCNN(sizeof(ARAssignStruct) * s->numItems);

					for (i = 1; i <= av_len(a); i++) {
						SV            **hvr = av_fetch(a, i, 0);
						if (hvr && *hvr && (SvTYPE(SvRV(*hvr)) == SVt_PVHV))
							if (rev_ARAssignStruct_helper(ctrl, (HV *) SvRV(*hvr),
										      &(s->parameterList[i-1])) == -1)
								return -1;
					}

					return 0;

				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARFunctionAssignStruct: hash value is not an array reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
					    "rev_ARFunctionAssignStruct: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
			   "rev_ARFunctionAssignStruct: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		"rev_ARFunctionAssignStruct: first argument is not a hash");
	return -1;
}

static int
rev_ARFunctionAssignStructStr2FCODE(ARControlStruct * ctrl, char *c, unsigned int *o)
{
	int             i;
	for (i = 0; FunctionMap[i].number != TYPEMAP_LAST; i++)
		if (strcasecmp(FunctionMap[i].name, c) == 0)
			break;
	if (FunctionMap[i].number == TYPEMAP_LAST) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARFunctionAssignStructStr2FCODE: unknown function name:");
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL, c);
		return -1;
	}
	*o = FunctionMap[i].number;
	return 0;
}

#ifdef ARS452
/* ROUTINE
 *   rev_ARFilterStatusStruct(hash, key, filterstatusstruct)
 *
 * DESCRIPTION
 *   take hash ref from hash/key and extract filter status struct fields
 *   from that. populate filter status struct.
 *
 * RETURNS
 *   0 on success
 *  -1 on failure
 *  -2 on warning
 */

int
rev_ARFilterStatusStruct(ARControlStruct * ctrl, HV * h, char *k, 
			 ARFilterStatusStruct * m)
{
	if (!m || !h || !k) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARFilterStatusStruct: invalid (NULL) parameter");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			SV            **val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/* hash value should be a hash reference */

				if (SvTYPE(SvRV(*val)) == SVt_PVHV) {
					HV             *a = (HV *) SvRV((SV *) * val);
					int             rv = 0;

					rv += strmakHVal(a, "messageText", &(m->messageText));
					rv += uintcpyHVal(a, "messageType", &(m->messageType));
					rv += longcpyHVal(a, "messageNum", &(m->messageNum));
					return rv;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARFilterStatusStruct: hash value is not a hash reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
					    "rev_ARFilterStatusStruct: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "rev_ARFilterStatusStruct: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			"rev_ARFilterStatusStruct: first argument is not a hash");
	return -1;
}
#endif

/* ROUTINE
 *   rev_ARStatusStruct(hash, key, statusstruct)
 *
 * DESCRIPTION
 *   take hash ref from hash/key and extract status struct fields
 *   from that. populate status struct.
 *
 * RETURNS
 *   0 on success
 *  -1 on failure
 *  -2 on warning
 */

int
rev_ARStatusStruct(ARControlStruct * ctrl, HV * h, char *k, ARStatusStruct * m)
{
	if (!m || !h || !k) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARStatusStruct: invalid (NULL) parameter");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			SV            **val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/* hash value should be a hash reference */

				if (SvTYPE(SvRV(*val)) == SVt_PVHV) {
					HV             *a = (HV *) SvRV((SV *) * val);
					int             rv = 0;

					rv += strmakHVal(a, "messageText", &(m->messageText));
					rv += uintcpyHVal(a, "messageType", &(m->messageType));
					rv += longcpyHVal(a, "messageNum", &(m->messageNum));
#if AR_EXPORT_VERSION >= 4
					rv += strmakHVal(a, "appendedText", &(m->appendedText));
#endif
					return rv;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARStatusStruct: hash value is not a hash reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
					    "rev_ARStatusStruct: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "rev_ARStatusStruct: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			"rev_ARStatusStruct: first argument is not a hash");
	return -1;
}

#if AR_EXPORT_VERSION >= 4
int
rev_ARMessageStruct(ARControlStruct * ctrl, HV * h, char *k, ARMessageStruct * m)
{
	if (!m || !h || !k) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARMessageStruct: invalid (NULL) parameter");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			SV            **val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/* hash value should be a hash reference */

				if (SvTYPE(SvRV(*val)) == SVt_PVHV) {
					HV             *a = (HV *) SvRV((SV *) * val);
					int             rv = 0;
					char           *str = NULL;

					if(hv_exists(a,  "messageType", strlen("messageType") )) {
						SV **sval = hv_fetch(a,  "messageType", strlen("messageType") , 0);
						if(sval && *sval) {
							if (SvPOK(*sval)) 
								str = SvPV(*sval, PL_na);
						}
					} else {
						ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
							    "rev_ARMessageStruct: messageType key doesn't exist:");
						return -1;
					}


					/* pre1-1.68 messageType was an int, from 1.68 on, it 
					 * is a decoded string, so we need to re-encode from the string
					 * value. previous code was:
					 *
					 * rv += uintcpyHVal(a, "messageType", &(m->messageType));
					 *
					 * new code follows (next 10 lines or so)
					 */

					m->messageType = 
						revTypeName((TypeMapStruct *)StatusReturnTypeMap,
							   str);

					if(m->messageType == TYPEMAP_LAST) {
						ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
							    "rev_ARMessageStruct: messageType key invalid. key follows:");
						ARError_add(AR_RETURN_WARNING, AP_ERR_CONTINUE,
							    str ? str : "[key null]");

						return -1;
					}

					rv += strmakHVal(a, "messageText", &(m->messageText));
					rv += longcpyHVal(a, "messageNum", &(m->messageNum));
					rv += boolcpyHVal(a, "usePromptingPane", &(m->usePromptingPane));

					return rv;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARMessageStruct: hash value is not a hash reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
					    "rev_ARMessageStruct: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				  "rev_ARMessageStruct: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		       "rev_ARMessageStruct: first argument is not a hash");
	return -1;
}
#endif

/* ROUTINE
 *   rev_ARFieldCharacteristics(hash, key, fieldcharstruct)
 *
 * DESCRIPTION
 *   just like all the rest, only different.
 *
 * RETURNS
 *   0 on success
 *  -1 on failure
 *  -2 on warning
 */

int
rev_ARFieldCharacteristics(ARControlStruct * ctrl,
			   HV * h, char *k, ARFieldCharacteristics * m)
{
	if (!m || !h || !k) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		    "rev_ARFieldCharacteristics: invalid (NULL) parameter");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			SV            **val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/* hash value should be a hash reference */

				if (SvTYPE(SvRV(*val)) == SVt_PVHV) {
					HV             *a = (HV *) SvRV((SV *) * val);
					int             rv = 0;

					rv += uintcpyHVal(a, "accessOption", &(m->accessOption));
					rv += uintcpyHVal(a, "focus", &(m->focus));
					rv += ulongcpyHVal(a, "fieldId", &(m->fieldId));
					rv += strmakHVal(a, "charMenu", &(m->charMenu));
#if AR_EXPORT_VERSION >= 3
					if (rev_ARPropList(ctrl, a, "props", &(m->props)) == -1)
						return -1;
#else				/* 2.x */
					m->display = (ARDisplayStruct *) MALLOCNN(sizeof(ARDisplayStruct));
					if (rev_ARDisplayStruct_helper(ctrl, a, "display", m->display) == -1)
						return -1;
#endif
					return rv;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARFieldCharacteristics: hash value is not a hash reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
					    "rev_ARFieldCharacteristics: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
			   "rev_ARFieldCharacteristics: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		"rev_ARFieldCharacteristics: first argument is not a hash");
	return -1;
}

#if AR_EXPORT_VERSION >= 3
int
rev_ARPropList(ARControlStruct * ctrl, HV * h, char *k, ARPropList * m)
{
	if (!m || !h || !k) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARPropList: invalid (NULL) parameter");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			SV            **val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/*
				 * hash value should be an array reference.
				 * each hash will be a Prop Struct hash
				 */

				if (SvTYPE(SvRV(*val)) == SVt_PVAV) {
					AV             *a = (AV *) SvRV((SV *) * val);
					int             i;

					/*
					 * allocate space for field assign
					 * structure list
					 */

					m->numItems = av_len(a) + 1;
					if (m->numItems == 0)
						return 0;	/* nothing to do */

					m->props = (ARPropStruct *) MALLOCNN(sizeof(ARPropStruct) * m->numItems);

					/*
					 * iterate over the array, grabbing
					 * each hash reference out of it and
					 * passing that to a helper routine
					 * to fill in the Prop structure.
					 */

					for (i = 0; i <= av_len(a); i++) {
						SV            **av_hv = av_fetch(a, i, 0);

						if (av_hv && *av_hv && (SvTYPE(SvRV(*av_hv)) == SVt_PVHV)) {
							if (rev_ARPropList_helper(ctrl, (HV *) SvRV(*av_hv), m, i) != 0)
								return -1;
						} else
							ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
								    "rev_ARPropList: inner array value is not a hash reference");
					}
					return 0;

				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARPropList: hash value is not an array reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				  "rev_ARPropList: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "rev_ARPropList: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARPropList: first argument is not a hash");
	return -1;
}

static int
rev_ARPropList_helper(ARControlStruct * ctrl, HV * h, ARPropList * m, int idx)
{
	int             rv = 0;

	if (hv_exists(h,  "prop", strlen("prop") ) &&
	    hv_exists(h,  "value", strlen("value") ) &&
	    hv_exists(h,  "valueType", strlen("valueType") )) {

		rv += ulongcpyHVal(h, "prop", &(m->props[idx].prop));
		rv += rev_ARValueStruct(ctrl, h, "value", "valueType",
					&(m->props[idx].value));

		return rv;
	}
	ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		    "rev_ARPropList_helper: required hash keys not present (prop, value, valueType).");
	return -1;
}
#endif				/* 3.x */

int
rev_ARActiveLinkMacroStruct(ARControlStruct * ctrl,
			    HV * h, char *k, ARActiveLinkMacroStruct * m)
{
	if (!m || !h || !k) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		   "rev_ARActiveLinkMacroStruct: invalid (NULL) parameter");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			SV            **val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/* hash value should be a hash reference */

				if (SvTYPE(SvRV(*val)) == SVt_PVHV) {
					HV             *a = (HV *) SvRV((SV *) * val);
					return rev_ARActiveLinkMacroStruct_helper(ctrl, a, m);
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARActiveLinkMacroStruct: hash value is not a hash reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
					    "rev_ARActiveLinkMacroStruct: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
			  "rev_ARActiveLinkMacroStruct: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		"rev_ARActiveLinkMacroStruct: first argument is not a hash");
	return -1;
}

static int
rev_ARActiveLinkMacroStruct_helper(ARControlStruct * ctrl,
				   HV * h, ARActiveLinkMacroStruct * m)
{
	int             rv = 0;

	if (hv_exists(h,  "macroParms", strlen("macroParms") ) &&
	    hv_exists(h,  "macroText", strlen("macroText") ) &&
	    hv_exists(h,  "macroName", strlen("macroName") )) {

		rv += strcpyHVal(h, "macroName", m->macroName, sizeof(ARNameType));
		rv += strmakHVal(h, "macroText", &(m->macroText));
		rv += rev_ARMacroParmList(ctrl, h, "macroParms", &(m->macroParms));

		return 0;
	}
	ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		    "rev_ARActiveLinkMacroStruct_helper: required keys not present in hash (macroParms, macroText, macroName)");
	return -1;
}

int
rev_ARMacroParmList(ARControlStruct * ctrl, HV * h, char *k, ARMacroParmList * m)
{
	if (!h || !k || !*k || !m) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARMacroParmList: invalid parameter(s).");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			SV            **val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {

				/* hash value should be a hash reference */

				if (SvTYPE(SvRV(*val)) == SVt_PVHV) {
					HV             *a = (HV *) SvRV((SV *) * val);
					int             rv = 0, i, i2;
					SV             *hval;
					char           *hkey;
					I32             klen;

					/*
					 * the hash's keys are the names of
					 * the macroparm and the values are
					 * the value of the macroparm. both
					 * are pv's. so iterate over every
					 * key in the hash and populate the
					 * parms list with them.
					 */

					(void) hv_iterinit(a);
					for (i = 0; hv_iternext(a) != (HE *) NULL; i++);
					m->numItems = i;
					m->parms = (ARMacroParmStruct *) MALLOCNN(sizeof(ARMacroParmStruct)
							     * m->numItems);
					(void) hv_iterinit(a);
					i2 = 0;
					while ((hval = hv_iternextsv(a, &hkey, &klen))) {
						if (hval && SvPOK(hval)) {
							char           *vv = SvPV(hval, PL_na);
							int             vl = SvCUR(hval);

							if (i2 <= i) {
								(void) strncpy(m->parms[i2].name, hkey, sizeof(ARNameType));
								/* (void) copymem(m->parms[i2].value, vv, vl); */
								m->parms[i2].value = strdup( vv );
								i2++;
							} else {
								ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
									    "rev_ARMacroParmList: oops! more parms than i thought!");
								return -1;
							}
						} else {
							ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARMacroParmList: value for macro param is not a string. macro param name:");
							ARError_add(AR_RETURN_ERROR, AP_ERR_CONTINUE, hkey);
							rv = -1;
						}
					}
					return rv;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
						    "rev_ARMacroParmList: hash value is not a hash reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
					    "rev_ARMacroParmList: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				  "rev_ARMacroParmList: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
		       "rev_ARMacroParmList: first argument is not a hash");
	return -1;
}

#ifdef _WIN32
/* roll our own strcasecmp and strncasecmp for Win */

int 
strcasecmp(char *s1, char *s2)
{
	char           *p1, *p2;
	char            c1, c2;
	p1 = s1;
	p2 = s2;
	while ((*p1 != '\0') && (*p2 != '\0')) {
		c1 = tolower(*p1);
		c2 = tolower(*p2);
		if ((c1 - c2) == 0) {
			p2++;
			p1++;
		} else {
			return (c1 - c2);
		}
	}
	return *p1 - *p2;
}

int 
strncasecmp(char *s1, char *s2, size_t n)
{

	char           *p1, *p2;
	char            c1, c2;
	size_t          i = 0;
	p1 = s1;
	p2 = s2;

	while ((*p1 != '\0') && (*p2 != '\0') && (i <= n)) {
		c1 = tolower(*p1);
		c2 = tolower(*p2);
		if ((c1 - c2) == 0) {
			p2++;
			p1++;
		} else {
			return (c1 - c2);
		}
		i++;
	}
	return (i == n)? 0 : *p1 - *p2;
}

char*
arsperl_strdup( char *s1 ){
	char *p1;
	int len = strlen( s1 );
	p1 = MALLOCNN( len + 1 );
	strncpy( p1, s1, len );
	/* p1[len] = '\0'; */
	return p1;
}

#endif



int
rev_ARDisplayInstanceList(ARControlStruct * ctrl, HV * h, char *k, ARDisplayInstanceList * d)
{
	SV            **val;
	int             i;

	if (!d) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARDisplayInstanceList: DisplayInstanceList param is NULL");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {
				if (SvTYPE(SvRV(*val)) == SVt_PVHV) {
					val = hv_fetch( (HV*) SvRV(*val), "dInstanceList", strlen("dInstanceList"), 0 );

					if (val && *val) {
						/* hash value should be an array reference */
						if (SvTYPE(SvRV(*val)) == SVt_PVAV) {
							AV *ar = (AV *) SvRV((SV *) * val);

							/*
							 * allocate space for display
							 * structure list
							 */

							d->commonProps.numItems = 0;     /* TODO */
							d->commonProps.props    = NULL;  /* TODO */
							d->numItems = av_len(ar) + 1;
							if (d->numItems == 0)
								return 0;	/* nothing to do */
								
							/* d->dInstanceList = safemalloc(sizeof(ARDisplayInstanceStruct) * d->numItems); */
							d->dInstanceList = MALLOCNN(sizeof(ARDisplayInstanceStruct) * d->numItems);

							/*
							 * iterate over the array, grabbing
							 * each hash reference out of it and
							 * passing that to a helper routine
							 * to fill in the DisplayInstanceList
							 * structure
							 */

							for (i = 0; i <= av_len(ar); i++) {
								SV **av_hv = av_fetch(ar, i, 0);

								if (av_hv && *av_hv && (SvTYPE(SvRV(*av_hv)) == SVt_PVHV)) {
									if (rev_ARDisplayInstanceStruct(ctrl, (HV *) SvRV(*av_hv),
												&(d->dInstanceList[i])) != 0)
										return -1;
								} else
									ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
											"rev_ARDisplayInstanceList: inner array value is not a hash reference");
							}
							return 0;
						} else
							ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
									"rev_ARDisplayInstanceList: hash value is not an array reference");
					} else {
						ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
						"rev_ARDisplayInstanceList: hv_fetch returned null (dInstanceList)");
						return -2;
					}
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
							"rev_ARDisplayInstanceList: hash value is not a hash reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				"rev_ARDisplayInstanceList: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "rev_ARDisplayInstanceList: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			 "rev_ARDisplayInstanceList: first argument is not a hash");
	return -1;
}

int
rev_ARDisplayInstanceStruct(ARControlStruct *ctrl, HV *h, ARDisplayInstanceStruct *d){
	int rv = 0;	

	rv += ulongcpyHVal( h, "vui", &(d->vui) );
	/* printf( "vui=%d\n", d->vui ); */

	rv += rev_ARPropList( ctrl, h, "props", &(d->props) );
	/* printf( "props.numItems=%d\n", d->props.numItems ); */

	return rv;
}

int
rev_ARPermissionList(ARControlStruct * ctrl, HV * h, char *k, ARPermissionList * d)
{
	SV            **val;

	if (!d) {
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			    "rev_ARPermissionList: PermissionList param is NULL");
		return -1;
	}
	if (SvTYPE((SV *) h) == SVt_PVHV) {
		if (hv_exists(h,  k, strlen(k) )) {
			val = hv_fetch(h,  k, strlen(k) , 0);
			if (val && *val) {
				if (SvTYPE(SvRV(*val)) == SVt_PVHV) {
					HE *he;
					int i = 0;					

					d->numItems = hv_iterinit( (HV*) SvRV(*val) );
					/* d->permissionList = safemalloc(sizeof(ARPermissionStruct) * d->numItems); */
					d->permissionList = MALLOCNN(sizeof(ARPermissionStruct) * d->numItems);

					while( he = hv_iternext((HV*) SvRV(*val)) ){
						d->permissionList[i].groupId = atoi( HePV(he,PL_na) );
						if( HeVAL(he) && SvPOK(HeVAL(he)) ){
							d->permissionList[i].permissions
								= caseLookUpTypeNumber( (TypeMapStruct*) FieldPermissionTypeMap, SvPV_nolen(HeVAL(he)) );

							/* TS 18.08.05 */
							if( d->permissionList[i].permissions == TYPEMAP_LAST ){
								d->permissionList[i].permissions
									= caseLookUpTypeNumber( (TypeMapStruct*) SchemaPermissionTypeMap, SvPV_nolen(HeVAL(he)) );
							}
						}else{
							ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
									"rev_ARPermissionList: no permission type value");
							return -2;
						}
						++i; 
					}
					return 0;
				} else
					ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
							"rev_ARPermissionList: hash value is not a hash reference");
			} else {
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				"rev_ARPermissionList: hv_fetch returned null");
				return -2;
			}
		} else {
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL,
				    "rev_ARPermissionList: key doesn't exist");
			return -2;
		}
	} else
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL,
			 "rev_ARPermissionList: first argument is not a hash");
	return -1;
}




int
rev_ARReferenceStruct( ARControlStruct *ctrl, HV *h, char *k, ARReferenceStruct *p ){
	SV  **val;
	int i = 0;

	if( !p ){
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARReferenceStruct: AR Object param is NULL" );
		return -1;
	}

	if( SvTYPE((SV*) h) == SVt_PVHV ){

		// printf( "ARReferenceStruct: k = <%s>\n", k );
		if( hv_exists(h,k,strlen(k)) ){
			val = hv_fetch( h, k, strlen(k), 0 );
			if( val && *val ){
				{
				
					{
						char *pcase = NULL;
						char errText[512];
						SV **valDataType;
				
							// pcase = SvPV_nolen(*val);
							// p->reference.dataType = caseLookUpTypeNumber( (TypeMapStruct*) dataType, pcase );
							HV *h2 = (HV* ) SvRV((SV*) *val);
							valDataType = hv_fetch( h2, "dataType", 8, 0 );
							p->reference.dataType = SvIV(*valDataType);
				
				
							switch( p->reference.dataType ){
				
							case ARREF_DATA_ARSREF:
								{
								
								
									if( SvTYPE(SvRV(*val)) == SVt_PVHV ){
										int i = 0, num = 0;
										HV *h = (HV* ) SvRV((SV*) *val);
										char k[256];
										k[255] = '\0';
								
								
									{
										SV **val;
										strncpy( k, "name", 255 );
										val = hv_fetch( h, "name", 4, 0 );
										if( val	&& *val ){
											{
												strncpy( p->reference.u.name, SvPV_nolen(*val), sizeof(p->reference.u.name) );
											}
										}else{
											ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "hv_fetch error: key \"name\"" );
											return -1;
										}
									}
								
								
									}else{
										ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARReferenceStruct: hash value is not a hash reference" );
										return -1;
									}
								
								
								}
								break;
				
				
							case ARREF_DATA_EXTREF:
								{
								
								
									if( SvTYPE(SvRV(*val)) == SVt_PVHV ){
										int i = 0, num = 0;
										HV *h = (HV* ) SvRV((SV*) *val);
										char k[256];
										k[255] = '\0';
								
								
									{
										SV **val;
										strncpy( k, "permittedGroups", 255 );
										val = hv_fetch( h, "permittedGroups", 15, 0 );
										if( val	&& *val ){
											rev_ARInternalIdList( ctrl, h, k, &(p->reference.u.extRef.permittedGroups) );
										}else{
											ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "hv_fetch error: key \"permittedGroups\"" );
											return -1;
										}
									}
								
									{
										SV **val;
										strncpy( k, "value", 255 );
										val = hv_fetch( h, "value", 5, 0 );
										if( val	&& *val ){
											rev_ARValueStruct( ctrl, h, k, "value_dataType", &(p->reference.u.extRef.value) );
										}else{
											ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "hv_fetch error: key \"value\"" );
											return -1;
										}
									}
								
								
									}else{
										ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARReferenceStruct: hash value is not a hash reference" );
										return -1;
									}
								
								
								}
								break;
				
							default:
								sprintf( errText, "rev_ARReferenceStruct: invalid switch value %d", p->reference.dataType );
								ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, errText );
							}
				
					}
				
				
				
					if( SvTYPE(SvRV(*val)) == SVt_PVHV ){
						int i = 0, num = 0;
						HV *h = (HV* ) SvRV((SV*) *val);
						char k[256];
						k[255] = '\0';
				
				
					{
						SV **val;
						strncpy( k, "type", 255 );
						val = hv_fetch( h, "type", 4, 0 );
						if( val	&& *val ){
							{
								p->type = SvIV(*val);
							}
						}else{
							ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "hv_fetch error: key \"type\"" );
							return -1;
						}
					}
				
				
					{
						SV **val;
						strncpy( k, "label", 255 );
						val = hv_fetch( h, "label", 5, 0 );
						if( val	&& *val ){
							{
								p->label = strdup( SvPV_nolen(*val) );
							}
						}else{
							ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "hv_fetch error: key \"label\"" );
							return -1;
						}
					}
				
				
					{
						SV **val;
						strncpy( k, "description", 255 );
						val = hv_fetch( h, "description", 11, 0 );
						if( val	&& *val ){
							{
								p->description = strdup( SvPV_nolen(*val) );
							}
						}else{
							ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "hv_fetch error: key \"description\"" );
							return -1;
						}
					}
				
				
					}else{
						ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARReferenceStruct: hash value is not a hash reference" );
						return -1;
					}
				
				
				}
			}else{
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL, "rev_ARReferenceStruct: hv_fetch returned null");
				return -2;
			}
		}else{
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL, "rev_ARReferenceStruct: key doesn't exist");
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL, k );
			return -2;
		}
	}else{
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARReferenceStruct: first argument is not a hash");
		return -1;
	}

	return 0;
}


int
rev_ARCharMenuItemStruct( ARControlStruct *ctrl, HV *h, char *k, ARCharMenuItemStruct *p ){
	SV  **val;
	int i = 0;

	if( !p ){
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARCharMenuItemStruct: AR Object param is NULL" );
		return -1;
	}

	if( SvTYPE((SV*) h) == SVt_PVHV ){

		// printf( "ARCharMenuItemStruct: k = <%s>\n", k );
		if( hv_exists(h,k,strlen(k)) ){
			val = hv_fetch( h, k, strlen(k), 0 );
			if( val && *val ){
				{
				
					{
						char *pcase = NULL;
						char errText[512];
				
						HV *h;
						SV **hval = NULL;
						char *k   = NULL;
						if( SvTYPE(SvRV(*val)) != SVt_PVHV ){
							ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARCharMenuItemStruct: not a hash value" );
							return -1;
						}
						h = (HV* ) SvRV((SV*) *val);
				
							if( 0 ){
				
							}else if( hv_exists(h,"menuValue",9) ){
								p->menuType = AR_MENU_TYPE_VALUE;
								k = "menuValue";
				
				
							}else if( hv_exists(h,"childMenu",9) ){
								p->menuType = AR_MENU_TYPE_MENU;
								k = "childMenu";
				
							}else{
							    ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARCharMenuItemStruct: map error" );
							}
				
				
							switch( p->menuType ){
				
							case AR_MENU_TYPE_VALUE:
								{
								
								
									if( SvTYPE(SvRV(*val)) == SVt_PVHV ){
										int i = 0, num = 0;
										HV *h = (HV* ) SvRV((SV*) *val);
										char k[256];
										k[255] = '\0';
								
								
									{
										SV **val;
										strncpy( k, "menuValue", 255 );
										val = hv_fetch( h, "menuValue", 9, 0 );
										if( val	&& *val ){
											{
												p->u.menuValue = strdup( SvPV_nolen(*val) );
											}
										}else{
											ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "hv_fetch error: key \"menuValue\"" );
											return -1;
										}
									}
								
								
									}else{
										ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARCharMenuItemStruct: hash value is not a hash reference" );
										return -1;
									}
								
								
								}
								break;
				
				
							case AR_MENU_TYPE_MENU:
								{
								
								
									if( SvTYPE(SvRV(*val)) == SVt_PVHV ){
										int i = 0, num = 0;
										HV *h = (HV* ) SvRV((SV*) *val);
										char k[256];
										k[255] = '\0';
								
								
									{
										SV **val;
										strncpy( k, "childMenu", 255 );
										val = hv_fetch( h, "childMenu", 9, 0 );
										if( val	&& *val ){
											{
												p->u.childMenu = (ARCharMenuStruct*) MALLOCNN( sizeof(ARCharMenuStruct) );
												p->u.childMenu->menuType = AR_CHAR_MENU_LIST;
												rev_ARCharMenuList( ctrl, h, k, &(p->u.childMenu->u.menuList) );
											}
										}else{
											ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "hv_fetch error: key \"childMenu\"" );
											return -1;
										}
									}
								
								
									}else{
										ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARCharMenuItemStruct: hash value is not a hash reference" );
										return -1;
									}
								
								
								}
								break;
				
							default:
								sprintf( errText, "rev_ARCharMenuItemStruct: invalid switch value %d", p->menuType );
								ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, errText );
							}
				
					}
				
				
				
					if( SvTYPE(SvRV(*val)) == SVt_PVHV ){
						int i = 0, num = 0;
						HV *h = (HV* ) SvRV((SV*) *val);
						char k[256];
						k[255] = '\0';
				
				
					{
						SV **val;
						strncpy( k, "menuLabel", 255 );
						val = hv_fetch( h, "menuLabel", 9, 0 );
						if( val	&& *val ){
							{
								strncpy( p->menuLabel, SvPV_nolen(*val), sizeof(p->menuLabel) );
							}
						}else{
							ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "hv_fetch error: key \"menuLabel\"" );
							return -1;
						}
					}
				
				
					}else{
						ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARCharMenuItemStruct: hash value is not a hash reference" );
						return -1;
					}
				
				
				}
			}else{
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL, "rev_ARCharMenuItemStruct: hv_fetch returned null");
				return -2;
			}
		}else{
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL, "rev_ARCharMenuItemStruct: key doesn't exist");
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL, k );
			return -2;
		}
	}else{
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARCharMenuItemStruct: first argument is not a hash");
		return -1;
	}

	return 0;
}



#if AR_EXPORT_VERSION >= 8L
int
rev_ARArchiveInfoStruct( ARControlStruct *ctrl, HV *h, char *k, ARArchiveInfoStruct *p ){
	SV  **val;
	int i = 0;

	if( !p ){
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARArchiveInfoStruct: AR Object param is NULL" );
		return -1;
	}

	if( SvTYPE((SV*) h) == SVt_PVHV ){

		// printf( "ARArchiveInfoStruct: k = <%s>\n", k );
		if( hv_exists(h,k,strlen(k)) ){
			val = hv_fetch( h, k, strlen(k), 0 );
			if( val && *val ){
				{
				
					{
						char *pcase = NULL;
						char errText[512];
				
						HV *h;
						SV **hval = NULL;
						char *k   = NULL;
						if( SvTYPE(SvRV(*val)) != SVt_PVHV ){
							ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARArchiveInfoStruct: not a hash value" );
							return -1;
						}
						h = (HV* ) SvRV((SV*) *val);
				
						hval = hv_fetch( h, "archiveType", 11, 0 );
				

							if( hval && *hval ){
								p->archiveType = SvIV(*hval);                 
							}else{
								ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL, "rev_ARArchiveInfoStruct: hv_fetch (hval) returned null");
								return -2;
							}
				
				
							if( (p->archiveType & AR_ARCHIVE_FILE_ARX) != 0 ){
								{
								
								
									if( SvTYPE(SvRV(*val)) == SVt_PVHV ){
										int i = 0, num = 0;
										HV *h = (HV* ) SvRV((SV*) *val);
										char k[256];
										k[255] = '\0';
								
								
									{
										SV **val;
										strncpy( k, "dirPath", 255 );
										val = hv_fetch( h, "dirPath", 7, 0 );
										if( val	&& *val ){
											{
												p->u.dirPath = strdup( SvPV_nolen(*val) );
											}
										}else{
											ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "hv_fetch error: key \"dirPath\"" );
											return -1;
										}
									}
								
								
									}else{
										ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARArchiveInfoStruct: hash value is not a hash reference" );
										return -1;
									}
								
								
								}

							}else if( (p->archiveType & AR_ARCHIVE_FILE_XML) != 0 ){
								{
								
								
									if( SvTYPE(SvRV(*val)) == SVt_PVHV ){
										int i = 0, num = 0;
										HV *h = (HV* ) SvRV((SV*) *val);
										char k[256];
										k[255] = '\0';
								
								
									{
										SV **val;
										strncpy( k, "dirPath", 255 );
										val = hv_fetch( h, "dirPath", 7, 0 );
										if( val	&& *val ){
											{
												p->u.dirPath = strdup( SvPV_nolen(*val) );
											}
										}else{
											ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "hv_fetch error: key \"dirPath\"" );
											return -1;
										}
									}
								
								
									}else{
										ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARArchiveInfoStruct: hash value is not a hash reference" );
										return -1;
									}
								
								
								}

							}else if( (p->archiveType & (AR_ARCHIVE_FORM | AR_ARCHIVE_DELETE)) != 0 ){
								{
								
								
									if( SvTYPE(SvRV(*val)) == SVt_PVHV ){
										int i = 0, num = 0;
										HV *h = (HV* ) SvRV((SV*) *val);
										char k[256];
										k[255] = '\0';
								
								
									{
										SV **val;
										strncpy( k, "formName", 255 );
										val = hv_fetch( h, "formName", 8, 0 );
										if( val	&& *val ){
											{
												strncpy( p->u.formName, SvPV_nolen(*val), sizeof(p->u.formName) );
											}
										}else{
											ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "hv_fetch error: key \"formName\"" );
											return -1;
										}
									}
								
								
									}else{
										ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARArchiveInfoStruct: hash value is not a hash reference" );
										return -1;
									}
								
								
								}
							}else if( p->archiveType == AR_ARCHIVE_NONE ){				
								/* do nothing */
							}else{
								sprintf( errText, "rev_ARArchiveInfoStruct: invalid switch value %d", p->archiveType );
								ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, errText );
							}
				
					}
				
				
				
					if( SvTYPE(SvRV(*val)) == SVt_PVHV ){
						int i = 0, num = 0;
						HV *h = (HV* ) SvRV((SV*) *val);
						char k[256];
						k[255] = '\0';
				
				
					{
						SV **val;
						strncpy( k, "archiveFrom", 255 );
						val = hv_fetch( h, "archiveFrom", 11, 0 );
						if( val	&& *val && SvOK(*val) ){
							strncpy( p->archiveFrom, SvPV_nolen(*val), sizeof(p->archiveFrom) );
						}else{
							strcpy( p->archiveFrom, "" );
						}
					}
				
				
					{
						SV **val;
						strncpy( k, "query", 255 );
						val = hv_fetch( h, "query", 5, 0 );
						if( val	&& *val && SvOK(*val) ){
							rev_ARQualifierStruct( ctrl, h, k, &(p->query) );
						}else{
							p->query.operation = AR_COND_OP_NONE;
						}
					}
				
				
					{
						SV **val;
						strncpy( k, "enable", 255 );
						val = hv_fetch( h, "enable", 6, 0 );
						if( val	&& *val ){
							{
								int flag = 0;
								if( !strcmp(SvPV_nolen(*val),"true") ){
									p->enable = TRUE;
									flag = 1;
								}
								if( !strcmp(SvPV_nolen(*val),"false") ){
									p->enable = FALSE;
									flag = 1;
								}
								if( flag == 0 ){
									ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL,  "rev_ARArchiveInfoStruct: invalid key value" );
									ARError_add( AR_RETURN_ERROR, AP_ERR_CONTINUE, SvPV_nolen(*val) );
								}
							}
						}else{
							ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "hv_fetch error: key \"enable\"" );
							return -1;
						}
					}
				
				
					{
						SV **val;
						strncpy( k, "TmHourMask", 255 );
						val = hv_fetch( h, "TmHourMask", 10, 0 );
						if( val	&& *val ){
							{
								p->archiveTime.hourmask = SvIV(*val);
							}
						}else{
							ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "hv_fetch error: key \"TmHourMask\"" );
							return -1;
						}
					}
				
				
					{
						SV **val;
						strncpy( k, "TmWeekDayMask", 255 );
						val = hv_fetch( h, "TmWeekDayMask", 13, 0 );
						if( val	&& *val ){
							{
								p->archiveTime.weekday = SvIV(*val);
							}
						}else{
							ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "hv_fetch error: key \"TmWeekDayMask\"" );
							return -1;
						}
					}
				
				
					{
						SV **val;
						strncpy( k, "TmMinute", 255 );
						val = hv_fetch( h, "TmMinute", 8, 0 );
						if( val	&& *val ){
							{
								p->archiveTime.minute = SvIV(*val);
							}
						}else{
							ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "hv_fetch error: key \"TmMinute\"" );
							return -1;
						}
					}
				
				
					{
						SV **val;
						strncpy( k, "TmMonthDayMask", 255 );
						val = hv_fetch( h, "TmMonthDayMask", 14, 0 );
						if( val	&& *val ){
							{
								p->archiveTime.monthday = SvIV(*val);
							}
						}else{
							ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "hv_fetch error: key \"TmMonthDayMask\"" );
							return -1;
						}
					}
				
				
					}else{
						ARError_add( AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARArchiveInfoStruct: hash value is not a hash reference" );
						return -1;
					}
				
				
				}
			}else{
				ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL, "rev_ARArchiveInfoStruct: hv_fetch returned null");
				return -2;
			}
		}else{
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL, "rev_ARArchiveInfoStruct: key doesn't exist");
			ARError_add(AR_RETURN_WARNING, AP_ERR_GENERAL, k );
			return -2;
		}
	}else{
		ARError_add(AR_RETURN_ERROR, AP_ERR_GENERAL, "rev_ARArchiveInfoStruct: first argument is not a hash");
		return -1;
	}

	return 0;
}
#endif

