/*
 *  inascii.C from ObjectProDSP
 *  Copyright (C) 1994, Mountain Math Software. All rights reserved.
 *  
 *  This file is part of ObjectProDSP, a tool for Digital Signal
 *  Processing design, development and implementation. It is free
 *  software provided you use and distribute it under the terms of
 *  version 2 of the GNU General Public License as published
 *  by the Free Software Foundation. You may NOT distribute it or
 *  works derived from it or code that it generates under ANY
 *  OTHER terms.  In particular NONE of the ObjectProDSP system is
 *  licensed for use under the GNU General Public LIBRARY License.
 *  Mountain Math Software plans to offer a commercial version of
 *  ObjectProDSP for a fee. That version will allow redistribution
 *  of generated code under standard commercial terms.
 *  
 *  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 version 2 of the GNU General
 *  Public License along with this program. See file COPYING. If not
 *  or if you wish information on commercial versions and licensing
 *  write Mountain Math Software, P. O. Box 2124, Saratoga, CA 95070,
 *  USA, or send us e-mail at: support@mtnmath.com.
 *  
 *  You may also obtain the GNU General Public License by writing the
 *  Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
 *  USA.  However if you received a copy of this program without the
 *  file COPYING or without a copyright notice attached to all text
 *  files, librarys and executables please inform Mountain Math Software.
 *  
 *  ObjectProDSP is a trademark of Mountain Math Software.
 */
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "cgidbg.h"
#include "inascii.h"
#include "import.h"
#include "yacintfc.h"
#include "remcom.h"
#include "newaloc.h"
#include "environ.h"
#include "mkstr.h"

static int SignExtendBit = 15 ; // needs to be made a parameter of user
static uint32 SignExtendMask = (0xffffffff << SignExtendBit) ;

AsciiInputFile::format AsciiInputFile::find_code(const char * fmt)
{
	int found_per = 0 ;
	int found_l = 0 ;
	for (const char * Ptr = fmt; *Ptr; Ptr++) {
		int fmt = unknown_f ;
		switch (*Ptr) {
			
case '%':
			found_per = 1 ;
			break ;
case 'l':
			if (found_per) found_l = 1 ;
			break ;
case 'e':
case 'E':
case 'f':
case 'F':
			if (found_l) fmt = float_f ;
			else if (found_per) return unknown_f ;
			// single precision floating no good
			break ;
case 'x':
case 'X':
			if (found_l) return unknown_f ;
			fmt = hex_f | unsigned_f ;
			break ;
case 'o':
case 'O':
			if (found_l) return unknown_f ;
			fmt = oct_f | unsigned_f ;
			break ;
case 'd':
case 'D':
			if (found_l) return unknown_f ;
			fmt = dec_f | signed_int_f ;
			break ;
		}
		if (found_per && fmt != unknown_f) return (format) fmt ;
		if (found_l && *Ptr != 'l') return unknown_f ;
	}
	return unknown_f;
}

void AsciiInputFile::open_file(int force_error)
{
/*
 *	LogOut << "AsciiInputFile::open_file(" << force_error << "), Thefile = " <<
 *		(void *) TheFile << "\n" ;
 */
	if (TheFile) return ;
	const char * new_name = TheNode->def_name(FileName);
	const char * e_name = TargetNode::open_file(&new_name,TheFile,0,
		force_error);
	if (FileName != new_name) {
		FileName = Concatenate(new_name);
		DeleteName = 1 ;
	}

	if (e_name != new_name) exp_name = Concatenate(e_name);
    else exp_name = 0 ; 
}

void AsciiInputFile::Rewind()
{
	fseek(TheFile,(long) 0,SEEK_SET);
	CurrentField= MaxFields + 1;
}

const int AsciiInputFile::MaxLineSize = 2048 ;

AsciiInputFile::AsciiInputFile(ImportData * node):
	EndOfFileFlag(1),
	TheNode(node),
	FileName(node->GetFileName()),
	DeleteName(0),
	TheStream(0),
	TheFile(0),
	exp_name(0)
	
{
	Format = Concatenate(TheNode->GetFormat());
	int len = strlen(Format);
	if (len > 2) if (Format[len-2] == '_') Format[len-2] = '\0' ;
	format_code = find_code(Format) ;
	if (format_code == unknown_f) State.Error("unknown format");
	MaxFields = TheNode->GetFields();
	if (!MaxFields) MaxFields = MaxLineSize ;
	CurrentField= MaxFields + 1;

	FileBuf = new char[MaxLineSize+2];
	FileBuf[0] = '\0' ;

	BufPtr = FileBuf ;
}

