/**---------------------------------------------------------------------------
 ** 
 ** stat.c -- Extended statistics functions
 ** 
 ** Author          : Pierre Jaccard
 ** Created On      : 1999/07/15 13:39:52
 ** Last Modified By: Pierre Jaccard
 ** Last Modified On: 1999/07/16 20:33:24
 ** Update Count    : 4
 ** Directory       : /home/pego/pcd1/codas3c/gfi/src/libs/math/
 ** Version         : 0.0
 ** Status          : Unknown
 ** ---------------------------------------------------------------------- ** 
 ** DESCRIPTION: 
 ** 
 **    This file provides functions to calculate statistics on data. They are
 **    built on those defined in file vstat.c, but allow to calculate
 **    statistics on several variables at the same time. In addition, similar
 **    structure manipulation are available for lists of flags.
 ** 
 ** ---------------------------------------------------------------------- ** 
 ** REVISIONS: 
 ** ---------------------------------------------------------------------- ** 
 ** CHANGES: 
 **------------------------------------------------------------------------**/

#include "stat.h"

/* ------------------------------------------------------------------
   The folowing functions are local.
   ------------------------------------------------------------------ */

/* ------------------------------------------------------------------
   Insert a cell.
	 According to its input, this function determines whether a statistical cell
	 or flag element should be inserted in a new list. The following methods are
	 available:

	     0 : option is an ULONG. Only elements whose bits corresponding
			     to the code value in the reference list are set will be
					 inserted. In addition, all elements with a negative code value
					 in the reference list will be inserted.
				
			-1 : All elements of the reference list are inserted in the new list. 

	  RETURNS: 1 if current cell should be inserted in the new listt, 0 if not 
    ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
char insert_cell(/* code value of the variable from the reference list */
                 int def, 
                 /* variable to be used to determine if current element with
                    code value given by [[def]] should be inserted in the new
                    list */ 
                 char *option, 
                 /* code determining how to process the content of the option
                    parameter (see methods above). */ 
                 int code)
#else
char insert_cell(def, option, code)
int def;
char *option;
int code;
#endif
{

	char func[]="insert_cell";

	char insert=0;

	ULONG mask, bits;

	switch(code){
	case 0: 
		bits = *((ULONG *) option);
		mask = (ULONG) to_bit(def);
		insert = ((def < 0) || (bits & mask)) ? 1 : 0;
		break;
	case -1:
		insert = 1;
		break;
	default:
		warning_msg(func, "No initialization method defined for this code");
		break;
	}
	
	return(insert);

}

/* ------------------------------------------------------------------
	 Copies unistat list.

	 Given pointers to a reference unistat list and another one, copy the values
	 of this list into the other one. For strings, set only pointer values to
	 those of the reference list. By this way, sizeof(UNISTAT_LIST_TYPE) can
	 be used afterwards.

	 RETURNS: 0
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int copy_unistat_list(/* Destination */
                      UNISTAT_LIST_TYPE *u2, 
                      /* Source */
                      UNISTAT_LIST_TYPE *u1)
#else
int (u2, u1)
UNISTAT_LIST_TYPE *u2;
UNISTAT_LIST_TYPE *u1;
#endif
{

	u2->name    = u1->name;
	u2->format  = u1->format;
	u2->size    = u1->size;
	u2->options = u1->options;
	u2->code    = u1->code;
	u2->data    = u1->data;
	u2->stat    = u1->stat;

	return(0);

}

/* ------------------------------------------------------------------
	 Copy of a flag list.

	 Given pointers to a reference flag list and another one, copy the values
	 of this list into the other one. For strings, set only pointer values to
	 those of the reference list. By this way, sizeof(FLAG_LIST_TYPE) can
	 be used afterwards.

	 RETURNS: 0
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int copy_flag_list(/* Destination */
                   FLAG_LIST_TYPE *f2, 
                   /* Source */
                   FLAG_LIST_TYPE *f1)
#else
int copy_flag_list(f2, f1)
FLAG_LIST_TYPE *f2;
FLAG_LIST_TYPE *f1;
#endif
{

	f2->name    = f1->name;
	f2->size    = f1->size;
	f2->code    = f1->code;
	f2->flag    = f1->flag;

	return(0);
 
}

