/*===========================================================================
  Copyright (C) 1995-2009 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
..Type        Module
..NAME        tcr.c
..LANGUAGE    C
..AUTHOR      IPG-ESO Garching
..CATEGORY    table interface (old table system)
..COMMENTS

\begin{TeX}

This module contains the routines to handle table rows. 
Access to elements is done by column and row numbers. 
Elements in the table can be integer, float, double precision and
character string data types, as defined during the creation of the
columns. 
Implicit conversion of the element value is done automatically if the
input/output is done with a routine not corresponding to the data type.

The functions provided by this module are:

\begin{itemize}
\item Delete several elements in a row (TCRDEL),
\item Read several row elements  from the table (TCRRDx),
\item Write several row elements into the table (TCRWRx).
\end{itemize}

Main arguments used by the routines are:
\begin{description}
\item[column] sequential column number. Integer array defining 
           the set of columns to be considered.
\item[null] null flag. It is an array with a value TRUE if the 
           corresponding element is undefined, FALSE otherwise.
\item[row] sequential row number. It is an integer defining 
           the row number in the table or the symbols LAST, FIRST, NEXT 
           and PREVIOUS defined in the system file 'midas\_def.h' in the
           directory 'MID\_INCLUDE'. 
           The sequence number is the physical sequence number (by default)
           or the sequence corresponding to the index of the reference 
           column.
\item[tid] table identifier. It is an integer number provided by the
           system when the table is created or opened.
\item[value] row values. The type depends on the routine name.
           Implicit conversion is done if this type does not correspond
           to the column data type.
\end{description}

\end{TeX}

..VERSION     1.0 25-Mar-1987   Implementation     J.D. Ponz
..VERSION     1.1 21-Oct-1987   Modification of the calling sequence
..VERSION     1.2 11-Apr-1988   Modification of the calling sequence
..VERSION     1.3 11-Jan-1989   Include record file organization
..VERSION     1.4 16-Oct-1989   indexing (ifirst-1)
..VERSION  3.0 	01-Jul-1990   	New Version with Arrays / Elementary IO
				Added Routine TCRSEL
..VERSION  3.1 	27-Sep-1990   	Added TCRMAP TCRUMP
..VERSION  3.2 	18-Dec-1990: Take into account the number of selected rows.
..VERSION  3.3   02-May-1991  read null values as 0 in order to be compatible
                             with old application code MP
                30-Oct-1991  correct bug in TCRRDC (oscopy...)MP
                feb1992      modif of TCRRDC for DANET MP
                20-mAr-1992   correct bug in TCRRDC
                07-Oct-1992  Correct again a bug in TCRRDC

 090407		last modif
------------------------------------------------------------*/

#include <midas_def.h>		/* ANSI-C Prototyping 		*/
#include <tblsys.h>		/* Table System parameters	*/
#include <tbldef.h>		/* Symbols used for Tables	*/
#include <tblerr.h>		/* List of Table Errors		*/

#include <atype.h>		/* Character classification	*/
#include <macrogen.h>		/* Classical macros		*/

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

#include <math.h>		/* System Library		*/

static char col_sep = ' ';	/* Column separator for ASCII 	*/

#define CheckOverflow(tp,row)	(row <= tp->arows ? ERR_NORMAL :	\
				 TBL_ALLOROW(tid, row + row/5))

/*===================================================================
 *		Private Routines
 *===================================================================*/
#ifdef __STDC__
static int strloc(char *str, char c)
#else
static int strloc(str, c)
/*+++++++
..PURPOSE Locate the first occurence of character `c'
..RETURNS Index of `c' in str; length of str if `c' not found.
---------*/
	char *str;	/* IN: string to scan	*/
	char c;		/* IN: char to locate	*/
#endif
{
	register char *p;

  for (p=str; *p && (*p != c); p++) ;
  return(p-str);
}

#ifdef __STDC__
static int check_cols(TABLE *tp, int nc, int *column)
#else
static int check_cols(tp, nc, column)
/*+++++++
..PURPOSE Check if row / colums are OK
..RETURNS Status
---------*/
	TABLE	*tp			/* IN : table ptr	*/;
	int	nc 			/* IN : number of cols.	*/;
	int	column[]		/* IN : column numbers	*/;
