/*===========================================================================
  Copyright (C) 1989-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        tbaload.c
.LANGUAGE    C
.AUTHOR      IPG-ESO Garching
.CATEGORY    table utilities

.COMMENTS    Routines to load an opened table from an ASCII file
		and eventual format.

.VERSION 1.0 	25-Mar-1989   Definition     J.D. Ponz
.VERSION 1.1 	16-May-1990   Change default length of char.strings  J.D. Ponz
.VERSION 3.0 	05-Jul-1990   New version with column arrays   F.Ochsenbein
			Added tbl_loads (load with tabs)
			      tbl_iload (load table size)
                08-Mar-1992   Add the possibility of having null lines in data

 090707		last modif
------------------------------------------------------------*/

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

#include <tbldef.h>
#include <midas_def.h>
#include <proto_tbl.h>
#include <proto_st.h>
#include <str.h>		/* String Utilities */

#define MAXBYTE      4096
#define MAXCOL        256

char *osfsupply();	/* Creates filename from name + defaults */
char *osmsg();		/* Error for file i/o			 */

/*

*/
int tbl_loadl(tid, datafile, n)
/*++++++++++++++++++
.PURPOSE Populates an empty table from ASCII file;
	each column is defined as a single precision floating number.
.RETURNS Status
------------------*/
int   tid;	/* IN: Table Concerned		*/
char *datafile;	/* IN: Filename with data	*/
int 	n;	/* IN: How many columns		*/

{
int status, fid, nchar, nrow, j, i, lineno;
int dummy;

char label[1+TBL_LABLEN], txt[80];
char buffer[MAXBYTE], *p, x;


status = ERR_NORMAL;

/* create columns by default */

for (i=1; (status == ERR_NORMAL) && (i<=n); i++) 
   {
   sprintf(label,"LAB%03d",i);
   status = TCCINI (tid, D_R4_FORMAT, 1, "E15.6", "Unitless",label,&dummy);
   }
   if (status)	return (status);


/* open data file */

fid = osaopen(osfsupply(datafile,".dat"),F_I_MODE);
if (fid < 0) fid = osaopen(datafile,F_I_MODE);
if (fid < 0) 
   {
   SCTPUT (osmsg());
   return (ERR_FILBAD);
   }

nrow = lineno = 0;

while ( (nchar = osaread(fid,buffer,MAXBYTE)) >= 0) 
   {
   lineno++;

   if (nchar == 0) continue;
   if ((*buffer == '#') || (*buffer == '!')) continue;	/* Comments...	*/

   if (nchar >= MAXBYTE) 
      {
      sprintf (txt,"**** Datafile line %d: truncated record!", lineno);
      SCTPUT (txt);
      }

   nrow++;
   p = buffer + strspan (buffer, _SPACE_);
   for (j = 1; (j <= n) && (*p); j++) 
      {
      if (*p == '*') 
         p++;					/* NULL */
      else 
         { 
         i = strscan (p, _SPACE_);
         x = p[i]; p[i] = '\0';

         status = TCEWRC (tid, nrow, j, p);
         if (status != ERR_NORMAL)
            {
            sprintf (buffer,"**** Datafile line %d, col %d: bad number",
                     nrow, j);
            SCTPUT(buffer);
            goto end_of_it;
            }
         p += i; *p = x;
         }
      p += strspan (p, _SPACE_);
      }
   }

end_of_it:
osaclose(fid);
return (status);
}       

int tbl_loads(tid, datafile, col_sep,dtype)
/*++++++++++++++++++
.PURPOSE Populates a table from an ASCII file, assuming that the
	columns have been created.
.RETURNS Status
------------------*/
int tid;	/* IN: Table Concerned		*/
char *datafile;	/* IN: Filename with data	*/
char *col_sep;	/* IN: char used to separate columns	*/
int *dtype;