/* ------------------------------------------------------------------
   The next functions are available by external utilities
   ------------------------------------------------------------------ */

/* ------------------------------------------------------------------
	 Fully copies unistat list.

	 Given two pointers to unistat lists and a code value, a full copy of one
	 list is performed into the other one. If code is not BADINT, only
	 the elements corresponding to this code value are copied.

	 The lists must be initialized with the same settings, i.e. only data are
	 copied. 
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int full_copy_unistat_list(/* Destination list */
                           UNISTAT_LIST_TYPE *u2, 
                           /* Source list */
                           UNISTAT_LIST_TYPE *u1,
                           /* Code of variables to copy, or BADINT to copy all 
                              of them */
													 int code)
#else
int full_copy_unistat_list(u2, u1, code)
#endif
{

	UNISTAT_LIST_TYPE *src, *dst;
	UNISTAT_TYPE *s, *d;
	int i, j;
	

	/* Initializations */
	src = u1;
	dst = u2;

	/* Loop through the unistat elements */
	while(src->name != NULL){
		if((src->code == code) || (code == BADINT)){
			dst->size = min_val(src->size, dst->size);
			dst->options = src->options;
			dst->code = src->code;
			/* Loop through the data elements */
			for(i=0; i<(dst->size); i++)
				*(dst->data + i) = *(src->data + i);
			/* Loop through the unistat cells */
			for(i=0; i<(dst->size); i++){
				s = src->stat;
				d = dst->stat;
				d->n = min_val(s->n, d->n);
				d->n_increments = s->n_increments;
				d->options = s->options;
				/* Loop through each cell */
				for(j=0; j<(d->n); j++){
					*(d->sum + j) = *(s->sum + j);
					*(d->npts + j) = *(s->npts + j);
					if(s->options & U_VARIANCE)
						*(d->sumsq + j) = *(s->sumsq + j);
					if(s->options & U_EXTREMA){
						*(d->min + j) = *(s->min + j);
						*(d->max + j) = *(s->max + j);
					}
					if(s->options & U_INDICES){
						*(d->imin + j) = *(s->imin + j);
						*(d->imax + j) = *(s->imax + j);
					}
				}
			}
		}
		/* Update pointers */
		dst++;
		src++;
	}

	return(0);

}

/* ------------------------------------------------------------------
   Initialize unistat list.

	 Complete initialization of an unistat list according to the entries 
	 found in an UNISTAT_LIST_TYPE list.

   RETURNS: 0
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int init_unistat_array(/* List to initialize */
                       UNISTAT_LIST_TYPE *list)
#else
int init_unistat_array(list)
#endif
{

	char func[]="init_unistat_array";

	UNISTAT_TYPE *s;
	UNISTAT_LIST_TYPE *uni;
	double *d;
	int i;

	uni = list;
	while(uni->name != NULL){

		/* Allocate space for unistat variable */
		s = (UNISTAT_TYPE *) malloc(sizeof(UNISTAT_TYPE));
		if(s == NULL){
			error_msg(func, "Could not allocate space for unistat variable");
			return(INSUFFICIENT_MEMORY);
		}

		/* Update pointer in list */
		uni->stat = s;

		/* Allocate unistat cells */
		allocate_unistat(s, uni->size, uni->name, uni->options);

		/* Initialize unistat cells */
		zero_unistat(s);

		/* Allocate space for data array */
		d = (double *) calloc((size_t) uni->size, sizeof(double));
	
		/* Update pointer in list */
		uni->data = d;
	
		/* Initialize this space to bad */
		for(i=0; i<list->size; i++){
			*d = BADDOUBLE;
			d++;
		}
		
		/* Update list pointer */
		uni++;
	}

	return(0);

}

/* ------------------------------------------------------------------
	 Create and initialize an unistat list.

	 Create and initialize an unistat list from a reference definition list, and
	 according to a specific method. 

	     0 : option is an ULONG. Only elements whose bits corresponding
			     to the code value in the reference list are set will be
					 inserted.

	 RETURNS: pointer to the created list, or NULL if an error occured
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
char *init_unistat_list(/* reference list containing the definitions for the
                           list to create */ 
                        UNISTAT_LIST_TYPE *defs, 
                        /* variable to be used to determine which
                           elements of the reference list should be
                           inserted in the new list  */
                        char *option, 
                        /* code determining how the to process the content of
                           the option argument */ 
                        int code)