#endif
{
	int	status, i, icol;
	
  for (i = 0, status = ERR_NORMAL; (status == ERR_NORMAL) && (i < nc); i++) {
    	icol = column[i];
	if ((icol<=0) || (icol>tp->cols)) 
		status = TBL_errf(ERR_TBLCOL, 
		"bad column number #array[%d]=%d, table: %s",
		i+1, icol, tp->phname);
  }
  return(status);
}

/*=======================================================================
 *		Public Routines
 *=======================================================================*/

int TCRDEL(tid, row)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
..PURPOSE
		Deletes all element in the row.
..ALGORITHM	
		uses TCEDEL.
..RETURNS
                Status
-------------------------------------------------------------*/
	int	tid			/* IN : table id	*/;
	int	row			/* IN : row number 	*/;

{
	TABLE	*tp;
	int	status;
  	int	i;

                       				/* checks arguments	*/
  tp = TBL_ptr(tid);
  if ((status = CheckTable(tp)))		return(TBL_errs(tid, status,0));
  if ((status = CheckRow(tp, row)))	return(TBL_errs(tid, status, row));


			/*     Loop on TCEDEL (Delete Element)	*/
  for (i = 1; (status == ERR_NORMAL) && (i <= tp->cols); i++)   
  	status = TCEDEL(tid, row, i);

			/* Delete the Selection Column		*/

  return (status);
}

int TCRRDC(tid, row, nc, column, value, null)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
..PURPOSE
		Reads table row as a character string.
..ALGORITHM	
                Access each single row element with implicit type conversion.
..RETURNS
		status
-------------------------------------------------------------*/
	int	tid			/* IN : table id	*/;
	int	row			/* IN : row number 	*/;
	int	nc 			/* IN : number of cols.	*/;
	int	column[]		/* IN : column numbers	*/;
	char	value[]			/* OUT: actual value	*/;
	int	null[] 			/* OUT: null flag	*/;
{
	TABLE	*tp;
	int	status, items, mylen;
	int	ic, icol, icol1, nbytes, dtype, i, j, k, len, dummy, len0;
	char  	*p, *x, form[10], form0[10], ws[4];

                       				/* checks arguments	*/
  tp = TBL_ptr(tid);
  if ((status = CheckTable(tp)))	return(TBL_errs(tid, status,0));
  if (row < 1)			return(TBL_errs(tid, ERR_TBLROW, row));

  mylen = strlen(value);
  for (i = 0; i<mylen; i++) value[i] = '\0';
				/* Don't use check function, col#0 valid */
  for (i = 0; (status == ERR_NORMAL) && (i < nc); i++) {
    	icol = column[i];
	if (icol == 0) {
		TCFGET (tid, icol, form0, &len0, &dummy);
		continue;
	}
	if ((icol<0) || (icol>tp->cols)) {
		status = ERR_TBLCOL;
		TBL_errf(status, "bad column number #array[%d]=%d, table: %s",
			i+1, icol, tp->phname);
		continue;
	}
	if (! (*ColumnFormat(tp, icol)))
		status = TCFGET (tid, icol, form, &dummy, &dummy);
  }
  if (status)		return(status);

					/* Execute Edition for types	*/
  p = value;
  for (i = 0; (status == ERR_NORMAL) && (i < nc); p += len, i++) {
	*(p++) = col_sep;
	icol  = column[i];
	if (icol == 0)	{
		len = len0;
		dummy = row;
		TBL_ed (p, form0, (TBL_D_I4<<TBL_D_BITS)|1, (char *)&dummy);
		continue;
	}
	icol1 = icol - 1;
  	nbytes= tp->bytes[icol1];
	dtype = tp->dtypes[icol1];
	items = TBL_Items(dtype);
	if ((dtype & (~TBL_D_MASK)) == 0) {
            GetLabel(tp,icol,39,3,ws);
            ws[3] = '\0';
            items = atoi(ws);
            if (items == 0) items = 1; 
            nbytes = nbytes/items;
            }
	len   = tp->abytes[icol1];
	if (dtype & (~TBL_D_MASK))
		len = (len+1)*items - 1;
	ic    = TBL_offset(tp, row, icol);
	if (row > tp->rows)  {
     		null[i] = 1;
     		oscfill (p, len, ' ');
     		continue;
     	}
	if_not(x = TBL_RD (tp, ic, nbytes))
		{ status = TBL_RDst(); continue; }

	null[i] = TBL_isNULL(dtype, (int *)x);
/*     		oscfill (p, len, ' ');
                if (dtype & (~TBL_D_MASK)) p[len-1] = '*';
     		continue;
     	} */

	if ((dtype & (~TBL_D_MASK)) == 0) {	/* Byte String. Copy	*/
                for (j=1; j<=items; j++) {
                     if (len <= nbytes) oscopy(p, x, len);
                     else  oscopy(p, x, nbytes);      
                     if (items > 1 && j != items) {
                      x += nbytes;
                      k = 0;
                      /*while (k++ < MIN(len,nbytes) && *p) p++;*/
                      TBL_s1(p,len);
                       p += MIN(len,nbytes); 
                      (*p++) = ',';
                      }
                     else TBL_s1(p,len);
                   }
		continue;
	}
						/* Convert bin -> ascii	*/
	TBL_ed (p, tp->format + icol1*(1+TBL_FORLEN), dtype, x);
  }
  *p = '\0';
  return (status);
}

