cmake: supernova - missing include_directories() for Jack
[supercollider.git] / lang / LangSource / SC_TerminalClient.cpp
blobcffeceeab62e90e96a1605635e62aa0da0df3dd6
1 /*
2 Commandline interpreter interface.
3 Copyright (c) 2003-2006 stefan kersten.
5 ====================================================================
7 SuperCollider real time audio synthesis system
8 Copyright (c) 2002 James McCartney. All rights reserved.
9 http://www.audiosynth.com
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 #include "SC_TerminalClient.h"
28 #include <errno.h>
29 #include <fcntl.h>
31 #ifdef SC_WIN32
32 # define __GNU_LIBRARY__
33 # include "getopt.h"
34 # include "SC_Win32Utils.h"
35 # include <io.h>
36 # include <windows.h>
37 #else
38 # include <sys/param.h>
39 # include <sys/poll.h>
40 # include <unistd.h>
41 # ifdef HAVE_READLINE
42 # include <readline/readline.h>
43 # include <readline/history.h>
44 # include <signal.h>
45 # endif
46 #endif
48 #include <string.h>
49 #include <time.h>
51 #include "GC.h"
52 #include "PyrKernel.h"
53 #include "PyrPrimitive.h"
54 #include "PyrLexer.h"
55 #include "PyrSlot.h"
56 #include "VMGlobals.h"
57 #include "SC_DirUtils.h" // for gIdeName
58 #include "SC_LibraryConfig.h"
60 #define STDIN_FD 0
62 static FILE* gPostDest = stdout;
64 static const int ticks_per_second = 50; // every 20 milliseconds
66 SC_TerminalClient::SC_TerminalClient(const char* name)
67 : SC_LanguageClient(name),
68 mShouldBeRunning(false),
69 mReturnCode(0),
70 mUseReadline(false),
71 mInput(false),
72 mSched(true),
73 mRecompile(false)
75 pthread_cond_init (&mCond, NULL);
76 pthread_mutex_init(&mSignalMutex, NULL);
77 pthread_mutex_init(&mInputMutex, NULL);
78 pthread_cond_init(&mInputCond, NULL);
81 SC_TerminalClient::~SC_TerminalClient()
83 pthread_cond_destroy (&mCond);
84 pthread_mutex_destroy(&mSignalMutex);
85 pthread_mutex_destroy(&mInputMutex);
86 pthread_cond_destroy(&mInputCond);
89 void SC_TerminalClient::postText(const char* str, size_t len)
91 fwrite(str, sizeof(char), len, gPostDest);
94 void SC_TerminalClient::postFlush(const char* str, size_t len)
96 fwrite(str, sizeof(char), len, gPostDest);
97 fflush(gPostDest);
100 void SC_TerminalClient::postError(const char* str, size_t len)
102 fprintf(gPostDest, "ERROR: ");
103 fwrite(str, sizeof(char), len, gPostDest);
106 void SC_TerminalClient::flush()
108 fflush(gPostDest);
111 void SC_TerminalClient::printUsage()
113 Options opt;
115 const size_t bufSize = 128;
116 char memGrowBuf[bufSize];
117 char memSpaceBuf[bufSize];
119 snprintMemArg(memGrowBuf, bufSize, opt.mMemGrow);
120 snprintMemArg(memSpaceBuf, bufSize, opt.mMemSpace);
122 fprintf(stdout, "Usage:\n %s [options] [file..] [-]\n\n", getName());
123 fprintf(stdout,
124 "Options:\n"
125 " -d <path> Set runtime directory\n"
126 " -D Enter daemon mode (no input)\n"
127 " -g <memory-growth>[km] Set heap growth (default %s)\n"
128 " -h Display this message and exit\n"
129 " -l <path> Set library configuration file\n"
130 " -m <memory-space>[km] Set initial heap size (default %s)\n"
131 " -r Call Main.run on startup\n"
132 " -s Call Main.stop on shutdown\n"
133 " -u <network-port-number> Set UDP listening port (default %d)\n"
134 " -i <ide-name> Specify IDE name (for enabling IDE-specific class code, default \"%s\")\n",
135 memGrowBuf,
136 memSpaceBuf,
137 opt.mPort,
138 gIdeName
142 bool SC_TerminalClient::parseOptions(int& argc, char**& argv, Options& opt)
144 const char* optstr = ":d:Dg:hl:m:rsu:i:";
145 int c;
147 // inhibit error reporting
148 opterr = 0;
150 while ((c = getopt(argc, argv, optstr)) != -1) {
151 switch (c) {
152 case 'd':
153 opt.mRuntimeDir = optarg;
154 break;
155 case 'D':
156 opt.mDaemon = true;
157 break;
158 case 'g':
159 if (!parseMemArg(optarg, &opt.mMemGrow)) {
160 optopt = c;
161 goto optArgInvalid;
163 break;
164 case 'h':
165 goto help;
166 case 'l':
167 opt.mLibraryConfigFile = optarg;
168 break;
169 case 'm':
170 if (!parseMemArg(optarg, &opt.mMemSpace)) {
171 optopt = c;
172 goto optArgInvalid;
174 break;
175 case 'r':
176 opt.mCallRun = true;
177 break;
178 case 's':
179 opt.mCallStop = true;
180 break;
181 case 'u':
182 if (!parsePortArg(optarg, &opt.mPort)) {
183 optopt = c;
184 goto optArgInvalid;
186 break;
187 case '?':
188 goto optInvalid;
189 break;
190 case ':':
191 goto optArgExpected;
192 break;
193 case 'i':
194 gIdeName = optarg;
195 break;
196 default:
197 ::post("%s: unknown error (getopt)\n", getName());
198 quit(255);
199 return false;
203 argv += optind;
204 argc -= optind;
206 return true;
208 help:
209 printUsage();
210 quit(0);
211 return false;
213 optInvalid:
214 ::post("%s: invalid option -%c\n", getName(), optopt);
215 quit(1);
216 return false;
218 optArgExpected:
219 ::post("%s: missing argument for option -%c\n", getName(), optopt);
220 quit(1);
221 return false;
223 optArgInvalid:
224 ::post("%s: invalid argument for option -%c -- %s\n", getName(), optopt, optarg);
225 quit(1);
226 return false;
229 int SC_TerminalClient::run(int argc, char** argv)
231 Options& opt = mOptions;
233 if (!parseOptions(argc, argv, opt)) {
234 return mReturnCode;
237 // finish argv processing
238 const char* codeFile = 0;
240 if (argc > 0) {
241 codeFile = argv[0];
242 opt.mDaemon = true;
243 argv++; argc--;
246 opt.mArgc = argc;
247 opt.mArgv = argv;
249 // read library configuration file
250 if (opt.mLibraryConfigFile) {
251 int argLength = strlen(opt.mLibraryConfigFile);
252 if (strcmp(opt.mLibraryConfigFile + argLength - 5, ".yaml"))
253 SC_LanguageConfig::readLibraryConfig(opt.mLibraryConfigFile);
254 else
255 SC_LanguageConfig::readLibraryConfigYAML(opt.mLibraryConfigFile);
256 } else
257 SC_LanguageConfig::readDefaultLibraryConfig();
259 // initialize runtime
260 initRuntime(opt);
262 // startup library
263 mShouldBeRunning = true;
264 compileLibrary();
266 // enter main loop
267 if (codeFile) executeFile(codeFile);
268 if (opt.mCallRun) runMain();
270 if (opt.mDaemon) {
271 daemonLoop();
273 else {
274 initInput();
275 if( shouldBeRunning() ) startInput();
276 if( shouldBeRunning() ) commandLoop();
277 endInput();
278 cleanupInput();
281 if (opt.mCallStop) stopMain();
283 // shutdown library
284 shutdownLibrary();
285 flush();
287 shutdownRuntime();
289 return mReturnCode;
292 void SC_TerminalClient::quit(int code)
294 mReturnCode = code;
295 mShouldBeRunning = false;
298 void SC_TerminalClient::interpretCmdLine(PyrSymbol* method, SC_StringBuffer& cmdLine)
300 setCmdLine(cmdLine);
301 cmdLine.reset();
302 runLibrary(method);
303 flush();
306 void SC_TerminalClient::interpretCmdLine(PyrSymbol* method, const char* cmdLine)
308 setCmdLine(cmdLine);
309 runLibrary(method);
310 flush();
314 void SC_TerminalClient::interpretCmdLine(PyrSymbol* method, const char *cmdLine, size_t size)
316 setCmdLine(cmdLine, size);
317 runLibrary(method);
318 flush();
321 // WARNING: Call with input locked!
322 void SC_TerminalClient::interpretInput()
324 char *data = mInputBuf.getData();
325 int c = mInputBuf.getSize();
326 int i = 0;
327 while( i < c ) {
328 switch (data[i]) {
329 case kInterpretCmdLine:
330 interpretCmdLine(s_interpretCmdLine, data, i);
331 break;
332 case kInterpretPrintCmdLine:
333 interpretCmdLine(s_interpretPrintCmdLine, data, i);
334 break;
336 case kRecompileLibrary:
337 recompileLibrary();
338 break;
340 default:
341 ++i;
342 continue;
345 data += i+1;
346 c -= i+1;
347 i = 0;
349 mInputBuf.reset();
350 if( mUseReadline ) pthread_cond_signal( &mInputCond );
353 void SC_TerminalClient::onLibraryStartup()
355 SC_LanguageClient::onLibraryStartup();
356 int base, index = 0;
357 base = nextPrimitiveIndex();
358 definePrimitive(base, index++, "_Argv", &SC_TerminalClient::prArgv, 1, 0);
359 definePrimitive(base, index++, "_Exit", &SC_TerminalClient::prExit, 1, 0);
360 definePrimitive(base, index++, "_AppClock_SchedNotify",
361 &SC_TerminalClient::prScheduleChanged, 1, 0);
362 definePrimitive(base, index++, "_Recompile", &SC_TerminalClient::prRecompile, 1, 0);
365 void SC_TerminalClient::onScheduleChanged()
367 lockSignal();
368 mSched = true;
369 pthread_cond_signal( &mCond );
370 unlockSignal();
373 void SC_TerminalClient::onInput()
375 lockSignal();
376 mInput = true;
377 pthread_cond_signal( &mCond );
378 unlockSignal();
381 void SC_TerminalClient::onQuit( int exitCode )
383 lockSignal();
384 postfl("main: quit request %i\n", exitCode);
385 quit( exitCode );
386 pthread_cond_signal( &mCond );
387 unlockSignal();
390 void SC_TerminalClient::onRecompileLibrary()
392 lockSignal();
393 mRecompile = true;
394 pthread_cond_signal( &mCond );
395 unlockSignal();
398 extern void ElapsedTimeToTimespec(double elapsed, struct timespec *spec);
400 void SC_TerminalClient::commandLoop()
402 bool haveNext = false;
403 struct timespec nextAbsTime;
405 lockSignal();
407 while( shouldBeRunning() )
410 while ( mInput || mSched || mRecompile ) {
411 bool input = mInput;
412 bool sched = mSched;
413 bool recompile = mRecompile;
415 unlockSignal();
417 if (input) {
418 //postfl("input\n");
419 lockInput();
420 interpretInput();
421 // clear input signal, as we've processed anything signalled so far.
422 lockSignal();
423 mInput = false;
424 unlockSignal();
425 unlockInput();
428 if (sched) {
429 //postfl("tick\n");
430 double secs;
431 lock();
432 haveNext = tickLocked( &secs );
433 // clear scheduler signal, as we've processed all items scheduled up to this time.
434 // and will enter the wait according to schedule.
435 lockSignal();
436 mSched = false;
437 unlockSignal();
438 unlock();
440 flush();
442 //postfl("tick -> next time = %f\n", haveNext ? secs : -1);
443 ElapsedTimeToTimespec( secs, &nextAbsTime );
446 if (recompile) {
447 recompileLibrary();
448 lockSignal();
449 mRecompile = false;
450 unlockSignal();
453 lockSignal();
456 if( !shouldBeRunning() ) {
457 break;
459 else if( haveNext ) {
460 int result = pthread_cond_timedwait( &mCond, &mSignalMutex, &nextAbsTime );
461 if( result == ETIMEDOUT ) mSched = true;
463 else {
464 pthread_cond_wait( &mCond, &mSignalMutex );
468 unlockSignal();
471 void SC_TerminalClient::daemonLoop()
473 commandLoop();
476 #ifdef HAVE_READLINE
478 static void sc_rl_cleanlf(void)
480 rl_reset_line_state();
481 rl_crlf();
482 rl_redisplay();
485 static void sc_rl_signalhandler(int sig)
487 // ensure ctrl-C clears line rather than quitting (ctrl-D will quit nicely)
488 rl_replace_line("", 0);
489 sc_rl_cleanlf();
492 static int sc_rl_mainstop(int i1, int i2)
494 SC_TerminalClient::instance()->stopMain();
495 sc_rl_cleanlf(); // We also push a newline so that there's some UI feedback
496 return 0;
499 int SC_TerminalClient::readlineRecompile(int i1, int i2)
501 static_cast<SC_TerminalClient*>(SC_LanguageClient::instance())->onRecompileLibrary();
502 sc_rl_cleanlf();
503 return 0;
506 void SC_TerminalClient::readlineCmdLine( char *cmdLine )
508 SC_TerminalClient *client = static_cast<SC_TerminalClient*>(instance());
510 if( cmdLine == NULL ) {
511 postfl("\nExiting sclang (ctrl-D)\n");
512 client->onQuit(0);
513 return;
516 if(*cmdLine!=0){
517 // If line wasn't empty, store it so that uparrow retrieves it
518 add_history(cmdLine);
519 int len = strlen(cmdLine);
521 client->lockInput();
522 client->mInputBuf.append(cmdLine, len);
523 client->mInputBuf.append(kInterpretPrintCmdLine);
524 client->onInput();
525 // Wait for input to be processed,
526 // so that its output is displayed before readline prompt.
527 if (client->mInputShouldBeRunning)
528 pthread_cond_wait( &client->mInputCond, &client->mInputMutex );
529 client->unlockInput();
533 void *SC_TerminalClient::readlineFunc( void *arg )
535 SC_TerminalClient *client = static_cast<SC_TerminalClient*>(arg);
537 // Setup readline
538 rl_readline_name = "sclang";
539 rl_basic_word_break_characters = " \t\n\"\\'`@><=;|&{}().";
540 //rl_attempted_completion_function = sc_rl_completion;
541 rl_bind_key(CTRL('t'), &sc_rl_mainstop);
542 rl_bind_key(CTRL('x'), &readlineRecompile);
543 rl_callback_handler_install( "sc3> ", &readlineCmdLine );
545 // Set our handler for SIGINT that will clear the line instead of terminating.
546 // NOTE: We prevent readline from setting its own signal handlers,
547 // to not override ours.
548 rl_catch_signals = 0;
549 struct sigaction sact;
550 memset( &sact, 0, sizeof(struct sigaction) );
551 sact.sa_handler = &sc_rl_signalhandler;
552 sigaction( SIGINT, &sact, 0 );
554 fd_set fds;
555 FD_ZERO(&fds);
557 while(true) {
558 FD_SET(STDIN_FD, &fds);
559 FD_SET(client->mInputCtlPipe[0], &fds);
561 if( select(FD_SETSIZE, &fds, NULL, NULL, NULL) < 0 ) {
562 if( errno == EINTR ) continue;
563 postfl("readline: select() error:\n%s\n", strerror(errno));
564 client->onQuit(1);
565 break;
568 if( FD_ISSET(client->mInputCtlPipe[0], &fds) ) {
569 postfl("readline: quit requested\n");
570 break;
573 if( FD_ISSET(STDIN_FD, &fds) ) {
574 rl_callback_read_char();
578 postfl("readline: stopped.\n");
580 return NULL;
583 // Completion from sclang dictionary TODO
584 char ** sc_rl_completion (const char *text, int start, int end);
585 char ** sc_rl_completion (const char *text, int start, int end){
586 char **matches = (char **)NULL;
587 printf("sc_rl_completion(%s, %i, %i)\n", text, start, end);
588 return matches;
591 #endif
593 #ifndef _WIN32
595 void *SC_TerminalClient::pipeFunc( void *arg )
597 SC_TerminalClient *client = static_cast<SC_TerminalClient*>(arg);
599 ssize_t bytes;
600 const size_t toRead = 256;
601 char buf[toRead];
602 SC_StringBuffer stack;
604 fd_set fds;
605 FD_ZERO(&fds);
607 bool shouldRead = true;
608 while(shouldRead) {
609 FD_SET(STDIN_FD, &fds);
610 FD_SET(client->mInputCtlPipe[0], &fds);
612 if( select(FD_SETSIZE, &fds, NULL, NULL, NULL) < 0 ) {
613 if( errno == EINTR ) continue;
614 postfl("pipe-in: select() error: %s\n", strerror(errno));
615 client->onQuit(1);
616 break;
619 if( FD_ISSET(client->mInputCtlPipe[0], &fds) ) {
620 postfl("pipe-in: quit requested\n");
621 break;
624 if( FD_ISSET(STDIN_FD, &fds) ) {
626 while(true) {
627 bytes = read( STDIN_FD, buf, toRead );
629 if( bytes > 0 ) {
630 client->pushCmdLine( stack, buf, bytes );
632 else if( bytes == 0 ) {
633 postfl("pipe-in: EOF. Will quit.\n");
634 client->onQuit(0);
635 shouldRead = false;
636 break;
638 else {
639 if( errno == EAGAIN ) {
640 break; // no more to read this time;
642 else if( errno != EINTR ){
643 postfl("pipe-in: read() error: %s\n", strerror(errno));
644 client->onQuit(1);
645 shouldRead = false;
646 break;
653 postfl("pipe-in: stopped.\n");
655 return NULL;
658 #else
660 void *SC_TerminalClient::pipeFunc( void *arg )
662 SC_TerminalClient *client = static_cast<SC_TerminalClient*>(arg);
664 SC_StringBuffer stack;
665 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
666 HANDLE hnds[] = { client->mQuitInputEvent, hStdIn };
668 bool shouldRun = true;
669 while (shouldRun) {
670 DWORD result = WaitForMultipleObjects( 2, hnds, false, INFINITE );
672 if( result == WAIT_FAILED ) {
673 postfl("pipe-in: wait error.\n");
674 client->onQuit(1);
675 break;
678 int hIndex = result - WAIT_OBJECT_0;
680 if( hIndex == 0 ) {
681 postfl("pipe-in: quit requested.\n");
682 break;
685 if( hIndex == 1 ) {
686 DWORD nAvail;
687 if (!PeekNamedPipe(hStdIn, NULL, 0, NULL, &nAvail, NULL)) {
688 DWORD err = GetLastError();
689 if( err == ERROR_BROKEN_PIPE ) {
690 postfl("pipe-in: Pipe has been ended. Quitting.\n");
691 client->onQuit(0);
693 else {
694 postfl("pipe-in: Error trying to peek stdin (%Li). Quitting.\n", err);
695 client->onQuit(1);
697 break;
700 while (nAvail > 0)
702 char buf[256];
703 DWORD nRead = sc_min(256, nAvail);
704 if (!ReadFile(hStdIn, buf, nRead, &nRead, NULL)) {
705 postfl("pipe-in: Error trying to read stdin (%Li). Quitting.\n", GetLastError());
706 client->onQuit(1);
707 shouldRun = false;
708 break;
710 else if (nRead > 0) {
711 client->pushCmdLine( stack, buf, nRead );
714 nAvail -= nRead;
719 postfl("pipe-in: stopped.\n");
721 return NULL;
724 #endif
726 void SC_TerminalClient::pushCmdLine( SC_StringBuffer &buf, const char *newData, size_t size)
728 lockInput();
730 bool signal = false;
732 while (size--) {
733 char c = *newData++;
734 switch (c) {
735 case kRecompileLibrary:
736 case kInterpretCmdLine:
737 case kInterpretPrintCmdLine:
738 mInputBuf.append( buf.getData(), buf.getSize() );
739 mInputBuf.append(c);
740 signal = true;
741 buf.reset();
742 break;
744 default:
745 buf.append(c);
749 if(signal) onInput();
751 unlockInput();
757 void SC_TerminalClient::initInput()
760 #ifndef _WIN32
762 if( pipe( mInputCtlPipe ) == -1 ) {
763 postfl("Error creating pipe for input thread control:\n%s\n", strerror(errno));
764 quit(1);
767 #ifdef HAVE_READLINE
769 if (strcmp(gIdeName, "none") == 0) {
770 // Other clients (emacs, vim, ...) won't want to interact through rl
771 mUseReadline = true;
772 return;
775 #endif
777 if( fcntl( STDIN_FD, F_SETFL, O_NONBLOCK ) == -1 ) {
778 postfl("Error setting up non-blocking pipe reading:\n%s\n", strerror(errno));
779 quit(1);
782 #else // !_WIN32
784 mQuitInputEvent = CreateEvent( NULL, false, false, NULL );
785 if( mQuitInputEvent == NULL ) {
786 postfl("Error creating event for input thread control.\n");
787 quit(1);
789 postfl("Created input thread control event.\n");
791 #endif // !_WIN32
795 void SC_TerminalClient::startInput()
797 mInputShouldBeRunning = true;
798 #ifdef HAVE_READLINE
799 if( mUseReadline )
800 pthread_create( &mInputThread, NULL, &SC_TerminalClient::readlineFunc, this );
801 else
802 #endif
803 pthread_create( &mInputThread, NULL, &SC_TerminalClient::pipeFunc, this );
806 void SC_TerminalClient::endInput()
808 // wake up the input thread in case it is waiting
809 // for input to be processed
810 lockInput();
811 mInputShouldBeRunning = false;
812 pthread_cond_signal( &mInputCond );
813 unlockInput();
815 #ifndef _WIN32
816 postfl("main: sending quit command to input thread.\n");
817 char c = 'q';
818 ssize_t bytes = write( mInputCtlPipe[1], &c, 1 );
819 if( bytes < 1 ) { postfl("WARNING: could not send quit command to input thread.\n"); }
821 #else
822 postfl("main: signalling input thread quit event\n");
823 SetEvent( mQuitInputEvent );
824 #endif
826 postfl("main: stopped, waiting for input thread to join...\n");
828 pthread_join( mInputThread, NULL );
830 postfl("main: input thread joined.\n");
833 void SC_TerminalClient::cleanupInput()
835 #ifdef HAVE_READLINE
836 if( mUseReadline ) rl_callback_handler_remove();
837 #endif
840 int SC_TerminalClient::prArgv(struct VMGlobals* g, int)
842 int argc = ((SC_TerminalClient*)SC_TerminalClient::instance())->options().mArgc;
843 char** argv = ((SC_TerminalClient*)SC_TerminalClient::instance())->options().mArgv;
845 PyrSlot* argvSlot = g->sp;
847 PyrObject* argvObj = newPyrArray(g->gc, argc * sizeof(PyrObject), 0, true);
848 SetObject(argvSlot, argvObj);
850 for (int i=0; i < argc; i++) {
851 PyrString* str = newPyrString(g->gc, argv[i], 0, true);
852 SetObject(argvObj->slots+i, str);
853 argvObj->size++;
854 g->gc->GCWrite(argvObj, (PyrObject*)str);
857 return errNone;
860 int SC_TerminalClient::prExit(struct VMGlobals* g, int)
862 int code;
864 int err = slotIntVal(g->sp, &code);
865 if (err) return err;
867 ((SC_TerminalClient*)SC_LanguageClient::instance())->onQuit( code );
869 return errNone;
872 int SC_TerminalClient::prScheduleChanged( struct VMGlobals *g, int numArgsPushed)
874 static_cast<SC_TerminalClient*>(instance())->onScheduleChanged();
875 return errNone;
878 int SC_TerminalClient::prRecompile(struct VMGlobals *, int)
880 static_cast<SC_TerminalClient*>(instance())->onRecompileLibrary();
881 return errNone;
883 // EOF