1 /*----------------------------------------------------------------------------
2 ChucK Concurrent, On-the-fly Audio Programming Language
3 Compiler and Virtual Machine
5 Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6 http://chuck.cs.princeton.edu/
7 http://soundlab.cs.princeton.edu/
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
29 // author: Ge Wang (gewang@cs.princeton.edu)
30 // Perry R. Cook (prc@cs.princeton.edu)
32 //-----------------------------------------------------------------------------
37 #include "util_buffers.h"
38 #include "util_console.h"
39 #include "util_math.h"
40 #include "util_string.h"
41 #include "util_thread.h"
42 #include "chuck_type.h"
43 #include "chuck_instr.h"
44 #include "chuck_globals.h"
46 #if defined(__PLATFORM_WIN32__)
50 int setenv( const char *n
, const char *v
, int i
)
52 return !SetEnvironmentVariable(n
, v
);
61 // for ConsoleInput and StringTokenizer
64 #include "util_thread.h"
68 #ifndef __DISABLE_KBHIT__
70 CK_DLL_CTOR( KBHit_ctor
);
71 CK_DLL_DTOR( KBHit_dtor
);
72 CK_DLL_MFUN( KBHit_on
);
73 CK_DLL_MFUN( KBHit_off
);
74 CK_DLL_MFUN( KBHit_state
);
75 CK_DLL_MFUN( KBHit_hit
);
76 CK_DLL_MFUN( KBHit_more
);
77 CK_DLL_MFUN( KBHit_getchar
);
78 CK_DLL_MFUN( KBHit_can_wait
);
80 static t_CKUINT KBHit_offset_data
= 0;
81 #endif // __DISABLE_KBHIT__
83 #ifndef __DISABLE_PROMPTER__
85 CK_DLL_CTOR( Skot_ctor
);
86 CK_DLL_DTOR( Skot_dtor
);
87 CK_DLL_MFUN( Skot_prompt
);
88 CK_DLL_MFUN( Skot_prompt2
);
89 CK_DLL_MFUN( Skot_more
);
90 CK_DLL_MFUN( Skot_getLine
);
91 CK_DLL_MFUN( Skot_can_wait
);
93 static t_CKUINT Skot_offset_data
= 0;
94 #endif // __DISABLE_PROMPTER__
97 CK_DLL_CTOR( StrTok_ctor
);
98 CK_DLL_DTOR( StrTok_dtor
);
99 CK_DLL_MFUN( StrTok_set
);
100 CK_DLL_MFUN( StrTok_reset
);
101 CK_DLL_MFUN( StrTok_more
);
102 CK_DLL_MFUN( StrTok_next
);
103 CK_DLL_MFUN( StrTok_next2
);
104 CK_DLL_MFUN( StrTok_get
);
105 CK_DLL_MFUN( StrTok_get2
);
106 CK_DLL_MFUN( StrTok_size
);
108 static t_CKUINT StrTok_offset_data
= 0;
115 CK_DLL_CTOR( VCR_ctor
);
116 CK_DLL_MFUN( VCR_load
);
117 CK_DLL_MFUN( VCR_reset
);
118 CK_DLL_MFUN( VCR_seek
);
119 CK_DLL_MFUN( VCR_more
);
120 CK_DLL_MFUN( VCR_curr
);
121 CK_DLL_MFUN( VCR_next
);
122 CK_DLL_MFUN( VCR_pos
);
123 CK_DLL_MFUN( VCR_size
);
124 CK_DLL_MFUN( VCR_name
);
126 static t_CKUINT VCR_offset_data
= 0;
129 CK_DLL_CTOR( Cereal_ctor
);
130 CK_DLL_MFUN( Cereal_open
);
131 CK_DLL_MFUN( Cereal_close
);
132 CK_DLL_MFUN( Cereal_send
);
133 CK_DLL_MFUN( Cereal_recv
);
134 CK_DLL_MFUN( Cereal_more
);
136 static t_CKUINT Cereal_offset_data
= 0;
143 //-----------------------------------------------------------------------------
144 // name: libstd_query()
145 // desc: query entry point
146 //-----------------------------------------------------------------------------
147 DLL_QUERY
libstd_query( Chuck_DL_Query
* QUERY
)
150 Chuck_Env
* env
= Chuck_Env::instance();
152 QUERY
->setname( QUERY
, "Std" );
155 std.rand2f( 100.0, 1000.0 ) => stdout;
158 // register deprecate
159 type_engine_register_deprecate( env
, "std", "Std" );
162 QUERY
->begin_class( QUERY
, "Std", "Object" );
165 QUERY
->add_sfun( QUERY
, abs_impl
, "int", "abs" );
166 QUERY
->add_arg( QUERY
, "int", "value" );
169 QUERY
->add_sfun( QUERY
, fabs_impl
, "float", "fabs" );
170 QUERY
->add_arg( QUERY
, "float", "value" );
173 QUERY
->add_sfun( QUERY
, rand_impl
, "int", "rand"); //! return int between 0 and RAND_MAX
176 QUERY
->add_sfun( QUERY
, rand2_impl
, "int", "rand2" ); //! integer between [min,max]
177 QUERY
->add_arg( QUERY
, "int", "min" );
178 QUERY
->add_arg( QUERY
, "int", "max" );
181 QUERY
->add_sfun( QUERY
, randf_impl
, "float", "randf" ); //! rand between -1.0,1.0
184 QUERY
->add_sfun( QUERY
, rand2f_impl
, "float", "rand2f" ); //! rand between min and max
185 QUERY
->add_arg( QUERY
, "float", "min" );
186 QUERY
->add_arg( QUERY
, "float", "max" );
189 QUERY
->add_sfun( QUERY
, srand_impl
, "void", "srand" );
190 QUERY
->add_arg( QUERY
, "int", "seed" );
193 QUERY
->add_sfun( QUERY
, sgn_impl
, "float", "sgn" ); //! return sign of value (-1, 0, 1)
194 QUERY
->add_arg( QUERY
, "float", "value" );
197 //! see \example std.ck
198 QUERY
->add_sfun( QUERY
, system_impl
, "int", "system" ); //! issue system command
199 QUERY
->add_arg( QUERY
, "string", "cmd" );
202 QUERY
->add_sfun( QUERY
, atoi_impl
, "int", "atoi" ); //! string to integer
203 QUERY
->add_arg( QUERY
, "string", "value" );
206 QUERY
->add_sfun( QUERY
, atof_impl
, "float", "atof" ); //! string to float
207 QUERY
->add_arg( QUERY
, "string", "value" );
210 QUERY
->add_sfun( QUERY
, itoa_impl
, "string", "itoa" ); //! int to string
211 QUERY
->add_arg( QUERY
, "int", "i" );
214 QUERY
->add_sfun( QUERY
, ftoa_impl
, "string", "ftoa" ); //! float to string
215 QUERY
->add_arg( QUERY
, "float", "f" );
216 QUERY
->add_arg( QUERY
, "int", "precision" );
219 QUERY
->add_sfun( QUERY
, getenv_impl
, "string", "getenv" ); //! fetch environment variable
220 QUERY
->add_arg( QUERY
, "string", "value" );
223 QUERY
->add_sfun( QUERY
, setenv_impl
, "int", "setenv" ); //! set environment variable
224 QUERY
->add_arg( QUERY
, "string", "key" );
225 QUERY
->add_arg( QUERY
, "string", "value" );
228 //! see \example mand-o-matic.ck
229 QUERY
->add_sfun( QUERY
, mtof_impl
, "float", "mtof" ); //! midi note to frequency
230 QUERY
->add_arg( QUERY
, "float", "value" );
233 QUERY
->add_sfun( QUERY
, ftom_impl
, "float", "ftom" ); //! frequency to midi note
234 QUERY
->add_arg( QUERY
, "float", "value" );
237 QUERY
->add_sfun( QUERY
, powtodb_impl
, "float", "powtodb" ); //! linear power to decibel
238 QUERY
->add_arg( QUERY
, "float", "value" );
241 QUERY
->add_sfun( QUERY
, rmstodb_impl
, "float", "rmstodb" ); //! rms to decibel
242 QUERY
->add_arg( QUERY
, "float", "value" );
245 QUERY
->add_sfun( QUERY
, dbtopow_impl
, "float", "dbtopow" ); //! decibel to linear
246 QUERY
->add_arg( QUERY
, "float", "value" );
249 QUERY
->add_sfun( QUERY
, dbtorms_impl
, "float", "dbtorms" ); //! decibel to rms
250 QUERY
->add_arg( QUERY
, "float", "value" );
253 QUERY
->end_class( QUERY
);
256 srand( time( NULL
) );
258 Chuck_DL_Func
* func
= NULL
;
260 #ifndef __DISABLE_KBHIT__
262 // begin class (KBHit)
263 if( !type_engine_import_class_begin( env
, "KBHit", "Event",
264 env
->global(), KBHit_ctor
,
268 // add member variable
269 KBHit_offset_data
= type_engine_import_mvar( env
, "int", "@KBHit_data", FALSE
);
270 if( KBHit_offset_data
== CK_INVALID_OFFSET
) goto error
;
273 func
= make_new_mfun( "void", "on", KBHit_on
);
274 if( !type_engine_import_mfun( env
, func
) ) goto error
;
277 func
= make_new_mfun( "void", "off", KBHit_off
);
278 if( !type_engine_import_mfun( env
, func
) ) goto error
;
281 func
= make_new_mfun( "void", "state", KBHit_state
);
282 if( !type_engine_import_mfun( env
, func
) ) goto error
;
285 func
= make_new_mfun( "Event", "hit", KBHit_hit
);
286 if( !type_engine_import_mfun( env
, func
) ) goto error
;
289 func
= make_new_mfun( "int", "more", KBHit_more
);
290 if( !type_engine_import_mfun( env
, func
) ) goto error
;
293 func
= make_new_mfun( "int", "getchar", KBHit_getchar
);
294 if( !type_engine_import_mfun( env
, func
) ) goto error
;
297 func
= make_new_mfun( "int", "can_wait", KBHit_can_wait
);
298 if( !type_engine_import_mfun( env
, func
) ) goto error
;
301 type_engine_import_class_end( env
);
304 KBHitManager::init();
305 #endif // __DISABLE_KBHIT__
308 // register deprecate
309 type_engine_register_deprecate( env
, "Skot", "ConsoleInput" );
311 #ifndef __DISABLE_PROMPTER__
312 // begin class (Skot)
313 if( !type_engine_import_class_begin( env
, "ConsoleInput", "Event",
314 env
->global(), Skot_ctor
,
318 // add member variable
319 Skot_offset_data
= type_engine_import_mvar( env
, "int", "@Skot_data", FALSE
);
320 if( Skot_offset_data
== CK_INVALID_OFFSET
) goto error
;
323 func
= make_new_mfun( "Event", "prompt", Skot_prompt
);
324 if( !type_engine_import_mfun( env
, func
) ) goto error
;
327 func
= make_new_mfun( "Event", "prompt", Skot_prompt2
);
328 func
->add_arg( "string", "what" );
329 if( !type_engine_import_mfun( env
, func
) ) goto error
;
332 func
= make_new_mfun( "int", "more", Skot_more
);
333 if( !type_engine_import_mfun( env
, func
) ) goto error
;
336 func
= make_new_mfun( "string", "getLine", Skot_getLine
);
337 if( !type_engine_import_mfun( env
, func
) ) goto error
;
340 func
= make_new_mfun( "int", "can_wait", Skot_can_wait
);
341 if( !type_engine_import_mfun( env
, func
) ) goto error
;
344 type_engine_import_class_end( env
);
345 #endif // __DISABLE_PROMPTER__
348 // register deprecate
349 type_engine_register_deprecate( env
, "PRC", "StringTokenizer" );
351 // begin class (StrTok)
352 if( !type_engine_import_class_begin( env
, "StringTokenizer", "Object",
353 env
->global(), StrTok_ctor
,
357 // add member variable
358 StrTok_offset_data
= type_engine_import_mvar( env
, "int", "@StrTok_data", FALSE
);
359 if( StrTok_offset_data
== CK_INVALID_OFFSET
) goto error
;
362 func
= make_new_mfun( "void", "set", StrTok_set
);
363 func
->add_arg( "string", "line" );
364 if( !type_engine_import_mfun( env
, func
) ) goto error
;
367 func
= make_new_mfun( "void", "reset", StrTok_reset
);
368 if( !type_engine_import_mfun( env
, func
) ) goto error
;
371 func
= make_new_mfun( "int", "more", StrTok_more
);
372 if( !type_engine_import_mfun( env
, func
) ) goto error
;
375 func
= make_new_mfun( "string", "next", StrTok_next
);
376 if( !type_engine_import_mfun( env
, func
) ) goto error
;
379 func
= make_new_mfun( "string", "next", StrTok_next2
);
380 func
->add_arg( "string", "out" );
381 if( !type_engine_import_mfun( env
, func
) ) goto error
;
384 func
= make_new_mfun( "string", "get", StrTok_get
);
385 func
->add_arg( "int", "index" );
386 if( !type_engine_import_mfun( env
, func
) ) goto error
;
389 func
= make_new_mfun( "string", "get", StrTok_get2
);
390 func
->add_arg( "int", "index" );
391 func
->add_arg( "string", "out" );
392 if( !type_engine_import_mfun( env
, func
) ) goto error
;
395 func
= make_new_mfun( "int", "size", StrTok_size
);
396 if( !type_engine_import_mfun( env
, func
) ) goto error
;
399 type_engine_import_class_end( env
);
406 if( !type_engine_import_class_begin( env
, "VCR", "Object",
407 env
->global(), VCR_ctor
) )
410 // add member variable
411 VCR_offset_data
= type_engine_import_mvar( env
, "int", "@me", FALSE
);
412 if( VCR_offset_data
== CK_INVALID_OFFSET
) goto error
;
415 func
= make_new_mfun( "int", "load", VCR_load
);
416 func
->add_arg( "string", "filename" );
417 func
->add_arg( "int", "column" );
418 if( !type_engine_import_mfun( env
, func
) ) goto error
;
421 func
= make_new_mfun( "int", "reset", VCR_reset
);
422 if( !type_engine_import_mfun( env
, func
) ) goto error
;
425 func
= make_new_mfun( "int", "seek", VCR_seek
);
426 func
->add_arg( "int", "where" );
427 if( !type_engine_import_mfun( env
, func
) ) goto error
;
430 func
= make_new_mfun( "int", "more", VCR_more
);
431 if( !type_engine_import_mfun( env
, func
) ) goto error
;
434 func
= make_new_mfun( "float", "curr", VCR_curr
);
435 if( !type_engine_import_mfun( env
, func
) ) goto error
;
438 func
= make_new_mfun( "int", "next", VCR_next
);
439 if( !type_engine_import_mfun( env
, func
) ) goto error
;
442 func
= make_new_mfun( "int", "pos", VCR_pos
);
443 if( !type_engine_import_mfun( env
, func
) ) goto error
;
446 func
= make_new_mfun( "int", "size", VCR_size
);
447 if( !type_engine_import_mfun( env
, func
) ) goto error
;
450 func
= make_new_mfun( "string", "name", VCR_name
);
451 if( !type_engine_import_mfun( env
, func
) ) goto error
;
453 // end the class import
454 type_engine_import_class_end( env
);
457 #if defined(__PLATFORM_WIN32__)
458 // begin class (Cereal)
459 if( !type_engine_import_class_begin( env
, "Cereal", "Object",
460 env
->global(), Cereal_ctor
) )
464 Cereal_offset_data
= type_engine_import_mvar( env
, "int", "@Cereal_data", FALSE
);
465 if( Cereal_offset_data
== CK_INVALID_OFFSET
) goto error
;
468 func
= make_new_mfun( "int", "open", Cereal_open
);
469 func
->add_arg( "string", "name" );
470 func
->add_arg( "int", "baudrate" );
471 if( !type_engine_import_mfun( env
, func
) ) goto error
;
474 func
= make_new_mfun( "void", "close", Cereal_close
);
475 if( !type_engine_import_mfun( env
, func
) ) goto error
;
478 func
= make_new_mfun( "int", "more", Cereal_more
);
479 if( !type_engine_import_mfun( env
, func
) ) goto error
;
482 func
= make_new_mfun( "int", "send", Cereal_send
);
483 func
->add_arg( "int", "bite" );
484 if( !type_engine_import_mfun( env
, func
) ) goto error
;
487 func
= make_new_mfun( "int", "recv", Cereal_recv
);
488 if( !type_engine_import_mfun( env
, func
) ) goto error
;
491 type_engine_import_class_end( env
);
504 // end the class import
505 type_engine_import_class_end( env
);
511 #define RAND_INV_RANGE(r) (RAND_MAX / (r))
513 int irand_exclusive ( int max
) {
516 while (x
>= max
* RAND_INV_RANGE (max
))
519 x
/= RAND_INV_RANGE (max
);
525 CK_DLL_SFUN( abs_impl
)
527 t_CKINT v
= GET_CK_INT(ARGS
);
528 RETURN
->v_int
= v
>= 0 ? v
: -v
;
532 CK_DLL_SFUN( fabs_impl
)
534 t_CKFLOAT v
= GET_CK_FLOAT(ARGS
);
535 RETURN
->v_float
= v
>= 0.0 ? v
: -v
;
536 //RETURN->v_float = ::fabs( GET_CK_FLOAT(ARGS) );
540 CK_DLL_SFUN( rand_impl
)
542 RETURN
->v_int
= ::rand();
546 CK_DLL_SFUN( randf_impl
)
548 RETURN
->v_float
= ( 2.0 * ::rand() / (t_CKFLOAT
)RAND_MAX
- 1.0 );
552 CK_DLL_SFUN( rand2f_impl
)
554 t_CKFLOAT min
= GET_CK_FLOAT(ARGS
), max
= *((t_CKFLOAT
*)ARGS
+ 1);
555 RETURN
->v_float
= min
+ (max
-min
)*(::rand()/(t_CKFLOAT
)RAND_MAX
);
559 CK_DLL_SFUN( rand2_impl
) // inclusive.
561 int min
= *(int *)ARGS
, max
= *((int *)ARGS
+ 1);
562 int range
= max
- min
;
567 //else if ( range < RAND_MAX / 2 ) {
568 // RETURN->v_int = ( range > 0 ) ? min + irand_exclusive(1 + range) : max + irand_exclusive ( -range + 1 ) ;
574 RETURN
->v_int
= min
+ (int) ( (1.0 + range
) * ( ::rand()/(RAND_MAX
+1.0) ) );
578 RETURN
->v_int
= min
- (int) ( (-range
+ 1.0) * ( ::rand()/(RAND_MAX
+1.0) ) );
584 CK_DLL_SFUN( srand_impl
)
586 t_CKINT seed
= GET_CK_INT(ARGS
);
591 CK_DLL_SFUN( sgn_impl
)
593 t_CKFLOAT v
= GET_CK_FLOAT(ARGS
);
594 RETURN
->v_float
= v
== 0.0f
? 0.0f
: ( v
> 0.0f
? 1.0f
: -1.0f
);
598 CK_DLL_SFUN( system_impl
)
600 const char * cmd
= GET_CK_STRING(ARGS
)->str
.c_str();
602 // check globals for permission
603 if( !g_enable_system_cmd
)
605 fprintf( stderr
, "[chuck]:error: VM not authorized to call Std.system( string )...\n" );
606 fprintf( stderr
, "[chuck]: (command string was: \"%s\")\n", cmd
);
607 fprintf( stderr
, "[chuck]: (note: enable via --caution-to-the-wind flag or other means)\n" );
613 EM_log( CK_LOG_SEVERE
, "invoking system( CMD )..." );
615 EM_log( CK_LOG_SEVERE
, "CMD: \"%s\"", cmd
);
617 RETURN
->v_int
= system( cmd
);
622 CK_DLL_SFUN( atoi_impl
)
624 Chuck_String
* str
= GET_CK_STRING(ARGS
);
627 const char * v
= str
->str
.c_str();
628 RETURN
->v_int
= atoi( v
);
637 CK_DLL_SFUN( atof_impl
)
639 Chuck_String
* str
= GET_CK_STRING(ARGS
);
642 const char * v
= GET_CK_STRING(ARGS
)->str
.c_str();
643 RETURN
->v_float
= atof( v
);
647 RETURN
->v_float
= 0.0;
652 CK_DLL_SFUN( itoa_impl
)
654 t_CKINT i
= GET_CK_INT(ARGS
);
655 // TODO: memory leak, please fix. Thanks.
656 Chuck_String
* a
= (Chuck_String
*)instantiate_and_initialize_object( &t_string
, NULL
);
658 RETURN
->v_string
= a
;
662 CK_DLL_SFUN( ftoa_impl
)
664 t_CKFLOAT f
= GET_NEXT_FLOAT(ARGS
);
665 t_CKINT p
= GET_NEXT_INT(ARGS
);
666 Chuck_String
* a
= (Chuck_String
*)instantiate_and_initialize_object( &t_string
, NULL
);
667 a
->str
= ftoa( f
, (t_CKUINT
)p
);
668 RETURN
->v_string
= a
;
672 static Chuck_String g_str
; // PROBLEM: not thread friendly
673 CK_DLL_SFUN( getenv_impl
)
675 const char * v
= GET_CK_STRING(ARGS
)->str
.c_str();
676 const char * s
= getenv( v
);
677 Chuck_String
* a
= (Chuck_String
*)instantiate_and_initialize_object( &t_string
, NULL
);
679 RETURN
->v_string
= a
;
683 CK_DLL_SFUN( setenv_impl
)
685 const char * v1
= GET_NEXT_STRING(ARGS
)->str
.c_str();
686 const char * v2
= GET_NEXT_STRING(ARGS
)->str
.c_str();
687 RETURN
->v_int
= setenv( v1
, v2
, 1 );
692 CK_DLL_SFUN( mtof_impl
)
694 t_CKFLOAT v
= GET_CK_FLOAT(ARGS
);
695 RETURN
->v_float
= mtof(v
);
699 CK_DLL_SFUN( ftom_impl
)
701 t_CKFLOAT v
= GET_CK_FLOAT(ARGS
);
702 RETURN
->v_float
= ftom(v
);
706 CK_DLL_SFUN( powtodb_impl
)
708 t_CKFLOAT v
= GET_CK_FLOAT(ARGS
);
709 RETURN
->v_float
= powtodb(v
);
713 CK_DLL_SFUN( rmstodb_impl
)
715 t_CKFLOAT v
= GET_CK_FLOAT(ARGS
);
716 RETURN
->v_float
= rmstodb(v
);
720 CK_DLL_SFUN( dbtopow_impl
)
722 t_CKFLOAT v
= GET_CK_FLOAT(ARGS
);
723 RETURN
->v_float
= dbtopow(v
);
727 CK_DLL_SFUN( dbtorms_impl
)
729 t_CKFLOAT v
= GET_CK_FLOAT(ARGS
);
730 RETURN
->v_float
= dbtorms(v
);
736 #ifndef __DISABLE_KBHIT__
738 CBufferAdvance
* KBHitManager::the_buf
= NULL
;
739 t_CKINT
KBHitManager::the_onoff
= 0;
740 t_CKBOOL
KBHitManager::the_init
= FALSE
;
741 XThread
* KBHitManager::the_thread
;
742 #define BUFFER_SIZE 1024
745 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
746 static void * kb_loop( void * )
748 static unsigned int __stdcall
kb_loop( void * )
752 EM_log( CK_LOG_INFO
, "starting kb loop..." );
755 while( KBHitManager::the_init
)
758 if( KBHitManager::the_onoff
)
760 // see if we have kb hit
766 KBHitManager::the_buf
->put( &c
, 1 );
779 t_CKBOOL
KBHitManager::init()
782 if( the_buf
) return FALSE
;
784 EM_log( CK_LOG_INFO
, "initializing KBHitManager..." );
785 the_buf
= new CBufferAdvance
;
786 if( !the_buf
->initialize( BUFFER_SIZE
, sizeof(t_CKINT
) ) )
788 EM_log( CK_LOG_SEVERE
, "KBHitManager: couldn't allocate central KB buffer..." );
789 SAFE_DELETE( the_buf
);
795 the_thread
= new XThread
;
796 the_thread
->start( kb_loop
, NULL
);
804 void KBHitManager::shutdown()
806 EM_log( CK_LOG_INFO
, "shutting down KBHitManager..." );
807 SAFE_DELETE( the_buf
);
816 void KBHitManager::on()
825 void KBHitManager::off()
828 if( kb_ready() && the_onoff
== 0 )
834 t_CKBOOL
KBHitManager::open( KBHit
* kb
)
836 if( the_buf
== NULL
) return FALSE
;
837 if( kb
->m_buffer
!= NULL
) return FALSE
;
839 EM_log( CK_LOG_INFO
, "adding KBHit..." );
841 kb
->m_buffer
= the_buf
;
843 kb
->m_read_index
= kb
->m_buffer
->join( (Chuck_Event
*)kb
->SELF
);
850 t_CKBOOL
KBHitManager::close( KBHit
* kb
)
852 if( the_buf
== NULL
) return FALSE
;
853 if( kb
->m_buffer
== NULL
) return FALSE
;
855 EM_log( CK_LOG_INFO
, "removing KBHit..." );
857 kb
->m_buffer
->resign( kb
->m_read_index
);
859 kb
->m_read_index
= 0;
885 t_CKBOOL
KBHit::open()
887 return KBHitManager::open( this );
892 t_CKBOOL
KBHit::close()
894 return KBHitManager::close( this );
901 if( m_onoff
== FALSE
)
913 if( m_onoff
== TRUE
)
923 t_CKBOOL
KBHit::empty()
925 if( m_buffer
== NULL
) return TRUE
;
926 if( m_onoff
== FALSE
) return TRUE
;
927 // if( m_read_index == 0 ) return TRUE;
928 return m_buffer
->empty( m_read_index
);
933 t_CKINT
KBHit::getch()
936 if( empty() ) return 0;
937 m_buffer
->get( &c
, 1, m_read_index
);
943 CK_DLL_CTOR( KBHit_ctor
)
945 KBHit
* kb
= new KBHit
;
946 OBJ_MEMBER_INT(SELF
, KBHit_offset_data
) = (t_CKINT
)kb
;
953 CK_DLL_DTOR( KBHit_dtor
)
955 delete (KBHit
*)OBJ_MEMBER_INT(SELF
, KBHit_offset_data
);
956 OBJ_MEMBER_INT(SELF
, KBHit_offset_data
) = 0;
960 CK_DLL_MFUN( KBHit_on
)
962 KBHit
* kb
= (KBHit
*)(OBJ_MEMBER_INT(SELF
, KBHit_offset_data
));
968 CK_DLL_MFUN( KBHit_off
)
970 KBHit
* kb
= (KBHit
*)(OBJ_MEMBER_INT(SELF
, KBHit_offset_data
));
976 CK_DLL_MFUN( KBHit_state
)
978 KBHit
* kb
= (KBHit
*)(OBJ_MEMBER_INT(SELF
, KBHit_offset_data
));
979 RETURN
->v_int
= kb
->state();
984 CK_DLL_MFUN( KBHit_hit
)
986 KBHit
* kb
= (KBHit
*)(OBJ_MEMBER_INT(SELF
, KBHit_offset_data
));
987 RETURN
->v_object
= SELF
;
992 CK_DLL_MFUN( KBHit_more
)
994 KBHit
* kb
= (KBHit
*)(OBJ_MEMBER_INT(SELF
, KBHit_offset_data
));
995 RETURN
->v_int
= (kb
->empty() == FALSE
);
1000 CK_DLL_MFUN( KBHit_getchar
)
1002 KBHit
* kb
= (KBHit
*)(OBJ_MEMBER_INT(SELF
, KBHit_offset_data
));
1003 RETURN
->v_int
= kb
->getch();
1008 CK_DLL_MFUN( KBHit_can_wait
)
1010 KBHit
* kb
= (KBHit
*)(OBJ_MEMBER_INT(SELF
, KBHit_offset_data
));
1011 RETURN
->v_int
= kb
->empty();
1013 #endif // __DISABLE_KBHIT__
1018 #ifndef __DISABLE_PROMPTER__
1019 class LineEvent
: public Chuck_Event
1022 LineEvent( Chuck_Event
* SELF
);
1026 void prompt( const string
& what
= "" );
1029 t_CKBOOL
can_wait();
1030 void enqueue( const string
& line
)
1031 { m_q
.push( line
); }
1040 t_CKBOOL g_le_launched
= FALSE
;
1041 t_CKBOOL g_le_wait
= TRUE
;
1042 // CHUCK_THREAD g_tid_le = 0;
1043 extern CHUCK_THREAD g_tid_whatever
;
1044 map
<LineEvent
*, LineEvent
*> g_le_map
;
1047 extern Chuck_VM
* g_vm
;
1049 void * le_cb( void * p
)
1052 map
<LineEvent
*, LineEvent
*>::iterator iter
;
1053 LineEvent
* le
= NULL
;
1068 if( !cin
.getline( line
, 2048 ) ) break;
1071 g_le_mutex
.acquire();
1073 for( iter
= g_le_map
.begin(); iter
!= g_le_map
.end(); iter
++ )
1075 // get the line event
1078 le
->enqueue( line
);
1080 le
->SELF
->queue_broadcast();
1083 g_le_mutex
.release();
1093 LineEvent::LineEvent( Chuck_Event
* SELF
)
1096 if( !g_le_launched
)
1098 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
1099 pthread_create( &g_tid_whatever
, NULL
, le_cb
, NULL
);
1101 g_tid_whatever
= CreateThread( NULL
, 0, (LPTHREAD_START_ROUTINE
)le_cb
, NULL
, 0, 0 );
1103 g_le_launched
= TRUE
;
1107 g_le_mutex
.acquire();
1109 g_le_map
[this] = this;
1112 g_le_mutex
.release();
1115 LineEvent::~LineEvent()
1120 void LineEvent::prompt( const string
& what
)
1124 if( g_le_what
!= "" ) g_le_what
+= " ";
1129 t_CKBOOL
LineEvent::more()
1132 return m_q
.size() > 0;
1135 string
LineEvent::getLine()
1140 g_le_mutex
.acquire();
1151 ret
= "[ERROR -> getLine() called on empty Skot]";
1154 g_le_mutex
.release();
1159 t_CKBOOL
LineEvent::can_wait()
1166 CK_DLL_CTOR( Skot_ctor
)
1168 LineEvent
* le
= new LineEvent((Chuck_Event
*)SELF
);
1169 OBJ_MEMBER_INT(SELF
, Skot_offset_data
) = (t_CKINT
)le
;
1172 CK_DLL_DTOR( Skot_dtor
)
1174 delete (LineEvent
*)OBJ_MEMBER_INT(SELF
, Skot_offset_data
);
1175 OBJ_MEMBER_INT(SELF
, Skot_offset_data
) = 0;
1178 CK_DLL_MFUN( Skot_prompt
)
1180 LineEvent
* le
= (LineEvent
*)OBJ_MEMBER_INT(SELF
, Skot_offset_data
);
1182 RETURN
->v_int
= (t_CKINT
)(SELF
);
1185 CK_DLL_MFUN( Skot_prompt2
)
1187 LineEvent
* le
= (LineEvent
*)OBJ_MEMBER_INT(SELF
, Skot_offset_data
);
1188 const char * v
= GET_CK_STRING(ARGS
)->str
.c_str();
1190 RETURN
->v_int
= (t_CKINT
)(SELF
);
1193 CK_DLL_MFUN( Skot_more
)
1195 LineEvent
* le
= (LineEvent
*)OBJ_MEMBER_INT(SELF
, Skot_offset_data
);
1196 RETURN
->v_int
= le
->more();
1199 CK_DLL_MFUN( Skot_getLine
)
1201 LineEvent
* le
= (LineEvent
*)OBJ_MEMBER_INT(SELF
, Skot_offset_data
);
1202 // TODO: memory leak
1203 Chuck_String
* a
= (Chuck_String
*)instantiate_and_initialize_object( &t_string
, NULL
);
1204 a
->str
= le
->getLine();
1205 RETURN
->v_string
= a
;
1208 CK_DLL_MFUN( Skot_can_wait
)
1210 LineEvent
* le
= (LineEvent
*)OBJ_MEMBER_INT(SELF
, Skot_offset_data
);
1211 RETURN
->v_int
= le
->can_wait();
1213 #endif // __DISABLE_PROMPTER__
1224 void set( const string
& line
);
1228 string
get( t_CKINT index
);
1232 istringstream
* m_ss
;
1234 vector
<string
> m_tokens
;
1235 vector
<string
>::size_type m_index
;
1246 SAFE_DELETE( m_ss
);
1249 void StrTok::set( const string
& line
)
1254 SAFE_DELETE( m_ss
);
1256 m_ss
= new istringstream( line
);
1260 while( (*m_ss
) >> s
)
1261 m_tokens
.push_back( s
);
1264 void StrTok::reset()
1269 t_CKBOOL
StrTok::more()
1271 return m_index
< m_tokens
.size();
1274 string
StrTok::next()
1276 if( !more() ) return "";
1277 return m_tokens
[m_index
++];
1280 string
StrTok::get( t_CKINT index
)
1282 if( index
>= (t_CKINT
)m_tokens
.size() ) return "";
1283 return m_tokens
[index
];
1286 t_CKINT
StrTok::size()
1288 return (t_CKINT
)m_tokens
.size();
1291 CK_DLL_CTOR( StrTok_ctor
)
1293 StrTok
* tokens
= new StrTok
;
1294 OBJ_MEMBER_INT(SELF
, StrTok_offset_data
) = (t_CKINT
)tokens
;
1297 CK_DLL_DTOR( StrTok_dtor
)
1299 delete (StrTok
*)OBJ_MEMBER_INT(SELF
, StrTok_offset_data
);
1300 OBJ_MEMBER_INT(SELF
, StrTok_offset_data
) = 0;
1303 CK_DLL_MFUN( StrTok_set
)
1305 StrTok
* tokens
= (StrTok
*)OBJ_MEMBER_INT(SELF
, StrTok_offset_data
);
1306 Chuck_String
* s
= GET_CK_STRING(ARGS
);
1307 if( s
) tokens
->set( s
->str
);
1308 else tokens
->set( "" );
1311 CK_DLL_MFUN( StrTok_reset
)
1313 StrTok
* tokens
= (StrTok
*)OBJ_MEMBER_INT(SELF
, StrTok_offset_data
);
1317 CK_DLL_MFUN( StrTok_more
)
1319 StrTok
* tokens
= (StrTok
*)OBJ_MEMBER_INT(SELF
, StrTok_offset_data
);
1320 RETURN
->v_int
= (t_CKINT
)tokens
->more();
1323 CK_DLL_MFUN( StrTok_next
)
1325 StrTok
* tokens
= (StrTok
*)OBJ_MEMBER_INT(SELF
, StrTok_offset_data
);
1326 Chuck_String
* a
= (Chuck_String
*)instantiate_and_initialize_object( &t_string
, NULL
);
1327 a
->str
= tokens
->next();
1328 RETURN
->v_string
= a
;
1331 CK_DLL_MFUN( StrTok_next2
)
1333 StrTok
* tokens
= (StrTok
*)OBJ_MEMBER_INT(SELF
, StrTok_offset_data
);
1334 Chuck_String
* a
= GET_CK_STRING(ARGS
);
1335 string s
= tokens
->next();
1337 RETURN
->v_string
= a
;
1340 CK_DLL_MFUN( StrTok_get
)
1342 StrTok
* tokens
= (StrTok
*)OBJ_MEMBER_INT(SELF
, StrTok_offset_data
);
1343 t_CKINT index
= GET_NEXT_INT(ARGS
);
1344 Chuck_String
* a
= (Chuck_String
*)instantiate_and_initialize_object( &t_string
, NULL
);
1345 string s
= tokens
->get( index
);
1347 RETURN
->v_string
= a
;
1350 CK_DLL_MFUN( StrTok_get2
)
1352 StrTok
* tokens
= (StrTok
*)OBJ_MEMBER_INT(SELF
, StrTok_offset_data
);
1353 t_CKINT index
= GET_NEXT_INT(ARGS
);
1354 Chuck_String
* a
= GET_NEXT_STRING(ARGS
);
1355 string s
= tokens
->get( index
);
1357 RETURN
->v_string
= a
;
1360 CK_DLL_MFUN( StrTok_size
)
1362 StrTok
* tokens
= (StrTok
*)OBJ_MEMBER_INT(SELF
, StrTok_offset_data
);
1363 RETURN
->v_int
= tokens
->size();
1376 virtual ~ColumnReader();
1378 bool init( const string
& filename
, long col
);
1380 bool reset() { if( !fin
.good() ) return false; where
= 0; return true; }
1381 bool seek( long pos
) { if( pos
< 0 || pos
>= values
.size() ) return false; where
= pos
; return true; }
1382 bool more() { return where
< values
.size(); }
1384 bool next() { if( where
< values
.size() ) where
++; return more(); }
1385 long pos() { return where
; }
1386 long size() { return values
.size(); }
1387 string
name() { return n
; }
1392 bool get_str( string
& out
);
1393 bool get_double( double & out
);
1403 vector
<double> values
;
1407 ColumnReader::ColumnReader()
1416 ColumnReader::~ColumnReader()
1423 bool ColumnReader::init( const string
& filename
, long col
)
1428 cerr
<< "column must be greater than 0!!!" << endl
;
1433 fin
.open( filename
.c_str(), ios::in
);
1437 cerr
<< "ColumnReader: cannot open file: '" << filename
<< "'..." << endl
;
1445 if( !fin
.getline( line
, len
) )
1447 cerr
<< "ColumnReader: cannot read first line: '" << filename
<< "'..." << endl
;
1454 cerr
<< "ColumnReader: cannot seek to column " << col
<< ": " << filename
<< "..." << endl
;
1461 while( fin
.getline( line
, len
) )
1465 if( !get_double( v
) )
1467 cerr
<< "ColumnReader: cannot read column " << v
<< " on line i: " << n
<< "..." << endl
;
1471 values
.push_back( v
);
1475 if( values
.size() == 0 )
1477 cerr
<< "ColumnReader: file doesn't not contain data after first line: " << n
<< "..." << endl
;
1489 double ColumnReader::curr()
1491 if( where
>= values
.size() )
1493 cerr
<< "ColumnReader: trying to read beyond end of file: " << n
<< "..." << endl
;
1497 return values
[where
];
1500 bool ColumnReader::get_double( double & out
)
1502 assert( column
> 0 );
1505 char * start
= line
;
1506 char * curr
= start
;
1511 while( *curr
&& *curr
!= ',' ) curr
++;
1513 while( *curr
&& *curr
== ',' ) curr
++;
1517 cerr
<< "ColumnReader: cannot find column " << column
<< ": " << n
<< endl
;
1528 while( *curr
&& *curr
!= ',' ) curr
++;
1532 out
= atof( start
);
1538 bool ColumnReader::get_str( string
& out
)
1540 assert( column
> 0 );
1543 char * start
= line
;
1544 char * curr
= start
;
1549 while( *curr
&& *curr
!= ',' ) curr
++;
1551 while( *curr
&& *curr
== ',' ) curr
++;
1555 cerr
<< "ColumnReader: cannot find column " << column
<< ": " << n
<< endl
;
1566 while( *curr
&& *curr
!= ',' ) curr
++;
1576 CK_DLL_CTOR( VCR_ctor
)
1578 OBJ_MEMBER_INT(SELF
, VCR_offset_data
) = (t_CKUINT
)new ColumnReader
;
1581 CK_DLL_MFUN( VCR_load
)
1583 ColumnReader
* vcr
= (ColumnReader
*)OBJ_MEMBER_INT(SELF
, VCR_offset_data
);
1584 const char * filename
= GET_NEXT_STRING(ARGS
)->str
.c_str();
1585 t_CKINT column
= GET_NEXT_INT(ARGS
);
1586 RETURN
->v_int
= vcr
->init( filename
, column
);
1589 CK_DLL_MFUN( VCR_reset
)
1591 ColumnReader
* vcr
= (ColumnReader
*)OBJ_MEMBER_INT(SELF
, VCR_offset_data
);
1592 RETURN
->v_int
= vcr
->reset();
1595 CK_DLL_MFUN( VCR_seek
)
1597 ColumnReader
* vcr
= (ColumnReader
*)OBJ_MEMBER_INT(SELF
, VCR_offset_data
);
1598 t_CKINT where
= GET_CK_INT(ARGS
);
1599 RETURN
->v_int
= vcr
->seek( where
);
1602 CK_DLL_MFUN( VCR_more
)
1604 ColumnReader
* vcr
= (ColumnReader
*)OBJ_MEMBER_INT(SELF
, VCR_offset_data
);
1605 RETURN
->v_int
= vcr
->more();
1608 CK_DLL_MFUN( VCR_curr
)
1610 ColumnReader
* vcr
= (ColumnReader
*)OBJ_MEMBER_INT(SELF
, VCR_offset_data
);
1611 RETURN
->v_float
= vcr
->curr();
1614 CK_DLL_MFUN( VCR_next
)
1616 ColumnReader
* vcr
= (ColumnReader
*)OBJ_MEMBER_INT(SELF
, VCR_offset_data
);
1617 RETURN
->v_int
= vcr
->next();
1620 CK_DLL_MFUN( VCR_pos
)
1622 ColumnReader
* vcr
= (ColumnReader
*)OBJ_MEMBER_INT(SELF
, VCR_offset_data
);
1623 RETURN
->v_int
= vcr
->pos();
1626 CK_DLL_MFUN( VCR_size
)
1628 ColumnReader
* vcr
= (ColumnReader
*)OBJ_MEMBER_INT(SELF
, VCR_offset_data
);
1629 RETURN
->v_int
= vcr
->size();
1632 CK_DLL_MFUN( VCR_name
)
1634 ColumnReader
* vcr
= (ColumnReader
*)OBJ_MEMBER_INT(SELF
, VCR_offset_data
);
1635 RETURN
->v_string
= &(vcr
->s
);
1639 #ifdef __PLATFORM_WIN32__
1646 // one stop bit, 8 bits, no parity
1650 unsigned read( char * buffer
, unsigned numberOfBytesToRead
);
1651 unsigned write( char * buffer
, unsigned numberOfBytesToWrite
);
1653 void write( char c
);
1656 unsigned available() const;
1658 t_CKBOOL
open( char * port
, t_CKUINT baudrate
);
1676 t_CKBOOL
Serial::open( char * port
, t_CKUINT baudrate
)
1682 serialFile
= CreateFile( port
,
1683 GENERIC_READ
| GENERIC_WRITE
,
1687 FILE_ATTRIBUTE_NORMAL
,
1689 if( serialFile
== INVALID_HANDLE_VALUE
)
1691 if( GetLastError() == ERROR_FILE_NOT_FOUND
)
1693 EM_log( CK_LOG_SYSTEM
, "error: cannot open serial port '%s'...", port
);
1697 EM_log( CK_LOG_SYSTEM
, "error opening serial port '%s'...", port
);
1704 DCB dcbSerialParams
= {0};
1705 dcbSerialParams
.DCBlength
= sizeof( dcbSerialParams
);
1706 if( !GetCommState( serialFile
, &dcbSerialParams
) )
1708 EM_log( CK_LOG_SYSTEM
, "error getting serial state..." );
1713 dcbSerialParams
.BaudRate
= baudrate
;
1714 dcbSerialParams
.ByteSize
= 8;
1715 dcbSerialParams
.StopBits
= ONESTOPBIT
;
1716 dcbSerialParams
.Parity
= NOPARITY
;
1717 if( !SetCommState( serialFile
, &dcbSerialParams
) )
1719 EM_log( CK_LOG_SYSTEM
, "error setting serial state..." );
1726 COMMTIMEOUTS timeouts = {0};
1727 timeouts.ReadIntervalTimeout = 50;
1728 timeouts.ReadTotalTimeoutConstant = 50;
1729 timeouts.ReadTotalTimeoutMultiplier = 10;
1730 timeouts.WriteTotalTimeoutConstant= 50;
1731 timeouts.WriteTotalTimeoutMultiplier = 10;
1732 if( !SetCommTimeouts( serialFile, &timeouts ) )
1734 //error occureed. Inform user
1741 void Serial::close()
1745 CloseHandle( serialFile
);
1750 void Serial::write( char c
)
1762 unsigned Serial::available() const
1764 struct _COMSTAT status
;
1766 memset( &status
, 0, sizeof(status
) );
1770 ClearCommError( serialFile
, &etat
, &status
);
1771 return status
.cbInQue
;
1777 // try to read numberOfBytesToRead into buffer, return how many bytes read
1778 unsigned Serial::read( char * buffer
, unsigned numberOfBytesToRead
)
1780 DWORD bytesRead
= 0;
1782 ReadFile( serialFile
, buffer
, numberOfBytesToRead
, &bytesRead
, NULL
);
1786 // try to write numberOfBytesToWrite to serial from buffer, return how many bytes written
1787 unsigned Serial::write( char * buffer
, unsigned numberOfBytesToWrite
)
1789 DWORD bytesWritten
= 0;
1791 WriteFile( serialFile
, buffer
, numberOfBytesToWrite
, &bytesWritten
, NULL
);
1792 return bytesWritten
;
1797 CK_DLL_CTOR( Cereal_ctor
)
1799 OBJ_MEMBER_UINT(SELF
, Cereal_offset_data
) = (t_CKUINT
)new Serial
;
1803 CK_DLL_MFUN( Cereal_open
)
1805 Serial
* s
= (Serial
*)OBJ_MEMBER_UINT(SELF
, Cereal_offset_data
);
1806 Chuck_String
* str
= GET_NEXT_STRING(ARGS
);
1807 t_CKINT i
= GET_NEXT_INT(ARGS
);
1813 RETURN
->v_int
= s
->open( (char *)str
->str
.c_str(), i
);
1819 CK_DLL_MFUN( Cereal_close
)
1821 Serial
* s
= (Serial
*)OBJ_MEMBER_UINT(SELF
, Cereal_offset_data
);
1826 CK_DLL_MFUN( Cereal_more
)
1828 Serial
* s
= (Serial
*)OBJ_MEMBER_UINT(SELF
, Cereal_offset_data
);
1829 RETURN
->v_int
= s
->available();
1833 CK_DLL_MFUN( Cereal_send
)
1835 Serial
* s
= (Serial
*)OBJ_MEMBER_UINT(SELF
, Cereal_offset_data
);
1836 t_CKINT i
= GET_NEXT_INT(ARGS
);
1842 CK_DLL_MFUN( Cereal_recv
)
1844 Serial
* s
= (Serial
*)OBJ_MEMBER_UINT(SELF
, Cereal_offset_data
);
1845 if( s
->available() )
1846 RETURN
->v_int
= (t_CKINT
)s
->read();