int TCRRDD(tid, row, nc, column, value, null)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
..PURPOSE
		Reads table row as a double precision array.
..ALGORITHM	
                Access each single row element with implicit type conversion.
..RETURNS
		status
-------------------------------------------------------------*/
	int	tid			/* IN : table id	*/;
	int	row			/* IN : row number 	*/;
	int	nc 			/* IN : number of cols.	*/;
	int	column[]		/* IN : column numbers	*/;
	double	value[]			/* OUT: actual value	*/;
	int	null[] 			/* OUT: null flag	*/;
{
	TABLE	*tp;
	int	status;
	int	ic, icol, icol1, nbytes, dtype, i;
	char  	*x;

                       				/* checks arguments	*/
  tp = TBL_ptr(tid);
  if ((status = CheckTable(tp)))	return(TBL_errs(tid, status,0));
  if (row < 1)			return(TBL_errs(tid, ERR_TBLROW, row));
  if ((status = check_cols(tp, nc, column)))	return(status);

					/* Execute Edition for types	*/
  for (i = 0; (status == ERR_NORMAL) && (i < nc); i++) {
	icol  = column[i];
	icol1 = icol - 1;
  	nbytes= tp->bytes[icol1];
	if (row > tp->rows)  {
     		null[i] = 1;
/*		TBL_toNULL ((TBL_D_R8<<TBL_D_BITS)|1, &value[i]);  */
                value[i] = 0;
     		continue;
     	}
	ic    = TBL_offset(tp, row, icol);
	dtype = tp->dtypes[icol1];
	if_not (x = TBL_RD (tp, ic, nbytes))
		{ status = TBL_RDst(); continue;}

	if ((null[i] = TBL_isNULL(dtype, (int *)x))) {
/*		TBL_toNULL ((TBL_D_R8<<TBL_D_BITS)|1, &value[i]); */
                value[i] = 0;
     		continue;
     	}

	switch (TBL_ElementType(dtype)) {
    	    case TBL_D_A1:	
    		status = TBL_cv(x, "E15.6", (TBL_D_R8<<TBL_D_BITS)|1, (char *)&value[i]);
		break;
	    case TBL_D_I1:	value[i] = *x;			break;
	    case TBL_D_A2:	value[i] = *(unsigned short *)x;break;
	    case TBL_D_I2:	value[i] = *(short *)x;		break;
	    case TBL_D_A4:	value[i] = *(unsigned int *)x;	break;
	    case TBL_D_I4:	value[i] = *(int *)x;		break;
	    case TBL_D_R8:	value[i] = *(double *)x;	break;
	    case TBL_D_R4:	value[i] = *(float *)x;		break;
	}
  }

  return (status);
}

int TCRRDI(tid, row, nc, column, value, null)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
..PURPOSE
		Reads table row as in integer array.
..ALGORITHM	
                Access each single row element with implicit type conversion.
..RETURNS
		status
