/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	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.

**********************************************************************/


#define STREAM_LIB
#define LIBRARY
#define S_FILE_LIBRARY

#include	<stdlib.h>
#include	<fcntl.h>
#ifdef VA2
#include	<varargs.h>
#else
#include	<stdarg.h>
#endif
#include	<errno.h>

#include	"memory_debug.h"
#include	"stream.h"
#include	"task.h"
#include	<sys/types.h>



extern SEM stream_lock;
int max_fid = 3;
int now_open_files = 4;

int s_close_file();
int s_write_file();
int s_read_file();
int s_vprintf_file();
int s_vprintf_cr_file();
int s_flush_file();
int s_vscanf_file();
int s_proc_send_file();
STREAM * s_proc_recv_file();
STREAM * s_open_file_descripter();

S_TABLE s_file_table = {
	'f',
	0,
	s_open_file_descripter,
	s_close_file,
	s_write_file,
	s_read_file,
	s_flush_file,
	s_proc_send_file,
	s_proc_recv_file
};

S_FILE __s_std[3] = {
	{	{	&s_file_table,
			O_RDONLY
		},
		INVALID_HANDLE_VALUE,
		stdin
	},
	{	{	&s_file_table,
			O_WRONLY
		},
		INVALID_HANDLE_VALUE,
		stdout
	},
	{	{	&s_file_table,
			O_WRONLY
		},
		INVALID_HANDLE_VALUE,
		stderr
	}
};

void
init_file_stream()
{
void insert_s_table(S_TABLE * tbl);

	__s_std[0].hfile = GetStdHandle(STD_INPUT_HANDLE);
	__s_std[1].hfile = GetStdHandle(STD_OUTPUT_HANDLE);
	__s_std[2].hfile = GetStdHandle(STD_ERROR_HANDLE);

	insert_s_table(&s_file_table);
}

STREAM *
s_open_file_descripter(HANDLE h, S_TABLE * tbl)
{
STREAM * ret;
int mode;
void _s_open(STREAM * s,int mode);
	
	if ( h == INVALID_HANDLE_VALUE)
		return 0; 
	mode = O_RDONLY;
	ret = d_alloc(sizeof(S_FILE),133);
	ret->h.tbl = tbl;
	ret->h.thread = 0;
	ret->file.hfile= h;

	lock_task(stream_lock);
	_s_open(ret,mode);
	unlock_task(stream_lock,"s_open_descripter");
	return ret;
}

STREAM *
_s_open_file_descripter(HANDLE h, S_TABLE * tbl)
{
STREAM * ret;
int mode;
	if ( h == INVALID_HANDLE_VALUE )
		return 0; 
/*	mode = fcntl(d,F_GETFL);
	if ( mode < 0 )
		return 0;
	mode &= ~3;
	fcntl(d,F_SETFL,mode);
*/
	mode = O_RDWR;
	
	ret = d_alloc(sizeof(S_FILE),133);
	ret->h.tbl = tbl;
	ret->h.thread = 0;
	ret->file.hfile = h;
	
	_s_open(ret,mode);
	return ret;
}


STREAM *
s_open_file(char * filename,int mode,int flags)
{
STREAM * ret;
DWORD access_mode;
DWORD create_disposition;
char * _f;

	errno = 0;
	ret = d_alloc(sizeof(S_FILE),134);
	ret->h.tbl = &s_file_table;
	ret->h.thread = 0;
	access_mode = GENERIC_READ;
	if (mode & O_RDWR)
		access_mode = GENERIC_WRITE|GENERIC_READ;
	
	if( (mode & O_CREAT) || (mode & O_RDWR) || (mode & O_WRONLY)){
		create_disposition = CREATE_ALWAYS;
	}
	else if(mode & O_TRUNC){
		create_disposition = TRUNCATE_EXISTING;
	}
	else{
		create_disposition = OPEN_EXISTING;
	}
	_f = change_delim_str(filename);
	ret->file.h.mode = mode;
	ret->file.hfile = CreateFile(_f, 
					access_mode, 
					FILE_SHARE_READ, 0, 
					create_disposition, 
					FILE_ATTRIBUTE_NORMAL, NULL);
	if ( _f != filename )
		d_f_ree(_f);
	
	if ( ret->file.hfile == INVALID_HANDLE_VALUE) {
		d_f_ree(ret);
		return 0;
	}
	lock_task(stream_lock);
	_s_open(ret,mode);
	unlock_task(stream_lock,"s_open_file");
	return ret;
}

int
s_close_file(STREAM * s)
{
void _s_close_sync(STREAM * s);
	_s_close_sync(s);
	CloseHandle(s->file.hfile);
	return 0;
}

int
s_write_file(STREAM * s,void * data,int len)
{
DWORD wrote=0;
	if(s->file.hfile != INVALID_HANDLE_VALUE)
		WriteFile(s->file.hfile, data, len, &wrote, NULL );
	else
		wrote = fwrite(data, 1, len, s->file.std_fd);
	s->h.last_size = len;
	s->h.last_err = GetLastError();
	return (int)wrote;
}

int
s_read_file(STREAM * s,void * data,int len)
{
DWORD read=0;
	if(s->file.hfile != INVALID_HANDLE_VALUE)
		ReadFile(s->file.hfile, data, len, &read, NULL);
	else
		read = fread(data, 1, len, s->file.std_fd);
	return (int)read;
}

int
s_flush_file(STREAM * s)
{
	if(s->file.hfile != INVALID_HANDLE_VALUE)
		FlushFileBuffers(s->file.hfile);
	else
		fflush(s->file.std_fd);
	return 0;
}




int
s_seek_file(STREAM * s,unsigned int offset,int where)
{
DWORD origin;
	
	if ( s->h.tbl != &s_file_table )
		return -1;
	origin = 0;
	switch(where){
		case SEEK_SET: origin=FILE_BEGIN;
		case SEEK_CUR: origin=FILE_CURRENT;
		case SEEK_END: origin=FILE_END;
	}
	return SetFilePointer(s->file.hfile, offset, NULL, origin);
}


int
s_proc_send_file(STREAM * s,PROC_SEND * ps)
{
void er_panic(char * str);

	int duped_hfile;
	ps->msg[0] = s->h.tbl->type;
	ps->msg[1] = 0;
	if(!DuplicateHandle(
			GetCurrentProcess(), 
			s->file.hfile,
			GetCurrentProcess(),
			(HANDLE*)&duped_hfile, 0, TRUE, DUPLICATE_SAME_ACCESS)){
			er_panic("dup error");
	}
	ps->fid[0] = duped_hfile;
	ps->fid[1] = -1;
	return 0;
}


STREAM *
s_proc_recv_file(PROC_RECV * ps)
{
HANDLE hfile;
	ps->ptr++;
	hfile = (void*)(ps->fidp++);
	return _s_open_file_descripter(hfile, ps->tbl);
}