#else
char *init_unistat_list(defs, option, code)
UNISTAT_LIST_TYPE *defs;
char *option;
int code;
#endif
{

	char func[]="init_unistat_list";

	UNISTAT_LIST_TYPE *u1, *u2, *list;
	int n;

	/* Determine the number of valid elements in list.
		 NOTE: start with n=1, because of the element marking the end of the list
		 */
	u1 = defs;
	n = 1;
	while(u1->name != NULL){
		if(insert_cell(u1->code, option, code))
			n++;
		/* update pointer */
		u1++;
	}

	/* Allocate space for this list */
	list = (UNISTAT_LIST_TYPE *) calloc((size_t) n, sizeof(UNISTAT_LIST_TYPE));
	if(list == NULL){
		error_msg(func, "Could not initialize space for unistat list");
		return(NULL);
	}
	
	/* Initialize each of these unistat variables */
	u1 = defs;
	u2 = list;
	while(u1->name != NULL){
		if(insert_cell(u1->code, option, code)){
			copy_unistat_list(u2, u1);
			/* update pointer */
			u2++;
		}
		/* update pointer */
		u1++;
	}
	/* Do not forget the last element, closing the list */
	copy_unistat_list(u2, u1);

	/* Initialize the unistat cells fore ach variables */
	if(init_unistat_array(list)){
		error_msg(func, "while initializing unistat cells");
		return(NULL);
	}
	
	return((char *) list);

}

/* ------------------------------------------------------------------
	 Free an unistat List

	 Release all memory allocated for the entries in an UNISTAT_LIST_TYPE
	 list.

   RETURNS: 0
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int free_unistat_list(/* List to free */
                      UNISTAT_LIST_TYPE *list)
#else
int free_unistat_list(list)
#endif
{

	UNISTAT_LIST_TYPE *s;

	if(list == NULL)
		return(0);

	/* Free space allocated for each unistat cell */
	s = list;
	while(s->name != NULL){
		/* Free space for each unistat cell */
		free_unistat(s->stat);
		/* Free space for data arrays */
		free(s->data);
		/* Free space for unistat variable */
		free(s->stat);
		/* Initialize pointers */
		s->stat = NULL;
		s->data = NULL;
		/* Update pointer */
		s++;
	}

	return(0);

}

/* ------------------------------------------------------------------
	 Write an unistat header.
	 
	 Outputs a header description of statistical variables contained in an
	 unistat list. The header consists of a column number and variable's name.
	 Lines are commented out with a '%', so that output file can be loaded
	 inside matlab.

	 RETURNS: n  number of next column, after flag variables
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int fprintf_stat_header(/* Pointer to output file */
                        FILE *fp, 
                        /* List of unistat variables */
                        UNISTAT_LIST_TYPE *list, 
                        /* Column number to start writing from */
                        int n)
#else
int fprintf_stat_header(fp, list, n)
FILE *fp;
UNISTAT_LIST_TYPE *list;
int n;
#endif
{

	UNISTAT_LIST_TYPE *uni;

	uni = list;
	while(uni->name != NULL){
		fprintf(fp, "%% %3d : %s\n", n, uni->name);
		n++;
		/* Update pointer */
		uni++;
	}
	
	return(n);

}

/* ------------------------------------------------------------------
	 Write unistat data.

	 Print content of current unistat data, according to the information
	 contained in an unistat list. Since unistat variables inside a list may
	 have different sizes, it is not obvious to write a function doing this.
	 Therefore, this should be done in the main programme.
	 ------------------------------------------------------------------ */

/* ------------------------------------------------------------------
	 Zero unistat list.

	 Set to zero all statistical cells in an unistat list. If code is equal
	 to BADINT, then set statistical cells of all elements in the list to
	 zero.

   RETURNS: 0
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int zero_unistat_list(/* List to set to zero */
                      UNISTAT_LIST_TYPE *list, 
                      /* Code of variable to consider, or BADINT for all of
                         them */
                      int code)