-------------------------------------------------------------*/
	int	tid			/* IN : table id	*/;
	int	row			/* IN : row number 	*/;
	int	nc 			/* IN : number of cols.	*/;
	int	column[]		/* IN : column numbers	*/;
	int	value[]			/* OUT: actual value	*/;
	int	null[] 			/* OUT: null flag	*/;
{
	TABLE	*tp;
	int	status;
	int	ic, icol, icol1, nbytes, dtype, i;
	char  	*x;

                       				/* checks arguments	*/
  tp = TBL_ptr(tid);
  if ((status = CheckTable(tp)))	return(TBL_errs(tid, status,0));
  if (row < 1)			return(TBL_errs(tid, ERR_TBLROW, row));
  if ((status = check_cols(tp, nc, column)))	return(status);

					/* Execute Edition for types	*/
  for (i = 0; (status == ERR_NORMAL) && (i < nc); i++) {
	icol  = column[i];
	icol1 = icol - 1;
  	nbytes= tp->bytes[icol1];
	if (row > tp->rows)  {
     		null[i] = 1;
                /* TBL_toNULL ((TBL_D_I4<<TBL_D_BITS)|1, &value[i]); */
                value[i] = 0;
     		continue;
     	}
	dtype = tp->dtypes[icol1];
	ic    = TBL_offset(tp, row, icol);
	if_not(x = TBL_RD (tp, ic, nbytes))	
		{ status = TBL_RDst(); continue; }

	if ((null[i] = TBL_isNULL(dtype, (int *)x))) {
               /* TBL_toNULL ((TBL_D_I4<<TBL_D_BITS)|1, &value[i]); */
                value[i] = 0;
     		continue;
     	}

  	switch (TBL_ElementType(dtype)) {
	    case TBL_D_A1:			 /* character string */
    		status = TBL_cv(x, "I12", (TBL_D_I4<<TBL_D_BITS)|1, (char *)&value[i]);
		break;
	    case TBL_D_I1:	value[i] = *x;			break;
	    case TBL_D_A2:	value[i] = *(unsigned short *)x;break;
	    case TBL_D_I2:	value[i] = *(short *)x;		break;
	    case TBL_D_A4:	value[i] = *(unsigned int *)x;	break;
	    case TBL_D_I4:	value[i] = *(int *)x;		break;
	    case TBL_D_R8:	value[i] = NINT(*(double *)x);	break;
	    case TBL_D_R4:	value[i] = NINT(*(float *)x);	break;
	}
  }

  return (status);
}

int TCRRDR(tid, row, nc, column, value, null)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
..PURPOSE
		Reads table row as floating point array.
..ALGORITHM	
                Access each single row element with implicit type conversion.
..RETURNS
		status
-------------------------------------------------------------*/
	int	tid			/* IN : table id	*/;
	int	row			/* IN : row number 	*/;
	int	nc 			/* IN : number of cols.	*/;
	int	column[]		/* IN : column numbers	*/;
	float	value[]			/* OUT: actual value	*/;
	int	null[] 			/* OUT: null flag	*/;
{
	TABLE	*tp;
	int	status;
	int	ic, icol, icol1, nbytes, dtype, i;
	char  	*x;

                       				/* checks arguments	*/
  tp = TBL_ptr(tid);
  if ((status = CheckTable(tp)))	return(TBL_errs(tid, status,0));
  if (row < 1)			return(TBL_errs(tid, ERR_TBLROW, row));
  if ((status = check_cols(tp, nc, column)))	return(status);

					/* Execute Edition for types	*/
  for (i = 0; (status == ERR_NORMAL) && (i < nc); i++) {
	icol  = column[i];
	icol1 = icol - 1;
  	nbytes= tp->bytes[icol1];
	if (row > tp->rows)  {
     		null[i] = 1;
/*		TBL_toNULL ((TBL_D_R4<<TBL_D_BITS)|1, &value[i]); */
                value[i] = 0;
     		continue;
     	}
	ic    = TBL_offset(tp, row, icol);
	dtype = tp->dtypes[icol1];
	if_not(x = TBL_RD (tp, ic, nbytes))	
		{ status = TBL_RDst(); continue; }

	if ((null[i] = TBL_isNULL(dtype, (int *)x))) {
/*		TBL_toNULL ((TBL_D_R4<<TBL_D_BITS)|1, &value[i]);*/
                value[i] = 0;
     		continue;
     	}

  	switch (TBL_ElementType(dtype)) {
	    case TBL_D_A1:			 /* character string */
    		status = TBL_cv(x, "E15.6", (TBL_D_R4<<TBL_D_BITS)|1, (char *)&value[i]);
		break;
	    case TBL_D_I1:	value[i] = *x;			break;
	    case TBL_D_I2:	value[i] = *(short *)x;		break;
	    case TBL_D_I4:	value[i] = *(int *)x;		break;
	    case TBL_D_A2:	value[i] = *(unsigned short *)x;break;
	    case TBL_D_A4:	value[i] = *(unsigned int *)x;	break;
	    case TBL_D_R8:	value[i] = *(double *)x;	break;
	    case TBL_D_R4:	value[i] = *(float *)x;		break;
	}
  }

  return (status);
}