{
char buffer[MAXBYTE], *p, *errmsg, x;
char newcsep[12], txt[80];

int find, status, fid, nrow, ncol, i, lineno, j, nchar, dummy;
int ec, el, ed;
int zero=0, one=1, less_once=1, more_once=1;



/* open data file */

fid = osaopen(osfsupply(datafile,".dat"),F_I_MODE);
if (fid < 0) fid = osaopen(datafile,F_I_MODE);

if (fid < 0) 
   {
   sprintf(buffer,"**** Problem opening datafile: %s",datafile);
   SCTPUT (buffer);
   SCTPUT (osmsg());
   return (ERR_FILBAD);
   }

status = ERR_NORMAL;
TCIGET(tid, &ncol, &nrow, &dummy, &dummy, &dummy);	/* get no of cols */

nrow = lineno = find = 0;
newcsep[0] = '"';
strcpy(newcsep+1,col_sep); 

SCECNT("GET",&ec,&el,&ed);			/* enable error checking */
SCECNT("PUT",&one,&zero,&zero);

while ( (nchar = osaread(fid,buffer,MAXBYTE)) >= 0) 
   {
   lineno++;

   if (nchar == 0)		continue;
   if ((*buffer == '#') || (*buffer == '!')) continue;	/* Comments...	*/

   if (nchar >= MAXBYTE) 
      {
      sprintf (txt,"**** Datafile line %d: truncated record!", lineno);
      SCTPUT (txt);
      }

   nrow++;
   p = buffer;

   if (dtype[0] == D_C_FORMAT && col_sep[strloc(col_sep,' ')]) 
      { 
      i = strspans(p,col_sep);
      if (p[i] == '"') 
         find = 1; 
      else
         find = 0;
      p = p + strspans(p,col_sep) + find;
      }
   else 
      {
      p +=  strspans(p,col_sep);
      }


   for (j=1; j<=ncol; j++) 
      {
      if ((dtype[j-1] == D_C_FORMAT) && (find == 1)) 
         i = strloc(p,'"');
      else 
         i = strscans (p, col_sep);

      x = p[i];	p[i] = '\0';
      status = TCEWRC (tid, nrow, j, p);
      if (status != ERR_NORMAL) 
         {
         errmsg = "writing error";
         goto error_return;
         }

      p += i; *p = x;
      if ( x == '"' && dtype[j-1] == D_C_FORMAT) p++ ;
      if (!*p)					/* end of line reached */
         {
         break;
         }

      if (dtype[j] == D_C_FORMAT && col_sep[strloc(col_sep,' ')]) 
         { 
         i = strspans(p,col_sep);
         if (p[i] == '"') 
            find = 1; 
         else 
            find = 0;
         p = p + strspans(p,col_sep) + find;
         }
      else 
         p +=  strspans(p,col_sep);
      }

   if (j < ncol)	
      {
      if (less_once == 1)
         {
         less_once = 0;
         sprintf (txt,"in datafile, line %d: too few numbers ", nrow);
         SCTPUT(txt);
         }
      }
   if (*p != '\0')
      {
      if (more_once == 1)
         {
         more_once = 0;
         sprintf (txt,"in datafile line, %d: too many numbers ", nrow);
         SCTPUT(txt);
         }
      }
   }   

SCECNT("PUT",&ec,&el,&ed);
osaclose(fid);
return (status);


error_return:
sprintf (txt,"**** Datafile line %d, col %d: %s", nrow, j, errmsg);
SCTPUT(txt);

osaclose(fid);
return (-1);
}       
/*

*/

int tbl_load(tid, datafile, format)
/*++++++++++++++++++
.PURPOSE Populated a table from ASCII file + FMT file
.RETURNS Status
.REMARKS If positions of the various fields are not defined, 
	we assume that tabs are used as separators.
------------------*/
int tid;	/* IN: Table Concerned		*/
char *datafile;	/* IN: Filename with data	*/
char *format;	/* IN: Name of Format File	*/