#else
int zero_unistat_list(list, code)
#endif
{

	UNISTAT_LIST_TYPE *uni;
	int i;

	uni = list;
	while(uni->name != NULL){
		if((code == BADINT) || (uni->code == code)){
			for(i=0; i<(uni->size); i++)
				zero_unistat(uni->stat);
		}
		uni++;
	}

	return(0);

}

/* ------------------------------------------------------------------
	 Update an unistat list.

	 Update the unistat variable corresponding to code, or all variables if
	 code is equal to BADINT.

   RETURNS: 0
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int update_unistat_list(/* List to update */
                        UNISTAT_LIST_TYPE *list, 
                        /* Code of variable to update, or BADINT for all of
                           them */
                        int code)
#else
int update_unistat_list(list, code)
#endif
{

	UNISTAT_LIST_TYPE *uni;

	uni = list;
	while(uni->name != NULL){
		if((uni->code == code) || (code == BADINT))
			update_unistat_d(uni->stat, uni->data, uni->size);
		uni++;
	}

	return(0);

}

/* ------------------------------------------------------------------
	 Calculate an unistat list.

	 Calculate the unistat variable corresponding to code, or all variables
	 if code is equal to BADINT.

   RETURNS: 0
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int calculate_unistat_list(/* List to calculate */
                           UNISTAT_LIST_TYPE *list,
                           /* Variable to calculate, or BADINT for all of them 
                            */
                           int code)
#else
int calculate_unistat_list(list, code)
#endif
{

	UNISTAT_LIST_TYPE *uni;

	uni = list;
	while(uni->name != NULL){
		if((uni->code == code) || (code == BADINT))
			calculate_unistat(uni->stat);
		uni++;
	}

	return(0);

}

/* ------------------------------------------------------------------
	 Get an unistat list element.

	 This function returns the pointer to the element of an unistat list that
	 is identified by the specified code.

	 RETURNS: pointer to the element or NULL if not found.
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
char *get_unistat_element(/* List to serach element from */
                          UNISTAT_LIST_TYPE *list, 
                          /* Code of vsearched variable */
                          int code)
#else
char *get_unistat_element(list, code)
#endif
{

	UNISTAT_LIST_TYPE *uni;
	int done;

	done = 0;
	uni = list;
	while(!done && (uni->name != NULL)){
		done = (uni->code == code);
		uni++;
	}
	uni--;

	if(!done)
		return((char *) NULL);
	
	return((char *) uni);

}

/* ------------------------------------------------------------------
	 Write flag header:
	 
	 Outputs a header description of statistical variables contained in an
	 flag list. The header consists of a column number and variable's name.
	 Lines are commented out with a '%', so that output file can be loaded
	 inside matlab. If n is positive, only flags with a positive
	 identification code are printed. If n is negative, only flags with a
	 negative identification code are printed.

	 RETURNS: n number of next column, after flag variables
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int fprintf_flag_header(/* Pointer to output file */
                        FILE *fp, 
                        /* List of flags */
                        FLAG_LIST_TYPE *list, 
                        /* Column number to start writting from */
                        int n)
#else
int fprintf_flag_header(fp, list, n)
FILE *fp;
FLAG_LIST_TYPE *list;
int n;
#endif
{

	FLAG_LIST_TYPE *f;
	int m;

	/* Initializations */
	m = abs_val(n);

	f = list;
	while(f->name != NULL){
		if(((n < 0) && (f->code < 0)) || ((n >=0) && (f->code >= 0))){
			fprintf(fp, "%% %3d : %s\n", m, f->name);
			m++;
		}
		/* Update pointer */
		f++;
	}
	
	return(m);

}

/* ------------------------------------------------------------------
	 Full copy of a flag list.

	 Given two pointers to flag lists and a code, perform a full copy of one
	 list into the other one. If code is equal to BADINT, then all
	 elements of the list are copied, else only those corresponding to the code
	 value are copied.

	 Both lists must be initialized to the same settings, i.e. only data are
	 copied. 

   RETURNS: 0
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int full_copy_flag_list(/* Destination */
                        FLAG_LIST_TYPE *f2, 
                        /* Source */
                        FLAG_LIST_TYPE *f1, 
                        /* Code of variable to copy, or BADINT for all of them 
                         */
                        int code)