int TCRSEL(tid, text, max_ranges, lower_bounds, upper_bounds, found_ranges)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
..PURPOSE
		Select Ranges defined over the rows.
..ALGORITHM	
		A set of rows has the general syntax 
		range[,range]...
		
		where "range" is @lower_row[..[upper_row]]
		
		Example:   @1..10,@20,@100..    for rows number 1 to 10, 20 
						and over 100

..RETURNS
		Status
-------------------------------------------------------------*/
	int	tid		/* IN : table id	*/;
	char	*text		/* IN : textual designation */;
	int	max_ranges	/* IN: Size of lower& upper bound arrays */;
	int	*lower_bounds	/* OUT: lower bounds of found ranges	*/;
	int	*upper_bounds	/* OUT: upper bounds of found ranges	*/;
	int	*found_ranges	/* OUT: How many ranges were found */;
{     
	TABLE	*tp;
	int	status, i;
	char	*p, *pa, b, c;
	int	j, ic, ib;


                       				/* checks arguments	*/
  tp = TBL_ptr(tid);
  if ((status = CheckTable(tp)))	return(TBL_errs(tid, status,0));

				/* Tokenize from commas, then from ..	*/
  for (j=0, p=text; (*p) && (j < max_ranges) && (status == ERR_NORMAL); j++) {
	if (*p == '@')	p++;
	pa = p;
	ic = strloc (p, ',');	c = p[ic]; p[ic] = '\0';
	for (ib=0; (p[ib]) && isdigit(p[ib]); ib++)   ;
				b = p[ib]; p[ib] = '\0';
	i = atoi(p);
	upper_bounds[j] = lower_bounds[j] = i;
/*      if ((i < 1) || (i > tp->arows)) 
		status = TBL_errf(ERR_TBLROW, 
		"bad row selection @%s outside range [1..%d], table: %s",
		pa, tp->arows, tp->phname); */
	if (b) {
		p += ib; ic -= ib;
		*p = b;	 
		if ((p[0] = '.') && (p[1] == '.')) {
			p += 2; ic -= 2;
			i = atoi(p);
			if (i == 0)	i = tp->rows;
			upper_bounds[j] = i;
/*                              if ((i < 1) || (i > tp->arows)) 
				status = TBL_errf(ERR_TBLROW, 
				"bad row selection @%s outside range [1..%d], table: %s",
				pa, tp->arows, tp->phname);  */
  			if (i < lower_bounds[j])
  				upper_bounds[j] = lower_bounds[j],
  				lower_bounds[j] = i;
		}
		else	status = TBL_errf(ERR_TBLROW, 
			"bad punctuation in @%s, table: %s", pa, tp->phname);
	}
	p += ic;  *p = c;
	if (c)	p++;
  }

  *found_ranges = j;

  return (status);
}

int TCRWRC(tid, row, nc, column, value)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
..PURPOSE
		Writes table row
..ALGORITHM	
                Access each row element with implicit type conversion.
..RETURNS
		status
-------------------------------------------------------------*/
	int	tid			/* IN : table id	*/;
	int	row			/* IN : row number 	*/;
	int	nc 			/* IN : number of cols.	*/;
	int	column[]		/* IN : column numbers	*/;
	char	value[]			/* IN : values to write	*/;
{
	TABLE	*tp;
	int	status;
	int	ic, icol, icol1, nbytes, dtype, i, len, dummy;
	char  	*p, *x, form[10];

                       				/* checks arguments	*/
  tp = TBL_ptr(tid);
  if ((status = CheckTable(tp)))	return(TBL_errs(tid, status,0));
  if (row < 1)			return(TBL_errs(tid, ERR_TBLROW, row));

				/* Don't use local check, col#0 valid	*/
  for (i = 0; (status == ERR_NORMAL) && (i < nc); i++) {
    	icol = column[i];
	if ((icol<=0) || (icol>tp->cols)) 
		status = TBL_errf(ERR_TBLCOL, 
		"bad column number #array[%d]=%d, table: %s",
		i+1, icol, tp->phname);
	if (! (*ColumnFormat(tp, icol)))
		status = TCFGET (tid, icol, form, &dummy, &dummy);
  }
  if (status)		return(status);

					/* check if row overflow */
  if ((status = CheckOverflow(tp,row)))	return(status);
  tp = TBL_ptr(tid);		
  if (row > tp->rows) 	tp->selected = row, tp->rows = row;   


				/* read value with intrinsic type */
  p = value;
  for (i = 0; (status == ERR_NORMAL) && (i < nc); i++) {
	icol  = column[i];
	status = TCFGET (tid, icol, form, &dummy, &dummy);
	icol1 = icol - 1;
  	nbytes= tp->bytes[icol1];
	len   = tp->abytes[icol1];
	dtype = tp->dtypes[icol1];
	ic    = TBL_offset(tp, row, icol);
	if_not( x = TBL_RDF (tp, ic, nbytes, 1))
		{ status = TBL_RDst(); continue; }

	dummy  = p[len]; p[len] = '\0';
	status = TBL_cv(p, form, dtype, x);
	p += len;
 	*p = dummy;
  }

  return (status);
}

