Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / lang / LangSource / SC_LanguageClient.cpp
blob3e7ee064b691656fd175a764bb9d00da2650533a
1 /*
2 Abstract interpreter interface.
3 Copyright (c) 2003 2004 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_LanguageClient.h"
27 #include "SC_LibraryConfig.h"
28 #include <cstring>
29 #include <string>
30 #include <cerrno>
32 #ifdef SC_WIN32
33 # include <stdio.h>
34 # include <direct.h>
35 # define snprintf _snprintf
36 # ifndef PATH_MAX
37 # define PATH_MAX _MAX_PATH
38 # endif
39 #else
40 # include <unistd.h>
41 #endif
43 #include "PyrObject.h"
44 #include "PyrKernel.h"
45 #include "PyrPrimitive.h"
46 #include "GC.h"
47 #include "VMGlobals.h"
48 #include "SC_DirUtils.h"
49 #include "SCBase.h"
51 void closeAllGUIScreens();
52 void initGUI();
53 void initGUIPrimitives();
55 extern PyrString* newPyrStringN(class PyrGC *gc, long length, long flags, long collect);
57 // =====================================================================
58 // SC_LanguageClient
59 // =====================================================================
61 SC_LanguageClient* SC_LanguageClient::gInstance = 0;
62 SC_Lock SC_LanguageClient::gInstanceMutex;
64 PyrSymbol* SC_LanguageClient::s_interpretCmdLine = 0;
65 PyrSymbol* SC_LanguageClient::s_interpretPrintCmdLine = 0;
66 PyrSymbol* SC_LanguageClient::s_run = 0;
67 PyrSymbol* SC_LanguageClient::s_stop = 0;
68 static PyrSymbol* s_tick = 0;
70 SC_LanguageClient::SC_LanguageClient(const char* name)
71 : mName(0),
72 mPostFile(0),
73 mScratch(0),
74 mRunning(false)
76 lockInstance();
78 if (gInstance) {
79 unlockInstance();
80 fprintf(stderr, "SC_LanguageClient already running\n");
81 abort();
84 mName = strdup(name);
85 gInstance = this;
87 unlockInstance();
90 SC_LanguageClient::~SC_LanguageClient()
92 lockInstance();
93 free(mName);
94 gInstance = 0;
95 unlockInstance();
98 void SC_LanguageClient::initRuntime(const Options& opt)
100 // start virtual machine
101 if (!mRunning) {
102 #ifdef __linux__
103 char deprecatedSupportDirectory[PATH_MAX];
104 sc_GetUserHomeDirectory(deprecatedSupportDirectory, PATH_MAX);
105 sc_AppendToPath(deprecatedSupportDirectory, PATH_MAX, "share/SuperCollider");
107 if (sc_DirectoryExists(deprecatedSupportDirectory)) {
108 char supportDirectory[PATH_MAX];
109 sc_GetUserAppSupportDirectory(supportDirectory, PATH_MAX);
110 postfl("WARNING: Deprecated support directory detected: %s\n"
111 "Extensions and other contents in this directory will not be available until you move them to the new support directory:\n"
112 "%s\n"
113 "Quarks will need to be reinstalled due to broken symbolic links.\n\n", deprecatedSupportDirectory, supportDirectory);
115 #endif
117 mRunning = true;
118 if (opt.mRuntimeDir) {
119 int err = chdir(opt.mRuntimeDir);
120 if (err)
121 error("Cannot change to runtime directory: %s", strerror(errno));
123 pyr_init_mem_pools(opt.mMemSpace, opt.mMemGrow);
124 init_OSC(opt.mPort);
125 schedInit();
126 onInitRuntime();
130 void SC_LanguageClient::shutdownRuntime()
132 cleanup_OSC();
135 void SC_LanguageClient::compileLibrary()
137 ::compileLibrary();
140 extern void shutdownLibrary();
141 void SC_LanguageClient::shutdownLibrary()
143 ::shutdownLibrary();
144 flush();
147 void SC_LanguageClient::recompileLibrary()
149 compileLibrary();
152 void SC_LanguageClient::setCmdLine(const char* buf, size_t size)
154 if (isLibraryCompiled()) {
155 lock();
156 if (isLibraryCompiled()) {
157 VMGlobals *g = gMainVMGlobals;
159 PyrString* strobj = newPyrStringN(g->gc, size, 0, true);
160 memcpy(strobj->s, buf, size);
162 SetObject(&slotRawInterpreter(&g->process->interpreter)->cmdLine, strobj);
163 g->gc->GCWrite(slotRawObject(&g->process->interpreter), strobj);
165 unlock();
169 void SC_LanguageClient::setCmdLine(const char* str)
171 setCmdLine(str, strlen(str));
174 void SC_LanguageClient::setCmdLine(const SC_StringBuffer& strBuf)
176 setCmdLine(strBuf.getData(), strBuf.getSize());
179 void SC_LanguageClient::setCmdLinef(const char* fmt, ...)
181 va_list ap;
182 va_start(ap, fmt);
183 mScratch.reset();
184 mScratch.vappendf(fmt, ap);
185 va_end(ap);
186 setCmdLine(mScratch);
189 void SC_LanguageClient::runLibrary(PyrSymbol* symbol)
191 lock();
192 ::runLibrary(symbol);
193 unlock();
196 void SC_LanguageClient::runLibrary(const char* methodName)
198 lock();
199 ::runLibrary(getsym(methodName));
200 unlock();
203 void SC_LanguageClient::executeFile(const char* fileName)
205 setCmdLinef("thisProcess.interpreter.executeFile(\"%s\")", fileName);
206 runLibrary(s_interpretCmdLine);
209 void SC_LanguageClient::snprintMemArg(char* dst, size_t size, int arg)
211 int rem = arg;
212 int mod = 0;
213 const char* modstr = "";
215 while (((rem % 1024) == 0) && (mod < 4)) {
216 rem /= 1024;
217 mod++;
220 switch (mod) {
221 case 0: modstr = ""; break;
222 case 1: modstr = "k"; break;
223 case 2: modstr = "m"; break;
224 case 3: modstr = "g"; break;
225 default: rem = arg; modstr = ""; break;
228 snprintf(dst, size, "%d%s", rem, modstr);
231 bool SC_LanguageClient::parseMemArg(const char* arg, int* res)
233 long value, factor = 1;
234 char* endPtr = 0;
236 if (*arg == '\0') return false;
238 value = strtol(arg, &endPtr, 0);
240 char spec = *endPtr++;
241 if (spec != '\0') {
242 if (*endPtr != '\0')
243 // trailing characters
244 return false;
246 switch (spec) {
247 case 'k':
248 factor = 1024;
249 break;
250 case 'm':
251 factor = 1024 * 1024;
252 break;
253 default:
254 // invalid mem spec
255 return false;
259 *res = value * factor;
261 return true;
264 bool SC_LanguageClient::parsePortArg(const char* arg, int* res)
266 long value;
267 char* endPtr;
269 if (*arg == '\0') return false;
271 value = strtol(arg, &endPtr, 0);
273 if ((*endPtr != '\0') || (value < 0) || (value > 65535))
274 return false;
276 *res = value;
278 return true;
281 void SC_LanguageClient::tick()
283 if (trylock()) {
284 if (isLibraryCompiled()) {
285 ::runLibrary(s_tick);
287 unlock();
289 flush();
292 bool SC_LanguageClient::tickLocked( double * nextTime )
294 if (isLibraryCompiled()) {
295 ::runLibrary(s_tick);
298 return slotDoubleVal( &gMainVMGlobals->result, nextTime ) == errNone;
301 void SC_LanguageClient::onInitRuntime()
305 void SC_LanguageClient::onLibraryStartup()
309 void SC_LanguageClient::onLibraryShutdown()
313 void SC_LanguageClient::onInterpStartup()
317 // =====================================================================
318 // library functions
319 // =====================================================================
321 // this is defined in PySCLang
322 #ifndef PYSCLANG
323 void setPostFile(FILE* file)
325 SC_LanguageClient::instance()->setPostFile(file);
328 int vpost(const char *fmt, va_list ap)
330 char buf[512];
331 int n = vsnprintf(buf, sizeof(buf), fmt, ap);
332 if (n > 0) {
333 SC_LanguageClient *client = SC_LanguageClient::lockedInstance();
334 if (client) client->postText(buf, sc_min(n, sizeof(buf) - 1));
335 SC_LanguageClient::unlockInstance();
337 return 0;
340 void post(const char *fmt, ...)
342 va_list ap;
343 va_start(ap, fmt);
344 vpost(fmt, ap);
347 void postfl(const char *fmt, ...)
349 char buf[512];
350 va_list ap;
351 va_start(ap, fmt);
352 int n = vsnprintf(buf, sizeof(buf), fmt, ap);
353 if (n > 0) {
354 SC_LanguageClient *client = SC_LanguageClient::lockedInstance();
355 if (client) client->postFlush(buf, sc_min(n, sizeof(buf) - 1));
356 SC_LanguageClient::unlockInstance();
360 void postText(const char *str, long len)
362 SC_LanguageClient *client = SC_LanguageClient::lockedInstance();
363 if (client) client->postFlush(str, len);
364 SC_LanguageClient::unlockInstance();
367 void postChar(char c)
369 SC_LanguageClient *client = SC_LanguageClient::lockedInstance();
370 if (client) client->postFlush(&c, sizeof(char));
371 SC_LanguageClient::unlockInstance();
374 void error(const char *fmt, ...)
376 char buf[512];
377 va_list ap;
378 va_start(ap, fmt);
379 int n = vsnprintf(buf, sizeof(buf), fmt, ap);
380 if (n > 0) {
381 SC_LanguageClient *client = SC_LanguageClient::lockedInstance();
382 if (client) client->postError(buf, sc_min(n, sizeof(buf) - 1));
383 SC_LanguageClient::unlockInstance();
387 void flushPostBuf(void)
389 SC_LanguageClient::instance()->flush();
392 void closeAllGUIScreens()
394 SC_LanguageClient::instance()->onLibraryShutdown();
397 void initGUI()
399 SC_LanguageClient::instance()->onInterpStartup();
402 void initGUIPrimitives()
404 SC_LanguageClient::s_interpretCmdLine = getsym("interpretCmdLine");
405 SC_LanguageClient::s_interpretPrintCmdLine = getsym("interpretPrintCmdLine");
406 SC_LanguageClient::s_run = getsym("run");
407 SC_LanguageClient::s_stop = getsym("stop");
408 s_tick = getsym("tick");
409 SC_LanguageClient::instance()->onLibraryStartup();
412 void initSCViewPrimitives();
413 void initSCViewPrimitives()
417 void initCocoaFilePrimitives();
418 void initCocoaFilePrimitives()
422 void initCocoaBridgePrimitives();
423 void initCocoaBridgePrimitives()
427 void initRendezvousPrimitives();
428 void initRendezvousPrimitives()
432 #if !defined(HAVE_SPEECH)
433 void initSpeechPrimitives();
434 void initSpeechPrimitives()
437 #endif // HAVE_SPEECH
439 long scMIDIout(int port, int len, int statushi, int chan, int data1, int data2);
440 long scMIDIout(int port, int len, int statushi, int chan, int data1, int data2)
442 return 0;
444 #endif
445 // EOF