0001
0002 #include <new>
0003 #include <stdio.h>
0004 #include <pscript.h>
0005 #include <psstdio.h>
0006 #include "psstdstream.h"
0007 #include <ndrstandard.h>
0008 #include <errno.h>
0009
0010 #define PSSTD_FILE_TYPE_TAG (PSSTD_STREAM_TYPE_TAG | 0x00000001)
0011
0012 PSFILE psstd_fopen(const PSChar *filename ,const PSChar *mode)
0013 {
0014 #ifndef PSUNICODE
0015 return (PSFILE)fopen(filename,mode);
0016 #else
0017 return (PSFILE)_wfopen(filename,mode);
0018 #endif
0019 }
0020
0021 PSInteger psstd_fread(void* buffer, PSInteger size, PSInteger count, PSFILE file)
0022 {
0023 PSInteger ret = (PSInteger)fread(buffer,size,count,(FILE *)file);
0024 return ret;
0025 }
0026
0027 PSUserPointer psstd_fgets(PSUserPointer buffer, PSInteger size, PSFILE file)
0028 {
0029 char *ret = fgets((char *)buffer,size,(FILE *)file);
0030
0031
0032 if (NULL!=ret)
0033 {
0034 int len = strlen(ret);
0035
0036 if (len>0 && ret[len-1]=='\n')
0037 {
0038 ret[len-1]=EXEOS;
0039
0040 if (len>1 && ret[len-2]=='\r')
0041 {
0042 ret[len-2]=EXEOS;
0043 }
0044 }
0045 }
0046
0047 return (PSUserPointer)ret;
0048
0049 }
0050
0051 PSInteger psstd_fwrite(const PSUserPointer buffer, PSInteger size, PSInteger count, PSFILE file)
0052 {
0053 return (PSInteger)fwrite(buffer,size,count,(FILE *)file);
0054 }
0055
0056 PSInteger psstd_fseek(PSFILE file, PSInteger offset, PSInteger origin)
0057 {
0058 PSInteger realorigin;
0059 switch(origin) {
0060 case PS_SEEK_CUR: realorigin = SEEK_CUR; break;
0061 case PS_SEEK_END: realorigin = SEEK_END; break;
0062 case PS_SEEK_SET: realorigin = SEEK_SET; break;
0063 default: return -1;
0064 }
0065 return fseek((FILE *)file,(long)offset,(int)realorigin);
0066 }
0067
0068 PSInteger psstd_ftell(PSFILE file)
0069 {
0070 return ftell((FILE *)file);
0071 }
0072
0073 PSInteger psstd_fflush(PSFILE file)
0074 {
0075 return fflush((FILE *)file);
0076 }
0077
0078 PSInteger psstd_fclose(PSFILE file)
0079 {
0080 return fclose((FILE *)file);
0081 }
0082
0083 PSInteger psstd_feof(PSFILE file)
0084 {
0085 return feof((FILE *)file);
0086 }
0087
0088
0089 struct PSFile : public PSStream {
0090 PSFile() { _handle = NULL; _owns = false;}
0091 PSFile(PSFILE file, bool owns) { _handle = file; _owns = owns;}
0092 virtual ~PSFile() { Close(); }
0093 bool Open(const PSChar *filename ,const PSChar *mode) {
0094 Close();
0095 if( (_handle = psstd_fopen(filename,mode)) ) {
0096 _owns = true;
0097 return true;
0098 }
0099 return false;
0100 }
0101 void Close() {
0102 if(_handle && _owns) {
0103 psstd_fclose(_handle);
0104 _handle = NULL;
0105 _owns = false;
0106 }
0107 }
0108 PSInteger Read(void *buffer,PSInteger size) {
0109 return psstd_fread(buffer,1,size,_handle);
0110 }
0111 PSUserPointer ReadLine(PSUserPointer buffer,PSInteger size) {
0112 return psstd_fgets(buffer,size,_handle);
0113 }
0114 PSInteger Write(void *buffer,PSInteger size) {
0115 return psstd_fwrite(buffer,1,size,_handle);
0116 }
0117 PSInteger Flush() {
0118 return psstd_fflush(_handle);
0119 }
0120 PSInteger Tell() {
0121 return psstd_ftell(_handle);
0122 }
0123 PSInteger Len() {
0124 PSInteger prevpos=Tell();
0125 Seek(0,PS_SEEK_END);
0126 PSInteger size=Tell();
0127 Seek(prevpos,PS_SEEK_SET);
0128 return size;
0129 }
0130 PSInteger Seek(PSInteger offset, PSInteger origin) {
0131 return psstd_fseek(_handle,offset,origin);
0132 }
0133 bool IsValid() { return _handle?true:false; }
0134 bool EOS() { return Tell()==Len()?true:false;}
0135 PSFILE GetHandle() {return _handle;}
0136 private:
0137 PSFILE _handle;
0138 bool _owns;
0139 };
0140
0141 static PSInteger _file__typeof(HPSCRIPTVM v)
0142 {
0143 ps_pushstring(v,_SC("file"),-1);
0144 return 1;
0145 }
0146
0147 static PSInteger _file_releasehook(PSUserPointer p, PSInteger PS_UNUSED_ARG(size))
0148 {
0149 PSFile *self = (PSFile*)p;
0150 self->~PSFile();
0151 ps_free(self,sizeof(PSFile));
0152 return 1;
0153 }
0154
0155 static PSInteger _file_constructor(HPSCRIPTVM v)
0156 {
0157 const PSChar *filename,*mode;
0158 bool owns = true;
0159 char dbg_name[PATH_MAX+1];
0160 PSFile *f;
0161 PSFILE newf;
0162 if(ps_gettype(v,2) == OT_STRING && ps_gettype(v,3) == OT_STRING) {
0163 ps_getstring(v, 2, &filename);
0164 ps_getstring(v, 3, &mode);
0165 newf = psstd_fopen(filename, mode);
0166 if(!newf) {
0167 int err = errno;
0168 snprintf(dbg_name, sizeof(dbg_name), _SC("cannot open file [%s]: %s"),
0169 filename, strerror(errno));
0170 return ps_throwerror(v, dbg_name);
0171 }
0172 } else if(ps_gettype(v,2) == OT_USERPOINTER) {
0173 owns = !(ps_gettype(v,3) == OT_NULL);
0174 ps_getuserpointer(v,2,&newf);
0175 } else {
0176 return ps_throwerror(v,_SC("wrong parameter"));
0177 }
0178
0179 f = new (ps_malloc(sizeof(PSFile)))PSFile(newf,owns);
0180 if(PS_FAILED(ps_setinstanceup(v,1,f))) {
0181 f->~PSFile();
0182 ps_free(f,sizeof(PSFile));
0183 return ps_throwerror(v, _SC("cannot create blob with negative size"));
0184 }
0185 ps_setreleasehook(v,1,_file_releasehook);
0186 return 0;
0187 }
0188
0189 static PSInteger _file_close(HPSCRIPTVM v)
0190 {
0191 PSFile *self = NULL;
0192 if(PS_SUCCEEDED(ps_getinstanceup(v,1,(PSUserPointer*)&self,(PSUserPointer)PSSTD_FILE_TYPE_TAG))
0193 && self != NULL)
0194 {
0195 self->Close();
0196 }
0197 return 0;
0198 }
0199
0200
0201 #define _DECL_FILE_FUNC(name,nparams,typecheck) {_SC(#name),_file_##name,nparams,typecheck}
0202 static const PSRegFunction _file_methods[] = {
0203 _DECL_FILE_FUNC(constructor,3,_SC("x")),
0204 _DECL_FILE_FUNC(_typeof,1,_SC("x")),
0205 _DECL_FILE_FUNC(close,1,_SC("x")),
0206 {NULL,(PSFUNCTION)0,0,NULL}
0207 };
0208
0209
0210
0211 PSRESULT psstd_createfile(HPSCRIPTVM v, PSFILE file,PSBool own)
0212 {
0213 PSInteger top = ps_gettop(v);
0214 ps_pushregistrytable(v);
0215 ps_pushstring(v,_SC("std_file"),-1);
0216 if(PS_SUCCEEDED(ps_get(v,-2))) {
0217 ps_remove(v,-2);
0218 ps_pushroottable(v);
0219 ps_pushuserpointer(v,file);
0220 if(own){
0221 ps_pushinteger(v,1);
0222 }
0223 else{
0224 ps_pushnull(v);
0225 }
0226 if(PS_SUCCEEDED( ps_call(v,3,PSTrue,PSFalse) )) {
0227 ps_remove(v,-2);
0228 return PS_OK;
0229 }
0230 }
0231 ps_settop(v,top);
0232 return PS_ERROR;
0233 }
0234
0235 PSRESULT psstd_getfile(HPSCRIPTVM v, PSInteger idx, PSFILE *file)
0236 {
0237 PSFile *fileobj = NULL;
0238 if(PS_SUCCEEDED(ps_getinstanceup(v,idx,(PSUserPointer*)&fileobj,(PSUserPointer)PSSTD_FILE_TYPE_TAG))) {
0239 *file = fileobj->GetHandle();
0240 return PS_OK;
0241 }
0242 return ps_throwerror(v,_SC("not a file"));
0243 }
0244
0245
0246
0247 #define IO_BUFFER_SIZE 2048
0248 struct IOBuffer {
0249 unsigned char buffer[IO_BUFFER_SIZE];
0250 PSInteger size;
0251 PSInteger ptr;
0252 PSFILE file;
0253 };
0254
0255 PSInteger _read_byte(IOBuffer *iobuffer)
0256 {
0257 if(iobuffer->ptr < iobuffer->size) {
0258
0259 PSInteger ret = iobuffer->buffer[iobuffer->ptr];
0260 iobuffer->ptr++;
0261 return ret;
0262 }
0263 else {
0264 if( (iobuffer->size = psstd_fread(iobuffer->buffer,1,IO_BUFFER_SIZE,iobuffer->file )) > 0 )
0265 {
0266 PSInteger ret = iobuffer->buffer[0];
0267 iobuffer->ptr = 1;
0268 return ret;
0269 }
0270 }
0271
0272 return 0;
0273 }
0274
0275 PSInteger _read_two_bytes(IOBuffer *iobuffer)
0276 {
0277 if(iobuffer->ptr < iobuffer->size) {
0278 if(iobuffer->size < 2) return 0;
0279 PSInteger ret = *((const wchar_t*)&iobuffer->buffer[iobuffer->ptr]);
0280 iobuffer->ptr += 2;
0281 return ret;
0282 }
0283 else {
0284 if( (iobuffer->size = psstd_fread(iobuffer->buffer,1,IO_BUFFER_SIZE,iobuffer->file )) > 0 )
0285 {
0286 if(iobuffer->size < 2) return 0;
0287 PSInteger ret = *((const wchar_t*)&iobuffer->buffer[0]);
0288 iobuffer->ptr = 2;
0289 return ret;
0290 }
0291 }
0292
0293 return 0;
0294 }
0295
0296 static PSInteger _io_file_lexfeed_PLAIN(PSUserPointer iobuf)
0297 {
0298 IOBuffer *iobuffer = (IOBuffer *)iobuf;
0299 return _read_byte(iobuffer);
0300
0301 }
0302
0303 #ifdef PSUNICODE
0304 static PSInteger _io_file_lexfeed_UTF8(PSUserPointer iobuf)
0305 {
0306 IOBuffer *iobuffer = (IOBuffer *)iobuf;
0307 #define READ(iobuf) \
0308 if((inchar = (unsigned char)_read_byte(iobuf)) == 0) \
0309 return 0;
0310
0311 static const PSInteger utf8_lengths[16] =
0312 {
0313 1,1,1,1,1,1,1,1,
0314 0,0,0,0,
0315 2,2,
0316 3,
0317 4
0318 };
0319 static const unsigned char byte_masks[5] = {0,0,0x1f,0x0f,0x07};
0320 unsigned char inchar;
0321 PSInteger c = 0;
0322 READ(iobuffer);
0323 c = inchar;
0324
0325 if(c >= 0x80) {
0326 PSInteger tmp;
0327 PSInteger codelen = utf8_lengths[c>>4];
0328 if(codelen == 0)
0329 return 0;
0330
0331 tmp = c&byte_masks[codelen];
0332 for(PSInteger n = 0; n < codelen-1; n++) {
0333 tmp<<=6;
0334 READ(iobuffer);
0335 tmp |= inchar & 0x3F;
0336 }
0337 c = tmp;
0338 }
0339 return c;
0340 }
0341 #endif
0342
0343 static PSInteger _io_file_lexfeed_UCS2_LE(PSUserPointer iobuf)
0344 {
0345 PSInteger ret;
0346 IOBuffer *iobuffer = (IOBuffer *)iobuf;
0347 if( (ret = _read_two_bytes(iobuffer)) > 0 )
0348 return ret;
0349 return 0;
0350 }
0351
0352 static PSInteger _io_file_lexfeed_UCS2_BE(PSUserPointer iobuf)
0353 {
0354 PSInteger c;
0355 IOBuffer *iobuffer = (IOBuffer *)iobuf;
0356 if( (c = _read_two_bytes(iobuffer)) > 0 ) {
0357 c = ((c>>8)&0x00FF)| ((c<<8)&0xFF00);
0358 return c;
0359 }
0360 return 0;
0361 }
0362
0363 PSInteger file_read(PSUserPointer file,PSUserPointer buf,PSInteger size)
0364 {
0365 PSInteger ret;
0366 if( ( ret = psstd_fread(buf,1,size,(PSFILE)file ))!=0 )return ret;
0367 return -1;
0368 }
0369
0370 PSInteger file_write(PSUserPointer file,PSUserPointer p,PSInteger size)
0371 {
0372 return psstd_fwrite(p,1,size,(PSFILE)file);
0373 }
0374
0375 PSRESULT psstd_loadfile(HPSCRIPTVM v,const PSChar *filename,PSBool printerror)
0376 {
0377 PSFILE file = psstd_fopen(filename,_SC("rb"));
0378
0379 PSInteger ret;
0380 unsigned short us;
0381 unsigned char uc;
0382 PSLEXREADFUNC func = _io_file_lexfeed_PLAIN;
0383 if(file){
0384 ret = psstd_fread(&us,1,2,file);
0385 if(ret != 2) {
0386
0387 us = 0;
0388 }
0389 if(us == PS_BYTECODE_STREAM_TAG) {
0390 psstd_fseek(file,0,PS_SEEK_SET);
0391 if(PS_SUCCEEDED(ps_readclosure(v,file_read,file))) {
0392 psstd_fclose(file);
0393 return PS_OK;
0394 }
0395 }
0396 else {
0397
0398 switch(us)
0399 {
0400
0401 case 0xFFFE: func = _io_file_lexfeed_UCS2_BE; break;
0402 case 0xFEFF: func = _io_file_lexfeed_UCS2_LE; break;
0403 case 0xBBEF:
0404 if(psstd_fread(&uc,1,sizeof(uc),file) == 0) {
0405 psstd_fclose(file);
0406 return ps_throwerror(v,_SC("io error"));
0407 }
0408 if(uc != 0xBF) {
0409 psstd_fclose(file);
0410 return ps_throwerror(v,_SC("Unrecognozed ecoding"));
0411 }
0412 #ifdef PSUNICODE
0413 func = _io_file_lexfeed_UTF8;
0414 #else
0415 func = _io_file_lexfeed_PLAIN;
0416 #endif
0417 break;
0418 default: psstd_fseek(file,0,PS_SEEK_SET); break;
0419 }
0420 IOBuffer buffer;
0421 buffer.ptr = 0;
0422 buffer.size = 0;
0423 buffer.file = file;
0424 if(PS_SUCCEEDED(ps_compile(v,func,&buffer,filename,printerror))){
0425 psstd_fclose(file);
0426 return PS_OK;
0427 }
0428 }
0429 psstd_fclose(file);
0430 return PS_ERROR;
0431 }
0432 return ps_throwerror(v,_SC("cannot open the file"));
0433 }
0434
0435
0436
0437
0438
0439
0440
0441
0442 static PSInteger mem_read(PSUserPointer memreader,PSUserPointer buf,PSInteger size)
0443 {
0444 PSInteger ret;
0445 PSMemReader *reader = (PSMemReader *)memreader;
0446 int out_block = reader->size - reader->offset;
0447
0448 if (out_block > size)
0449 {
0450 out_block = size;
0451 }
0452 else if (out_block==0)
0453 {
0454
0455 ret = -1;
0456 goto out;
0457 }
0458
0459 memcpy(buf, reader->memptr+reader->offset, out_block);
0460 reader->offset+=out_block;
0461 ret = out_block;
0462
0463 out:
0464 return ret;
0465 }
0466
0467
0468
0469
0470
0471
0472
0473 PSRESULT psstd_loadmem(HPSCRIPTVM v, PSMemReader *reader)
0474 {
0475 if(PS_SUCCEEDED(ps_readclosure(v,mem_read,reader))) {
0476 return PS_OK;
0477 }
0478 return PS_ERROR;
0479 }
0480
0481 PSRESULT psstd_dofile(HPSCRIPTVM v,const PSChar *filename,PSBool retval,PSBool printerror)
0482 {
0483 if(PS_SUCCEEDED(psstd_loadfile(v,filename,printerror))) {
0484 ps_push(v,-2);
0485 if(PS_SUCCEEDED(ps_call(v,1,retval,PSTrue))) {
0486 ps_remove(v,retval?-2:-1);
0487 return 1;
0488 }
0489 ps_pop(v,1);
0490 }
0491 return PS_ERROR;
0492 }
0493
0494 PSRESULT psstd_writeclosuretofile(HPSCRIPTVM v,const PSChar *filename)
0495 {
0496 PSFILE file = psstd_fopen(filename,_SC("wb+"));
0497 if(!file) return ps_throwerror(v,_SC("cannot open the file"));
0498 if(PS_SUCCEEDED(ps_writeclosure(v,file_write,file))) {
0499 psstd_fclose(file);
0500 return PS_OK;
0501 }
0502 psstd_fclose(file);
0503 return PS_ERROR;
0504 }
0505
0506 PSInteger _g_io_loadfile(HPSCRIPTVM v)
0507 {
0508 const PSChar *filename;
0509 PSBool printerror = PSFalse;
0510 ps_getstring(v,2,&filename);
0511 if(ps_gettop(v) >= 3) {
0512 ps_getbool(v,3,&printerror);
0513 }
0514 if(PS_SUCCEEDED(psstd_loadfile(v,filename,printerror)))
0515 return 1;
0516 return PS_ERROR;
0517 }
0518
0519 PSInteger _g_io_writeclosuretofile(HPSCRIPTVM v)
0520 {
0521 const PSChar *filename;
0522 ps_getstring(v,2,&filename);
0523 if(PS_SUCCEEDED(psstd_writeclosuretofile(v,filename)))
0524 return 1;
0525 return PS_ERROR;
0526 }
0527
0528 PSInteger _g_io_dofile(HPSCRIPTVM v)
0529 {
0530 const PSChar *filename;
0531 PSBool printerror = PSFalse;
0532 ps_getstring(v,2,&filename);
0533 if(ps_gettop(v) >= 3) {
0534 ps_getbool(v,3,&printerror);
0535 }
0536 ps_push(v,1);
0537 if(PS_SUCCEEDED(psstd_dofile(v,filename,PSTrue,printerror)))
0538 return 1;
0539 return PS_ERROR;
0540 }
0541
0542 #define _DECL_GLOBALIO_FUNC(name,nparams,typecheck) {_SC(#name),_g_io_##name,nparams,typecheck}
0543 static const PSRegFunction iolib_funcs[]={
0544 _DECL_GLOBALIO_FUNC(loadfile,-2,_SC(".sb")),
0545 _DECL_GLOBALIO_FUNC(dofile,-2,_SC(".sb")),
0546 _DECL_GLOBALIO_FUNC(writeclosuretofile,3,_SC(".sc")),
0547 {NULL,(PSFUNCTION)0,0,NULL}
0548 };
0549
0550 PSRESULT psstd_register_iolib(HPSCRIPTVM v)
0551 {
0552 PSInteger top = ps_gettop(v);
0553
0554 declare_stream(v,_SC("file"),(PSUserPointer)PSSTD_FILE_TYPE_TAG,_SC("std_file"),_file_methods,iolib_funcs);
0555 ps_pushstring(v,_SC("stdout"),-1);
0556 psstd_createfile(v,stdout,PSFalse);
0557 ps_newslot(v,-3,PSFalse);
0558 ps_pushstring(v,_SC("stdin"),-1);
0559 psstd_createfile(v,stdin,PSFalse);
0560 ps_newslot(v,-3,PSFalse);
0561 ps_pushstring(v,_SC("stderr"),-1);
0562 psstd_createfile(v,stderr,PSFalse);
0563 ps_newslot(v,-3,PSFalse);
0564 ps_settop(v,top);
0565 return PS_OK;
0566 }