int TCRWRD(tid, row, nc, column, value)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
..PURPOSE
		Writes table row from a double precision array.
..ALGORITHM	
                Access each row element with implicit type conversion.
..RETURNS
		status
-------------------------------------------------------------*/
	int	tid			/* IN : table id	*/;
	int	row			/* IN : row number 	*/;
	int	nc 			/* IN : number of cols.	*/;
	int	column[]		/* IN : column numbers	*/;
	double	value[]			/* IN : array with values */;
{
	TABLE	*tp;
	int	status;
	int	ic, icol, icol1, nbytes, dtype, i;
	char  	*x;
	char	form[9], edited[32];

                       				/* checks arguments	*/
  tp = TBL_ptr(tid);
  if ((status = CheckTable(tp)))	return(TBL_errs(tid, status,0));
  if (row < 1)			return(TBL_errs(tid, ERR_TBLROW, row));
  if ((status = check_cols(tp, nc, column)))	return(status);

					/* check if row overflow */
  if ((status = CheckOverflow(tp,row)))		return(status);
  tp = TBL_ptr(tid);		/* Might be changed by overflow	*/
  if (row > tp->rows) 	tp->selected = row, tp->rows = row;   


				/* read value with intrinsic type */
  for (i = 0; (status == ERR_NORMAL) && (i < nc); i++) {
	icol  = column[i];
	icol1 = icol - 1;
  	nbytes= tp->bytes[icol1];
	dtype = tp->dtypes[icol1];
	ic    = TBL_offset(tp, row, icol);
	if_not(x = TBL_RDF (tp, ic, nbytes, 1))
		{ status = TBL_RDst(); continue; }

  	switch (TBL_ElementType(dtype)) {
	    case TBL_D_A1:				 /* character string */
		form[0] = '%';
		if (nbytes < 7)	
			form[1] = 'f', form[2] = '\0';
		else 	sprintf(form+1, "%d.%de", MIN(22,nbytes), MIN(15, nbytes-7));
		sprintf(edited, form, value[i]);
		status = TCEWRC (tid, row, icol, edited);
								  	break;
	    case TBL_D_I1:	*x = NINT(value[i]);			break;
	    case TBL_D_A2:	*(unsigned short *)x = NINT(value[i]);	break;
	    case TBL_D_I2:	*(short *)x = NINT(value[i]);		break;
	    case TBL_D_A4:
	    case TBL_D_I4:	*(int *)x = NINT(value[i]);		break;
	    case TBL_D_R8:	*(double *)x = value[i];		break;
	    case TBL_D_R4:	*(float *)x = value[i];			break;
	}
  }

  return (status);
}

int TCRWRI(tid, row, nc, column, value)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
..PURPOSE
		Writes table row from an integer array of values.
..ALGORITHM	
                Access each row element with implicit type conversion.
..RETURNS
		status