void AsciiInputFile::DeleteColumns()
{
	const char * src = FileBuf ;
	char * dest = FileBuf ;
	int column_index = 1 ;
	int ix = 0 ;
	if (!TheNode->GetSkipColumns()[0]) return ;
	int next_skip = TheNode->GetSkipColumns()[0] ;
	while (*src) if (column_index < next_skip)
		*dest++ = *src++,column_index++ ;
	else {
		int end = 0 ;
		next_skip = MaxLineSize ;
		if (++ix < TheNode->GetSkipColumns_Length()) end =
			TheNode->GetSkipColumns()[ix] ;
		if (!end) break ;
		int inc = end - column_index + 1 ;
		src += inc ;
		column_index += inc ;
		if (++ix < TheNode->GetSkipColumns_Length()) next_skip =
			TheNode->GetSkipColumns()[ix] ;
	}
	*dest = '\0' ;
}

int AsciiInputFile::ReadLine()
{
	char buf[32] ;
	sprintf(buf,"&d",MaxLineSize);
	if (!fgets(FileBuf,MaxLineSize+1,TheFile)) {
		// LogOut << "AsciiInputFile::ReadLine, EOF\n" ;
		EndOfFileFlag = 1 ;
		return 0;
	}
	// LogOut << "Line is `" << FileBuf << "'\n" ;
	if (strlen(FileBuf) > MaxLineSize) {
		State.Error("Line in file `", FileName,
			"' is greater than ", buf, " characters")  ;
		return 0 ;
	}
	DeleteColumns();
	CurrentField = 1 ;
	TheStream = new istrstream(FileBuf,strlen(FileBuf)+1);
	return 1 ;
}

int AsciiInputFile::DoReadField()
{
	char LocalBuf[MaxLineSize+1];
	char * ToRead = LocalBuf ;
	LocalBuf[0] = '\0' ;
	*TheStream >> LocalBuf ;
	if (!LocalBuf[0]) return 0 ;

	if (format_code & hex_f) if (LocalBuf[0] == '0')
		if (LocalBuf[1] == 'x' || LocalBuf[1] == 'X')
		ToRead = LocalBuf + 2 ;
/*
 *	LogOut << "Fmt `" << Format << "', Bf `" << LocalBuf << "', f_code: 0x" <<
 *		hex << format_code << dec <<  ".\n" ;
 */
	int Return = 0;
	int32 val = 0 ;
	uint32 uval = 0 ;
	switch (format_code & (float_f|unsigned_f |signed_int_f)) {
default:
case unknown_f:
		State.Error("unknown format");
		return 0 ;
case float_f:
		Return = sscanf(ToRead,Format,&TheData) == 1 ;
		break ;
case unsigned_f:		
		Return = sscanf(ToRead,Format,&uval) == 1 ;
		TheData = uval ;
		break ;
case signed_int_f:
		Return = sscanf(ToRead,Format,&val) == 1 ;
		TheData = val ;
		break ;
	}
	if (!Return) State.Error("bad input file or format parameter");
/*
 *	LogOut << "DoReadField read " << TheData << ", Return = " <<
 *			Return << "\n" ;
 */
	return Return ;
}


int AsciiInputFile::ReadField()
{
	int failed = 0 ;
	for (;;) {
		if (State.IsError()) return 0 ;
		if (failed || CurrentField > MaxFields)
			if (!ReadLine()) {
				return 0 ;
			}
		failed = 0 ;
		if (!DoReadField()) {
			failed = 1 ;
			continue ;
		}
		for (int i = 0 ; i < TheNode->GetSkipFields_Length(); i++) 
			if (CurrentField == TheNode->GetSkipFields()[i]) break ;
		CurrentField++ ;
		if (i >= TheNode->GetSkipFields_Length()) break ;
	}
	return 1 ;
}


const double * AsciiInputFile::GetFieldContents()
{
	if (ReadField()) return &TheData ;
	return 0 ;
}

AsciiInputFile::~AsciiInputFile()
{
	if (DeleteName) delete (char *) FileName ;
	if (TheFile) fclose(TheFile);
	delete FileBuf ;
	delete TheStream ;
	delete exp_name;
}