#else
int full_copy_flag_list()
#endif
{

	FLAG_LIST_TYPE *src, *dst;
	int i;
	
	/* Initializations */
	src = f1;
	dst = f2;

	/* Loop through the flag list */
	while(src->name != NULL){
		if((src->code == code) || (code == BADINT)){
			dst->size = min_val(src->size, dst->size);
			dst->code = src->code;
			/* Loop through the flags values */
			for(i=0; i<(dst->size); i++)
				*(dst->flag + i) = *(src->flag + i);
		}
		/* Update pointers */
		src++;
		dst++;
	}

	return(0);

}

/* ------------------------------------------------------------------
	 Set flags to bad.

	 Set all flags of a list of flags to BADBYTE.

   RETURNS: 0
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int set_bad_flags(/* List of flags */
                  FLAG_LIST_TYPE *list)
#else
int set_bad_flags(list)
#endif
{

	char func[]="set_bad_flags";

	FLAG_LIST_TYPE *f;
	int i;

	f = list;
	while(f->name != NULL){
		/* Check if flag has been initialized */
		if(f->flag == NULL){
			error_msg(func, "Flag pointer has not been initialized");
			return(READ_ERROR);
		}
		/* Set flag values to bad */
		for(i=0; i<(f->size); i++)
			*(f->flag + i) = BADBYTE;
		/* Update flag pointer */
		f++;
	}

	return(0);

}

/* ------------------------------------------------------------------
	 Set flags to zero.

	 Set all flags of a list of flags to zero. If code is equal to
	 BADINT, then set all flags. Else, only set those with the given code.

   RETURNS: 0
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int zero_flag_list(/* List of flags */
                   FLAG_LIST_TYPE *list, 
                   /* Code of flags to set to zero, or BADINT for all of them
                    */ 
                   int code)
#else
int zero_flag_list(list, code)
#endif
{

	char func[]="zero_flags";

	FLAG_LIST_TYPE *f;
	int i;

	f = list;
	while(f->name != NULL){
		/* Check if flag has been initialized */
		if(f->flag == NULL){
			error_msg(func, "Flag pointer has not been initialized");
			return(READ_ERROR);
		}
		/* Check if the code is the right one */
		if((code == BADINT) || (f->code == code)){
			/* Set flag values to bad */
			for(i=0; i<(f->size); i++)
				*(f->flag + i) = 0;
		}
		/* Update flag pointer */
		f++;
	}

	return(0);

}

/* ------------------------------------------------------------------
	 Initialize a list of flags.

	 Complete initialization of an array of flags, according to the entries in
	 the FLAG_LIST_TYPE list.

   RETURNS: 0
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int init_flag_array(/* List of flags */
                    FLAG_LIST_TYPE *list)
#else
int init_flag_array(list)
#endif
{

	char func[]="init_flag_array";

	FLAG_LIST_TYPE *f;
	BYTE *b;
	int error;

	f = list;
	while(f->name != NULL){

		/* Allocate space for flag array */
		b = (BYTE *) calloc((size_t) f->size, sizeof(BYTE));
		/* Update pointer in list */
		f->flag = b;
		/* update list pointer */
		f++;
	}
	
	/* Initialize this space to undefined */
	error = set_bad_flags(list);
	if(error){
		error_msg(func, "Attempting to initialize flag values");
		return(error);
	}

	return(0);

}

/* ------------------------------------------------------------------
	 Create and initialize a list of flags.

	 Initialize a whole list of flag arrays, according to a given code and
	 return the pointer to the list. The following codes are available:

	     0 : option is an ULONG. Only elements whose bits corresponding
			     to the code value in the reference list are set will be
					 inserted. In addition, all elements with a negative code in the
					 refernce list will also be inserted.

	 RETURNS: pointer to the created list, or NULL if an error occured
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
char *init_flag_list(/* reference list containing the definitions for the list
                        to create */ 
                     FLAG_LIST_TYPE *defs, 
                     /* variable to be used to determine which elements of the
                        reference list should be inserted in the new list  */ 
                     char *option, 
                     /* code determining how the to process the content of the
                        option variable */ 
                     int code)