-------------------------------------------------------------*/
	int	tid			/* IN : table id	*/;
	int	row			/* IN : row number 	*/;
	int	nc 			/* IN : number of cols.	*/;
	int	column[]		/* IN : column numbers	*/;
	int	value[]			/* IN : data array	*/;
{
	TABLE	*tp;
	int	status;
	int	ic, icol, icol1, nbytes, dtype, i;
	char	*x;
	char	edited[16];


                       				/* checks arguments	*/
  tp = TBL_ptr(tid);
  if ((status = CheckTable(tp)))	return(TBL_errs(tid, status,0));
  if (row < 1)			return(TBL_errs(tid, ERR_TBLROW, row));
  if ((status = check_cols(tp, nc, column)))	return(status);

					/* check if row overflow */
  if ((status = CheckOverflow(tp,row)))	return(status);
  tp = TBL_ptr(tid);		/* Might be changed by overflow	*/
  if (row > tp->rows) 	tp->selected = row, tp->rows = row;   


				/* read value with intrinsic type */
  for (i = 0; (status == ERR_NORMAL) && (i < nc); i++) {
	icol  = column[i];
	icol1 = icol - 1;
  	nbytes= tp->bytes[icol1];
	dtype = tp->dtypes[icol1];
	ic    = TBL_offset(tp, row, icol);
	if_not( x = TBL_RDF (tp, ic, nbytes, 1))
		{ status = TBL_RDst(); continue; }

  	switch (TBL_ElementType(dtype)) {
	    case TBL_D_A1:		  		 /* character string */
		sprintf(edited, "%d", value[i]);
		status = TCEWRC (tid, row, icol, edited);
								break;
	    case TBL_D_I1:	*x = value[i];			break;
	    case TBL_D_A2:	*(unsigned short *)x = value[i];break;
	    case TBL_D_I2:	*(short *)x = value[i];		break;
	    case TBL_D_A4:	
	    case TBL_D_I4:	*(int *)x = value[i];		break;
	    case TBL_D_R8:	*(double *)x = value[i];	break;
	    case TBL_D_R4:	*(float *)x = value[i];		break;
	}
  }

  return (status);
}

int TCRWRR(tid, row, nc, column, value)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
..PURPOSE
		Writes table row from a floating point data array.
..ALGORITHM	
                Access each row element with implicit type conversion.
..RETURNS
		status
-------------------------------------------------------------*/
	int	tid			/* IN : table id	*/;
	int	row			/* IN : row number 	*/;
	int	nc 			/* IN : number of cols.	*/;
	int	column[]		/* IN : column numbers	*/;
	float	value[]			/* IN : data array	*/;
{
	TABLE	*tp;
	int	status;
	int	ic, icol, icol1, nbytes, dtype, i;
	char  	*x;
	char	form[9], edited[32];

                       				/* checks arguments	*/
  tp = TBL_ptr(tid);
  if ((status = CheckTable(tp)))	return(TBL_errs(tid, status,0));
  if (row < 1)			return(TBL_errs(tid, ERR_TBLROW, row));
  if ((status = check_cols(tp, nc, column)))	return(status);

					/* check if row overflow */
  if ((status = CheckOverflow(tp,row)))	return(status);
  tp = TBL_ptr(tid);		/* Might be changed by overflow	*/
  if (row > tp->rows) 	tp->selected = row, tp->rows = row;   


				/* read value with intrinsic type */
  for (i = 0; (status == ERR_NORMAL) && (i < nc); i++) {
	icol  = column[i];
	icol1 = icol - 1;
  	nbytes= tp->bytes[icol1];
	dtype = tp->dtypes[icol1];
	ic    = TBL_offset(tp, row, icol);
	if_not (x = TBL_RDF (tp, ic, nbytes, 1))
		{ status = TBL_RDst(); continue; }

  	switch (TBL_ElementType(dtype)) {
	    case TBL_D_A1:				 /* character string */
		form[0] = '%';
		if (nbytes < 7)	
			form[1] = 'f', form[2] = '\0';
		else 	sprintf(form+1, "%d.%de", MIN(22,nbytes), MIN(15, nbytes-7));
		sprintf(edited, form, value[i]);
		status = TCEWRC (tid, row, icol, edited);
								  	break;
	    case TBL_D_I1:	*x = NINT(value[i]);			break;
	    case TBL_D_A2:	*(unsigned short *)x = NINT(value[i]);	break;
	    case TBL_D_I2:	*(short *)x = NINT(value[i]);		break;
	    case TBL_D_A4:	*(unsigned int *)x = NINT(value[i]);	break;
	    case TBL_D_I4:	*(int *)x = NINT(value[i]);		break;
	    case TBL_D_R8:	*(double *)x = value[i];		break;
	    case TBL_D_R4:	*(float *)x = value[i];			break;
	}
  }

  return (status);
}