{
char buffer[MAXBYTE], x;
char  *q;
char col_sep[10];
char label[1+TBL_LABLEN], unit[1+TBL_UNILEN], form[10];

void charconv();

int  tbl_decfmt();

int status, i, j, fid, i2, i1, ncol, noelem, icc;
int ic, type, icol[MAXCOL], first[MAXCOL], last[MAXCOL];
int nline, nrow, nchar, dctype[MAXCOL];
int  ec,ed,el,zero,one;



/* access format file to create columns */

fid = osaopen(osfsupply(format, ".fmt"),F_I_MODE);
if (fid < 0) 
   {
   sprintf(buffer,"**** Problem opening format file: %s",format);
   SCTPUT (buffer);
   return (ERR_FILBAD);
   }

one = 1; zero = 0;			/* enable error checking in here */
SCECNT("GET",&ec,&el,&ed);
SCECNT("PUT",&one,&zero,&zero);

col_sep[0] = '\0';
ncol = 0;  

while (osaread(fid,buffer,MAXBYTE) >= 0) 
   {
   if ((stumatch(buffer,"fs")) == 2) 
      {
      q = buffer + strloc(buffer,'"') + 1;
      i = strloc(q,'"');
      q[i] = '\0';
      charconv(q,col_sep);
      } 
   else 
      {
      status = tbl_decfmt(buffer,&i1,&i2,&type,&noelem,form,unit,label);
      if (status) 
         {
         sprintf(buffer,"*** problems with format of column %d",ncol+1);
         status = ERR_INPINV;
         goto error_return;
         }

      if (type == 0) continue;

      status = TCCSER(tid,label,&icc) ;
      if (status != ERR_NORMAL)	
         {
         sprintf(buffer,"problems with TCCSER, ncol = %d ...",ncol+1);
         goto error_return;
         }
      if (icc > 0) 
         {
         sprintf(buffer,
               "*** label %s specified more than once in the format file", 
               label);
         status = ERR_INPINV;
         goto error_return;
         } 
         

      status = TCCINI(tid,type,noelem,form,unit,label,&ic);
      if (status != ERR_NORMAL)	
         {
         sprintf(buffer,"problems with TCCINI, ncol = %d ...",ncol+1);
         goto error_return;
         }

      first[ncol] = i1;
      last[ncol]  = i2;
      icol[ncol]  = ic;
      dctype[ncol] = type;

      if (ncol >= MAXCOL) 
         {
	 sprintf(buffer,"more than %d columns, we give up ...",(MAXCOL-1));
	 status = ERR_TBLCOL;
         goto error_return;
	 }

      ncol++;
      }
   }

(void) osaclose(fid);
SCECNT("PUT",&ec,&el,&ed);

				/* If no position parm. Assume tabs */
if (last[0] == 0) 
   {
   if (col_sep[0] == '\0') strcpy(col_sep,"\t ");

   return ( tbl_loads (tid, datafile, col_sep, dctype) );
   }



/* open data file */

fid = osaopen(osfsupply(datafile,".dat"),F_I_MODE);
if (fid < 0) fid = osaopen(datafile,F_I_MODE);
if (fid < 0) 
   {
   sprintf(buffer,"**** Problem opening datafile: %s",datafile);
   SCTPUT (buffer);
   return (ERR_FILBAD);
   }


SCECNT("PUT",&one,&zero,&zero);		/* again handle errors right here */
nrow = nline = 0;
oscfill(buffer,MAXBYTE,'\0');

while ((status == ERR_NORMAL) && ((nchar = osaread(fid,buffer,MAXBYTE)) >= 0))
   {
   nline ++;

   if (nchar == 0) continue;
   if ((*buffer == '#') || (*buffer == '!'))continue;	/* Comments...	*/

   nrow ++;
   for (j=0; j < ncol; j++) 
      {
      x = buffer[last[j]],  buffer[last[j]] = '\0';
      status = TCEWRC(tid,nrow,icol[j],buffer-1+first[j]);
      if (status != ERR_NORMAL) 
         {
         sprintf(buffer,"****Problems in datafile at line %d",nline);
         goto error_return;
         }
      buffer[last[j]] = x;
      }

   oscfill(buffer,MAXBYTE,'\0');
   }

SCECNT("PUT",&ec,&el,&ed);
osaclose(fid);
return (status);


/* we encountered problems... */

error_return:
SCTPUT(buffer);

SCECNT("PUT",&ec,&el,&ed);
osaclose(fid);
return (status);
}       

int tbl_iload(format, lines, cols)
/*++++++++++++++++++
.PURPOSE Retrieve in Format File the Table Size
.RETURNS Status
.REMARKS Values are specified as "Row[s=]" for number of rows, "Col[umn=]"
		for number of columns.
------------------*/
char *format;	/* IN: Name of Format File	*/
int  *lines;	/* OUT: Lines as found		*/
int  *cols;	/* OUT: Columns as found	*/

{
int  fid;

char buffer[80];



/* access format file to create columns */

*lines = *cols = 0;
fid = osaopen(osfsupply(format, ".fmt"),F_I_MODE);
if (fid < 0) 
   {
   char  text[1024];

   sprintf(text,"**** Problem opening format file: %s",format);
   SCTPUT (text);
   return (ERR_FILBAD);
   }


/* Look in formatfile */

while ( (!*lines) && (!*cols) ) 
   {
   if (osaread(fid, buffer, sizeof(buffer)) < 0)	break;

   if (stumatch(buffer, "row") == 4) 
      *lines = atoi (buffer + strscan (buffer, _SPACE_));

   if (stumatch(buffer, "col") == 3) 
      *cols = atoi (buffer + strscan (buffer, _SPACE_));
   }

osaclose (fid);
return (ERR_NORMAL);
}



void charconv(p,q)
char *q, *p;

{
char t;



while ( *p != '\0') 
   {
   if (*p == '\\') 
      {
      p++;
      switch (t = *p) 
         {
         case 't': *q++ = '\t'; p++; break;
         case 'n': *q++ = '\n'; p++; break;
         case 'r': *q++ = '\r'; p++; break;
         case 'b': *q++ = '\b'; p++; break;
         case 'f': *q++ = '\f'; p++; break;
         }
      }
   else *q++ = *p++;
   }

*q = '\0';			/* finish string correctly */
} 