#else
char *init_flag_list(defs, option, code)
FLAG_LIST_TYPE *defs;
char *option;
int code;
#endif
{

	char func[]="init_flag_list";

	FLAG_LIST_TYPE *f1, *f2, *list;
	int n;
		
	/* Determine the number of valid elements in list.
		 NOTE: start with n=1, because of the element marking the end of the list
		 */
	f1 = defs;
	n = 1;
	while(f1->name != NULL){
		if(insert_cell(f1->code, option, code))
			n++;
		/* update pointer */
		f1++;
	}

	/* Allocate space for this list */
	list = (FLAG_LIST_TYPE *) calloc((size_t) n, sizeof(FLAG_LIST_TYPE));
	if(list == NULL){
		error_msg(func, "Could not initialize space for unistat list");
		return(NULL);
	}
	
	/* Initialize each of these unistat variables */
	f1 = defs;
	f2 = list;
	while(f1->name != NULL){
		if(insert_cell(f1->code, option, code)){
			copy_flag_list(f2, f1);
			/* update pointer */
			f2++;
		}
		/* update pointer */
		f1++;
	}
	/* Do not forget the last element, closing the list */
	copy_flag_list(f2, f1);
	
	if(init_flag_array(list)){
		error_msg(func, "while initializing flag elements");
		return(NULL);
	}
	return((char *) list);

}

/* ------------------------------------------------------------------
	 Free a list of flags.

	 Release the memory allocated for the array of flags, described according to
	 the entries in the FLAG_LIST_TYPE list.
   
   RETURNS: 0
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int free_flag_list(/* Pointer to list of flags */
                   FLAG_LIST_TYPE *list)
#else
int free_flag_list(list)
#endif
{

	FLAG_LIST_TYPE *f;


	if(list == NULL)
		return(0);

	/* Free space allocated for each flag cell */
	f = list;
	while(f->name != NULL){
		/* Free space for each flag variable */
		free(f->flag);
		/* Initialize pointers */
		f->flag = NULL;
		/* Update pointer */
		f++;
	}

	return(0);

}

/* ------------------------------------------------------------------
	 Set a flag.

	 Set a specified flag in an array of flags, described by the
	 FLAG_LIST_TYPE list, to the given value.

   RETURN(0);
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int set_flag(/* List of flags */
             FLAG_LIST_TYPE *list, 
             /* Code specifying the flag */
             int code, 
             /* Index in flag array */
             int index, 
             /* Value of flag */
             BYTE value)
#else
int set_flag(list, code, index, value)
#endif
{

	char func[]="set_flag";

	FLAG_LIST_TYPE *f;

	f = list;
	while(f->name != NULL){
		if(f->code == code){
			if(index >= f->size){
				warning_msg(func, "Flag index is larger than flag array");
				return(-1);
			}
			*(f->flag + index) = value;
			return(0);
		}
		f++;
	}
	
	warning_msg(func, "No flag defined for this code");
	return(-1);
	
}

/* ------------------------------------------------------------------
	 Get a flag.

	 Get the value of a specified flag in an array of flags, described by the 
	 FLAG_LIST_TYPE list.

   RETURNS: the value of the given flag, or BADINT of not found.
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int get_flag(/* Pointer to list of flags */
             FLAG_LIST_TYPE *list, 
             /* Code of flag */
             int code, 
             /* Index in flag array */
             int index)
#else
int get_flag(list, code, index)
#endif
{

	char func[]="get_flag";

	FLAG_LIST_TYPE *f;

	f = list;
	while(f->name != NULL){
		if(f->code == code){
			if(index >= f->size){
				warning_msg(func, "Flag index is larger than flag array");
				return(-1);
			}
			return((int) *(f->flag + index));
		}
		f++;
	}

	warning_msg(func, "No flag defined for this code");
	return(BADINT);

}

/* ------------------------------------------------------------------
	 Get element of a flag list.

	 This function returns the pointer to the element of an unistat list that
	 is identified by the specified code.

	 RETURNS: pointer to element, or NULL if not found.
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
char *get_flag_element(/* List of flags */
                       FLAG_LIST_TYPE *list, 
                       /* Code of flag */
                       int code)
#else
char *get_flag_element(list, code)
#endif
{

	FLAG_LIST_TYPE *flag;
	int done;

	done = 0;
	flag = list;
	while(!done && (flag->name != NULL)){
		done = (flag->code == code);
		flag++;
	}
	flag--;

	if(!done)
		return((char *) NULL);
	
	return((char *) flag);

}











