/*
// Dao Virtual Machine
// http://daoscript.org
//
// Copyright (c) 2006-2017, Limin Fu
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include"ctype.h"
#include"string.h"
#include"daoStream.h"
#include"daoVmspace.h"
#include"daoRoutine.h"
#include"daoProcess.h"
#include"daoNumtype.h"
#include"daoNamespace.h"
#include"daoValue.h"
#include"daoGC.h"
#define IO_BUF_SIZE 4096
int DaoStream_ReadStdin( DaoStream *self, DString *data, int count )
{
DString_Reset( data, 0 );
if( count >= 0 ){
DString_Reset( data, count );
DString_Reset( data, fread( data->chars, 1, count, stdin ) );
}else if( count == -1 ){
DaoFile_ReadLine( stdin, data );
}else{
DaoFile_ReadAll( stdin, data, 0 );
}
fseek( stdin, 0, SEEK_END );
return data->size;
}
int DaoStream_WriteStdout( DaoStream *self, const void *data, int count )
{
DString bytes = DString_WrapBytes( (char*) data, count );
DaoFile_WriteString( stdout, & bytes );
return count;
}
int DaoStream_WriteStderr( DaoStream *self, const void *data, int count )
{
DString bytes = DString_WrapBytes( (char*) data, count );
DaoFile_WriteString( stderr, & bytes );
return count;
}
int DaoStream_AtEnd( DaoStream *self )
{
return 0;
}
void DaoStream_FlushStdout( DaoStream *self )
{
if( self->Write == DaoStream_WriteStdout ){
fflush( stdout );
}else if( self->Write == DaoStream_WriteStderr ){
fflush( stderr );
}
}
int DaoStdStream_ReadStdin( DaoStream *stream, DString *data, int count )
{
DaoStdStream *self = (DaoStdStream*) stream;
if( self->redirect && self->redirect->Read ){
return self->redirect->Read( self->redirect, data, count );
}
return DaoStream_ReadStdin( stream, data, count );
}
int DaoStdStream_WriteStdout( DaoStream *stream, const void *data, int count )
{
DaoStdStream *self = (DaoStdStream*) stream;
if( count == 0 ) return 0;
if( self->redirect && self->redirect->Write ){
int k = self->redirect->Write( self->redirect, data, count );
if( k ) return k;
}
return DaoStream_WriteStdout( stream, data, count );
}
int DaoStdStream_WriteStderr( DaoStream *stream, const void *data, int count )
{
DaoStdStream *self = (DaoStdStream*) stream;
if( count == 0 ) return 0;
if( self->redirect && self->redirect->Write ){
int k = self->redirect->Write( self->redirect, data, count );
if( k ) return k;
}
return DaoStream_WriteStderr( stream, data, count );
}
static int DaoStdStream_AtEnd( DaoStream *stream )
{
DaoStdStream *self = (DaoStdStream*) stream;
if( self->redirect && self->redirect->Flush ){
return self->redirect->AtEnd( self->redirect );
}
return DaoStream_AtEnd( stream );
}
static void DaoStdStream_FlushStdout( DaoStream *stream )
{
DaoStdStream *self = (DaoStdStream*) stream;
if( self->redirect && self->redirect->Flush ){
self->redirect->Flush( self->redirect );
return;
}
DaoStream_FlushStdout( stream );
}
static int DaoStdStream_SetColor( DaoStream *stream, const char *fgcolor, const char *bgcolor )
{
DaoStdStream *self = (DaoStdStream*) stream;
if( self->redirect ){
if( self->redirect->SetColor ){
return self->redirect->SetColor( self->redirect, fgcolor, bgcolor );
}
return 1;
}
return DaoStream_SetScreenColor( stream, fgcolor, bgcolor );
}
static int DaoStream_WriteBuffer( DaoStream *self, const void *data, int count )
{
DString_AppendBytes( self->buffer, (char*) data, count );
return count;
}
DaoStream* DaoStream_New( DaoVmSpace *vms )
{
DaoStream *self = (DaoStream*) dao_calloc( 1, sizeof(DaoStream) );
DaoCstruct_Init( (DaoCstruct*) self, vms->typeStream );
self->Read = DaoStream_ReadStdin;
self->Write = DaoStream_WriteStdout;
self->AtEnd = DaoStream_AtEnd;
self->Flush = DaoStream_FlushStdout;
self->SetColor = DaoStream_SetScreenColor;
return self;
}
DaoStream* DaoStdStream_New( DaoVmSpace *vms )
{
DaoStdStream *self = (DaoStdStream*) dao_calloc( 1, sizeof(DaoStdStream) );
DaoCstruct_Init( (DaoCstruct*) self, vms->typeStream );
self->base.type = DAO_CSTRUCT;
self->base.Read = DaoStdStream_ReadStdin;
self->base.Write = DaoStdStream_WriteStdout;
self->base.AtEnd = DaoStdStream_AtEnd;
self->base.Flush = DaoStdStream_FlushStdout;
self->base.SetColor = DaoStdStream_SetColor;
return (DaoStream*) self;
}
void DaoStream_Delete( DaoStream *self )
{
if( self->buffer ) DString_Delete( self->buffer );
DaoCstruct_Free( (DaoCstruct*) self );
dao_free( self );
}
void DaoStream_SetStringMode( DaoStream *self )
{
if( self->buffer == NULL ) self->buffer = DString_New();
self->Write = DaoStream_WriteBuffer;
self->Read = NULL;
self->Flush = NULL;
self->SetColor = NULL;
}
void DaoStream_Flush( DaoStream *self )
{
if( self->Flush ) self->Flush( self );
}
int DaoStream_IsOpen( DaoStream *self )
{
return self->Read != NULL || self->Write != NULL;
}
int DaoStream_EndOfStream( DaoStream *self )
{
if( self->AtEnd == NULL ) return 0;
return self->AtEnd( self );
}
int DaoStream_IsReadable( DaoStream *self )
{
return self->Read != NULL;
}
int DaoStream_IsWritable( DaoStream *self )
{
return self->Write != NULL;
}
void DaoStream_WriteChar( DaoStream *self, char val )
{
const char *format = "%c";
char buffer[4];
int count;
if( self->Write == NULL ) return;
count = snprintf( buffer, sizeof(buffer), "%c", val );
self->Write( self, buffer, count );
}
void DaoStream_WriteInt( DaoStream *self, dao_integer val )
{
const char *format = self->format;
char buffer[48];
int count;
if( self->Write == NULL ) return;
if( format == NULL ) format = "%"DAO_I64;
count = snprintf( buffer, sizeof(buffer), format, val );
self->Write( self, buffer, count );
}
void DaoStream_WriteFloat( DaoStream *self, double val )
{
const char *format = self->format;
const char *iconvs = "diouxXcC";
char buffer[100];
int count;
if( self->Write == NULL ) return;
if( format && strchr( iconvs, format[ strlen(format)-1 ] ) && val ==(dao_integer)val ){
DaoStream_WriteInt( self, (dao_integer)val );
return;
}
if( format == NULL ) format = "%f";
count = snprintf( buffer, sizeof(buffer), format, val );
self->Write( self, buffer, count );
}
void DaoStream_WriteChars( DaoStream *self, const char *chars )
{
if( self->Write == NULL ) return;
self->Write( self, chars, strlen(chars) );
}
daoint DaoStream_WriteBytes( DaoStream *self, const void *bytes, daoint count )
{
const uchar_t *chars = (const uchar_t*)bytes;
daoint sum = 0;
if( self->Write == NULL ) return -1;
while( sum < count ){
daoint num = count - sum;
if( num > 0x7fffffff ) num = 0x7fffffff;
num = self->Write( self, chars + sum, num );
if( num < 0 ) return -1;
if( num == 0 ) break;
sum += num;
}
return sum;
}
void DaoStream_WriteString( DaoStream *self, DString *val )
{
if( self->Write == NULL ) return;
self->Write( self, val->chars, val->size );
}
void DaoStream_WriteLocalString( DaoStream *self, DString *str )
{
str = DString_Copy( str );
DString_ToLocal( str );
DaoStream_WriteString( self, str );
DString_Delete( str );
}
void DaoStream_WritePointer( DaoStream *self, void *val )
{
const char *format = self->format;
char buffer[32];
int count;
if( format == NULL ) format = "%p";
count = snprintf( buffer, sizeof(buffer), format, val );
self->Write( self, buffer, count );
}
void DaoStream_WriteNewLine( DaoStream *self )
{
DaoStream_WriteChars( self, daoConfig.iscgi ? "
" : "\n" );
}
daoint DaoStream_Read( DaoStream *self, DString *output, daoint count )
{
DString_Reset( output, 0 );
if( self->Read == NULL ) return 0;
if( count == -1 ){
return self->Read( self, output, -1 );
}else if( count <= -2 ){
return self->Read( self, output, -2 );
}else if( count <= 0x7fffffff ){
return self->Read( self, output, count );
}
DString_Reserve( output, count );
count = DaoStream_ReadBytes( self, output->chars, count );
if( count > 0 ) DString_Reset( output, count );
return count;
}
daoint DaoStream_ReadBytes( DaoStream *self, void *output, daoint count )
{
daoint sum = 0;
if( count < 0 ) return -1;
if( self->Read == NULL ) return -1;
while( sum < count ){
DString buffer = DString_WrapBytes( (char*) output, count );
daoint num = count - sum;
if( num > 0x7fffffff ) num = 0x7fffffff;
num = self->Read( self, & buffer, num );
if( num < 0 ) return -1;
if( num == 0 ) break;
sum += num;
}
return sum;
}
int DaoStream_ReadLine( DaoStream *self, DString *line )
{
DString_Reset( line, 0 );
if( self->Read == NULL ) return 0;
if( self->AtEnd && self->AtEnd( self ) ) return 0;
return self->Read( self, line, -1 ) >= 0;
}
int DaoStream_SetColor( DaoStream *self, const char *fgcolor, const char *bgcolor )
{
if( self->SetColor ) return self->SetColor( self, fgcolor, bgcolor );
return 0;
}
void DaoStream_TryHighlight( DaoStream *self, int tag )
{
const char *color = NULL;
if( ! (self->mode & DAO_STREAM_HIGHLIGHT) ) return;
if( tag == 0 ){
DaoStream_SetColor( self, NULL, NULL );
return;
}
switch( tag ){
case '"' : color = "red"; break;
case '0' : color = "red"; break;
case 'A' : color = "green"; break;
case '.' : color = "green"; break;
case '(' :
case ')' : color = "blue"; break;
case '[' :
case ']' : color = "blue"; break;
case '{' :
case '}' : color = "blue"; break;
case ',' : color = "magenta"; break;
case ';' : color = "magenta"; break;
case ':' : color = "cyan"; break;
default: break;
}
DaoStream_SetColor( self, color, NULL );
}
void DaoStream_PrintHL( DaoStream *self, int tag, const char *text )
{
DaoStream_TryHighlight( self, tag );
DaoStream_WriteChars( self, text );
DaoStream_TryHighlight( self, 0 );
}
int DaoFile_ReadLine( FILE *fin, DString *line )
{
int ch;
DString_Reset( line, 0 );
if( feof( fin ) ) return 0;
while( (ch = fgetc(fin)) != EOF ){
if( line->size == line->bufSize ) DString_Reserve( line, (daoint)(5 + 1.2*line->size) );
line->chars[ line->size ++ ] = ch;
line->chars[ line->size ] = '\0';
if( ch == '\n' ) break;
}
return 1;
}
int DaoFile_ReadAll( FILE *fin, DString *output, int close )
{
char buf[IO_BUF_SIZE];
DString_Reset( output, 0 );
if( fin == NULL ) return 0;
while(1){
// TODO: read directly into output;
size_t count = fread( buf, 1, IO_BUF_SIZE, fin );
if( count ==0 ) break;
DString_AppendBytes( output, buf, count );
}
if( close ) fclose( fin );
return 1;
}
int DaoFile_ReadPart( FILE *fin, DString *output, daoint offset, daoint count )
{
char buf[IO_BUF_SIZE];
daoint k, m, size = output->size;
if( fin == NULL ) return 0;
fseek( fin, offset, SEEK_SET );
while( count > 0 ){
m = count < IO_BUF_SIZE ? count : IO_BUF_SIZE;
k = fread( buf, 1, m, fin );
if( k == 0 ) break;
DString_AppendBytes( output, buf, k );
count -= k;
}
return output->size - size;
}
int DaoFile_WriteString( FILE* file, DString *str )
{
char buffer[1024];
int nullterm = str->chars[ str->size ] == '\0';
daoint pos = 0;
while( pos < str->size ){
daoint count = 0;
if( nullterm ){
count = fprintf( file, "%s", str->chars + pos );
}else{
count = str->size - pos;
if( count > sizeof(buffer) ) count = sizeof(buffer);
count = snprintf( buffer, count, "%s", str->chars + pos );
if( count >= 0 ) count = fprintf( file, "%s", buffer );
}
if( count < 0 ) return 0;
pos += count;
if( pos >= str->size ) return 1;
if( str->chars[pos] != '\0' ) return 0;
fprintf( file, "%c", 0 );
pos += 1;
}
return 1;
}
static int DaoIO_CheckMode( DaoStream *self, DaoProcess *proc, int what )
{
if( DaoStream_IsOpen( self ) == 0 ){
DaoProcess_RaiseError( proc, NULL, "stream is not open!" );
return 0;
}
if( what == DAO_STREAM_READABLE && DaoStream_EndOfStream( self ) == 1 ){
DaoProcess_RaiseError( proc, NULL, "stream reached the end!" );
return 0;
}
if( what == DAO_STREAM_READABLE && DaoStream_IsReadable( self ) == 0 ){
DaoProcess_RaiseError( proc, NULL, "stream is not readable!" );
return 0;
}
if( what == DAO_STREAM_WRITABLE && DaoStream_IsWritable( self ) == 0 ){
DaoProcess_RaiseError( proc, NULL, "stream is not writable!" );
return 0;
}
return 1;
}
static void DaoIO_Write0( DaoStream *self, DaoProcess *proc, DaoValue *p[], int N )
{
DMap *cycmap = NULL;
int i;
for(i=0; itype > DAO_ARRAY ){
cycmap = DHash_New(0,0);
break;
}
}
for(i=0; itype > DAO_ARRAY ) DMap_Reset( cycmap );
DaoValue_Print( p[i], self, cycmap, proc );
}
if( cycmap ) DMap_Delete( cycmap );
}
static void DaoIO_Write( DaoProcess *proc, DaoValue *p[], int N )
{
DaoStream *self = & p[0]->xStream;
if( DaoIO_CheckMode( self, proc, DAO_STREAM_WRITABLE ) == 0 ) return;
DaoIO_Write0( self, proc, p+1, N-1 );
}
static void DaoIO_Write2( DaoProcess *proc, DaoValue *p[], int N )
{
DaoStream *stream = proc->stdioStream;
if( stream == NULL ) stream = proc->vmSpace->stdioStream;
if( DaoIO_CheckMode( stream, proc, DAO_STREAM_WRITABLE ) == 0 ) return;
DaoIO_Write0( stream, proc, p, N );
}
static void DaoIO_Writeln0( DaoStream *self, DaoProcess *proc, DaoValue *p[], int N )
{
DaoValue *params[DAO_MAX_PARAM];
DMap *cycmap = NULL;
int i;
if( DaoIO_CheckMode( self, proc, DAO_STREAM_WRITABLE ) == 0 ) return;
for(i=0; itype > DAO_ARRAY ){
cycmap = DHash_New(0,0);
break;
}
}
/*
// DaoValue_Print() may call user defined function and change the stack
// and invalidate the parameter array:
*/
memmove( params, p, N*sizeof(DaoValue*) );
for(i=0; itype > DAO_ARRAY ) DMap_Reset( cycmap );
DaoValue_Print( params[i], self, cycmap, proc );
if( i+1xStream;
if( DaoIO_CheckMode( self, proc, DAO_STREAM_WRITABLE ) == 0 ) return;
DaoIO_Writeln0( self, proc, p+1, N-1 );
}
static void DaoIO_Writeln2( DaoProcess *proc, DaoValue *p[], int N )
{
DaoStream *stream = proc->stdioStream;
if( stream == NULL ) stream = proc->vmSpace->stdioStream;
if( DaoIO_CheckMode( stream, proc, DAO_STREAM_WRITABLE ) == 0 ) return;
DaoIO_Writeln0( stream, proc, p, N );
}
/*
// C printf format: %[parameter][flags][width][.precision][length]type
//
// Dao writef format: %[flags][width][.precision]type[color]
//
// Where 'flags', 'width' and 'precision' will conform to the C format,
// but 'type' can only be:
// d, i, o, u, x/X : for integer;
// e/E, f/F, g/G : for float and double;
// c/C : for character, C for local encoding;
// s/S : for string, S for local encoding;
// p : for any type, write address;
// a : automatic, for any type, write in the default format;
// Namely the standard ones except 'n', and plus 'a'.
//
// Optional 'color' format will be in form of: [foreground:background], [foreground]
// or [:background]. The supported color name format will depend on the color printing
// handle. Mininum requirement is the support of the following 8 color names:
// black, white, red, green, blue, yellow, magenta, cyan.
*/
static void DaoIO_Writef0( DaoStream *self, DaoProcess *proc, DaoValue *p[], int N )
{
DaoValue *value;
DString *fmt2;
DString *fgcolor = NULL;
DString *bgcolor = NULL;
DMap *cycmap = NULL;
const char *convs = "asSpcCdiouxXfFeEgG";
char F, *s, *end, *fg, *bg, *fmt, message[100];
int i, k, id = 0;
if( DaoIO_CheckMode( self, proc, DAO_STREAM_WRITABLE ) == 0 ) return;
fmt2 = DString_New();
for(i=0; itype > DAO_ARRAY ){
cycmap = DHash_New(0,0);
break;
}
}
s = p[0]->xString.value->chars;
end = s + p[0]->xString.value->size;
for(; s= N || p[id] == NULL ) goto NullParameter;
value = p[id];
/* flags: */
while( *s == '+' || *s == '-' || *s == '#' || *s == '0' || *s == ' ' ) s += 1;
while( isdigit( *s ) ) s += 1; /* width; */
if( *s == '.' ){ /* precision: */
s += 1;
while( isdigit( *s ) ) s += 1;
}
DString_SetBytes( fmt2, fmt, s - fmt + 1 );
if( strchr( convs, *s ) == NULL ){
DaoProcess_RaiseWarning( proc, NULL, "invalid format conversion" );
continue;
}
F = *s;
s += 1;
fg = bg = NULL;
if( *s == '[' ){
s += 1;
fmt = s;
while( isalnum( *s ) ) s += 1;
if( fgcolor == NULL ) fgcolor = DString_New();
DString_SetBytes( fgcolor, fmt, s - fmt );
if( fgcolor->size ) fg = fgcolor->chars;
if( *s == ':' ){
s += 1;
fmt = s;
while( isalnum( *s ) ) s += 1;
if( bgcolor == NULL ) bgcolor = DString_New();
DString_SetBytes( bgcolor, fmt, s - fmt );
if( bgcolor->size ) bg = bgcolor->chars;
}
if( *s != ']' ) goto WrongColor;
}else{
s -= 1;
}
if( fg || bg ){
if( DaoStream_SetColor( self, fg, bg ) == 0 ) goto WrongColor;
}
self->format = fmt2->chars;
if( F == 'c' || F == 'C' ){
if( value->type != DAO_INTEGER ) goto WrongParameter;
DString_Reset( fmt2, 0 );
DString_AppendWChar( fmt2, (size_t)value->xInteger.value );
self->format = "%s";
if( F == 'C' ) DString_ToLocal( fmt2 );
DaoStream_WriteString( self, fmt2 );
}else if( F == 'd' || F == 'i' || F == 'o' || F == 'x' || F == 'X' ){
if( value->type == DAO_NONE || value->type > DAO_FLOAT ) goto WrongParameter;
DString_InsertChars( fmt2, "ll", fmt2->size-1, 0, 2 );
self->format = fmt2->chars;
DaoStream_WriteInt( self, DaoValue_GetInteger( value ) );
}else if( toupper( F ) == 'E' || toupper( F ) == 'F' || toupper( F ) == 'G' ){
if( value->type == DAO_NONE || value->type > DAO_FLOAT ) goto WrongParameter;
DaoStream_WriteFloat( self, DaoValue_GetFloat( value ) );
}else if( F == 's' && value->type == DAO_STRING ){
DaoStream_WriteString( self, value->xString.value );
}else if( F == 'S' && value->type == DAO_STRING ){
DaoStream_WriteLocalString( self, value->xString.value );
}else if( F == 'p' ){
DaoStream_WritePointer( self, value );
}else if( F == 'a' ){
self->format = NULL;
if( value->type > DAO_ARRAY ) DMap_Reset( cycmap );
DaoValue_Print( value, self, cycmap, proc );
}else{
goto WrongParameter;
}
self->format = NULL;
if( fg || bg ) DaoStream_SetColor( self, NULL, NULL );
continue;
NullParameter:
sprintf( message, "%i-th parameter is null!", id );
DaoProcess_RaiseWarning( proc, NULL, message );
continue;
WrongColor:
sprintf( message, "%i-th parameter has wrong color format!", id );
DaoProcess_RaiseWarning( proc, NULL, message );
continue;
WrongParameter:
self->format = NULL;
if( fg || bg ) DaoStream_SetColor( self, NULL, NULL );
sprintf( message, "%i-th parameter has wrong type for format \"%s\"!", id, fmt2->chars );
DaoProcess_RaiseWarning( proc, NULL, message );
}
if( cycmap ) DMap_Delete( cycmap );
if( fgcolor ) DString_Delete( fgcolor );
if( bgcolor ) DString_Delete( bgcolor );
DString_Delete( fmt2 );
}
static void DaoIO_Writef( DaoProcess *proc, DaoValue *p[], int N )
{
DaoStream *self = & p[0]->xStream;
if( DaoIO_CheckMode( self, proc, DAO_STREAM_WRITABLE ) == 0 ) return;
DaoIO_Writef0( self, proc, p+1, N-1 );
}
static void DaoIO_Writef2( DaoProcess *proc, DaoValue *p[], int N )
{
DaoStream *stream = proc->stdioStream;
if( stream == NULL ) stream = proc->vmSpace->stdioStream;
if( DaoIO_CheckMode( stream, proc, DAO_STREAM_WRITABLE ) == 0 ) return;
DaoIO_Writef0( stream, proc, p, N );
}
static void DaoIO_Flush( DaoProcess *proc, DaoValue *p[], int N )
{
DaoStream *self = & p[0]->xStream;
DaoStream_Flush( self );
}
static void DaoIO_Read( DaoProcess *proc, DaoValue *p[], int N )
{
DaoStream *self = proc->stdioStream;
DString *ds = DaoProcess_PutChars( proc, "" );
int ch, size, amount = -1; /* amount=-2: all; amount=-1: line; amount>=0: bytes; */
char buf[IO_BUF_SIZE];
if( self == NULL ) self = proc->vmSpace->stdioStream;
if( N > 0 ){
self = (DaoStream*) p[0];
amount = -2;
}
if( DaoIO_CheckMode( self, proc, DAO_STREAM_READABLE ) == 0 ) return;
if( N > 1 ){
if( p[1]->type == DAO_INTEGER ){
amount = (int)p[1]->xInteger.value;
if( amount < 0 ){
DaoProcess_RaiseError( proc, NULL, "cannot read negative amount!" );
return;
}
}else{
amount = - 1 - p[1]->xEnum.value;
}
}
DString_Reset( ds, 0 );
self->Read( self, ds, amount );
if( self->mode & DAO_STREAM_AUTOCONV ) DString_ToUTF8( ds );
}
static void DaoIO_Check( DaoProcess *proc, DaoValue *p[], int N )
{
DaoStream *self = & p[0]->xStream;
int res = 0, what = p[1]->xEnum.value;
switch( what ){
case 0 : res = DaoStream_IsReadable( self ); break;
case 1 : res = DaoStream_IsWritable( self ); break;
case 2 : res = DaoStream_IsOpen( self ); break;
case 3 : res = DaoStream_EndOfStream( self ); break;
}
DaoProcess_PutBoolean( proc, res );
}
static void DaoIO_Check2( DaoProcess *proc, DaoValue *p[], int N )
{
DaoStream *self = & p[0]->xStream;
int res = 0, what = p[1]->xEnum.value;
switch( what ){
case 0 : res = (self->mode & DAO_STREAM_AUTOCONV) != 0; break;
}
DaoProcess_PutBoolean( proc, res );
}
static void DaoIO_Enable( DaoProcess *proc, DaoValue *p[], int N )
{
DaoStream *self = & p[0]->xStream;
int what = p[1]->xEnum.value;
if( p[2]->xBoolean.value ){
self->mode |= DAO_STREAM_AUTOCONV;
}else{
self->mode &= ~DAO_STREAM_AUTOCONV;
}
}
static void DaoStream_ReadLines( DaoStream *self, DaoList *list, DaoProcess *proc, int count, int chop )
{
DaoValue *res;
DaoString *line;
DaoVmCode *sect = DaoProcess_InitCodeSection( proc, 1 );
daoint i = 0;
if( sect == NULL ){
line = DaoString_New();
while( (count == 0 || (i++) < count) && DaoStream_ReadLine( self, line->value ) ){
if( line->value->size == 0 && self->AtEnd != NULL && self->AtEnd( self ) ) break;
if( chop ) DString_Chop( line->value, 0 );
DaoList_Append( list, (DaoValue*) line );
}
DaoString_Delete( line );
}else{
ushort_t entry = proc->topFrame->entry;
if( sect->b ){
DaoString tmp = {DAO_STRING,0,0,0,1,NULL};
DString tmp2 = DString_WrapChars( "" );
tmp.value = & tmp2;
line = (DaoString*) DaoProcess_SetValue( proc, sect->a, (DaoValue*)(void*) &tmp );
}
while( (count == 0 || (i++) < count) && DaoStream_ReadLine( self, line->value ) ){
if( line->value->size == 0 && self->AtEnd != NULL && self->AtEnd( self ) ) break;
if( chop ) DString_Chop( line->value, 0 );
proc->topFrame->entry = entry;
DaoProcess_Execute( proc );
if( proc->status == DAO_PROCESS_ABORTED ) break;
res = proc->stackValues[0];
if( res && res->type != DAO_NONE ) DaoList_Append( list, res );
}
DaoProcess_PopFrame( proc );
}
}
static void DaoIO_ReadLines( DaoProcess *proc, DaoValue *p[], int N )
{
DaoList *list = DaoProcess_PutList( proc );
int count = (int)p[1]->xInteger.value;
int chop = (int)p[2]->xBoolean.value;
if( DaoIO_CheckMode( (DaoStream*) p[0], proc, DAO_STREAM_READABLE ) == 0 ) return;
DaoStream_ReadLines( (DaoStream*) p[0], list, proc, count, chop );
}
DaoFunctionEntry dao_io_methods[] =
{
{ DaoIO_Write2, "write( invar ... : any )" },
{ DaoIO_Writef2, "writef( format: string, invar ... : any )" },
{ DaoIO_Writeln2, "writeln( invar ... : any )" },
{ DaoIO_Read, "read( )=>string" },
{ NULL, NULL }
};
static DaoFunctionEntry daoStreamMeths[] =
{
{ DaoIO_Write, "write( self: Stream, data: string )" },
{ DaoIO_Write, "write( self: Stream, invar ... : any )" },
{ DaoIO_Writef, "writef( self: Stream, format: string, invar ... : any )" },
{ DaoIO_Writeln, "writeln( self: Stream, invar ... : any )" },
{ DaoIO_Read, "read( self: Stream, count = -1 )=>string" },
{ DaoIO_Read, "read( self: Stream, amount: enum = $all )=>string" },
{ DaoIO_ReadLines, "readlines( self: Stream, numline=0, chop = false )[line: string=>none|@T]=>list<@T>" },
{ DaoIO_Flush, "flush( self: Stream )" },
{ DaoIO_Enable, "enable( self: Stream, what: enum, state: bool )" },
{ DaoIO_Check, "check( self: Stream, what: enum ) => bool" },
{ DaoIO_Check2, "check( self: Stream, what: enum ) => bool" },
{ NULL, NULL }
};
static DaoFunctionEntry daoDeviceMeths[] =
{
{ NULL, "read( self: Device, count = -1 ) => string" },
{ NULL, "write( self: Device, data: string )" },
{ NULL, "check( self: Device, what: enum ) => bool" },
{ NULL, NULL }
};
DaoTypeCore daoDeviceCore =
{
"Device", /* name */
0, /* size */
{ NULL }, /* bases */
{ NULL }, /* casts */
NULL, /* numbers */
daoDeviceMeths, /* methods */
NULL, NULL, /* GetField */
NULL, NULL, /* SetField */
NULL, NULL, /* GetItem */
NULL, NULL, /* SetItem */
NULL, NULL, /* Unary */
NULL, NULL, /* Binary */
NULL, NULL, /* Conversion */
NULL, NULL, /* ForEach */
NULL, /* Print */
NULL, /* Slice */
NULL, /* Compare */
NULL, /* Hash */
NULL, /* Create */
NULL, /* Copy */
NULL, /* Delete */
NULL /* HandleGC */
};
DaoTypeCore daoStreamCore =
{
"Stream", /* name */
sizeof(DaoStream), /* size */
{ NULL }, /* bases */
{ NULL }, /* casts */
NULL, /* numbers */
daoStreamMeths, /* methods */
DaoCstruct_CheckGetField, DaoCstruct_DoGetField, /* GetField */
NULL, NULL, /* SetField */
NULL, NULL, /* GetItem */
NULL, NULL, /* SetItem */
NULL, NULL, /* Unary */
NULL, NULL, /* Binary */
NULL, NULL, /* Conversion */
NULL, NULL, /* ForEach */
NULL, /* Print */
NULL, /* Slice */
NULL, /* Compare */
NULL, /* Hash */
NULL, /* Create */
NULL, /* Copy */
(DaoDeleteFunction) DaoStream_Delete, /* Delete */
NULL /* HandleGC */
};