fix the CPU-usage issue when calling plain "./sclang" from the terminal on OSX (seems...
[supercollider.git] / Source / lang / LangSource / SC_TerminalClient.cpp
blobd5c93c58a2d7371c8f83fe182bb2572d7e525c92
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 # include "getopt.h"
33 # include "SC_Win32Utils.h"
34 # include <io.h>
35 #else
36 # include <sys/param.h>
37 # include <sys/poll.h>
38 # include <unistd.h>
39 #endif
41 #include <string.h>
42 #include <time.h>
44 #include "GC.h"
45 #include "PyrKernel.h"
46 #include "PyrPrimitive.h"
47 #include "PyrSlot.h"
48 #include "VMGlobals.h"
49 #include "SC_DirUtils.h" // for gIdeName
51 static FILE* gPostDest = stdout;
53 SC_TerminalClient::SC_TerminalClient(const char* name)
54 : SC_LanguageClient(name),
55 mShouldBeRunning(false),
56 mReturnCode(0)
60 void SC_TerminalClient::postText(const char* str, size_t len)
62 fwrite(str, sizeof(char), len, gPostDest);
65 void SC_TerminalClient::postFlush(const char* str, size_t len)
67 fwrite(str, sizeof(char), len, gPostDest);
68 fflush(gPostDest);
71 void SC_TerminalClient::postError(const char* str, size_t len)
73 fprintf(gPostDest, "ERROR: ");
74 fwrite(str, sizeof(char), len, gPostDest);
77 void SC_TerminalClient::flush()
79 fflush(gPostDest);
82 void SC_TerminalClient::printUsage()
84 Options opt;
86 const size_t bufSize = 128;
87 char memGrowBuf[bufSize];
88 char memSpaceBuf[bufSize];
90 snprintMemArg(memGrowBuf, bufSize, opt.mMemGrow);
91 snprintMemArg(memSpaceBuf, bufSize, opt.mMemSpace);
93 fprintf(stdout, "Usage:\n %s [options] [file..] [-]\n\n", getName());
94 fprintf(stdout,
95 "Options:\n"
96 " -d <path> Set runtime directory\n"
97 " -D Enter daemon mode (no input)\n"
98 " -g <memory-growth>[km] Set heap growth (default %s)\n"
99 " -h Display this message and exit\n"
100 " -l <path> Set library configuration file\n"
101 " -m <memory-space>[km] Set initial heap size (default %s)\n"
102 " -r Call Main.run on startup\n"
103 " -s Call Main.stop on shutdown\n"
104 " -u <network-port-number> Set UDP listening port (default %d)\n"
105 " -i <ide-name> Specify IDE name (for enabling IDE-specific class code, default \"%s\")\n",
106 memGrowBuf,
107 memSpaceBuf,
108 opt.mPort,
109 gIdeName
113 bool SC_TerminalClient::parseOptions(int& argc, char**& argv, Options& opt)
115 const char* optstr = ":d:Dg:hl:m:rsu:i:";
116 int c;
118 // inhibit error reporting
119 opterr = 0;
121 while ((c = getopt(argc, argv, optstr)) != -1) {
122 switch (c) {
123 case 'd':
124 opt.mRuntimeDir = optarg;
125 break;
126 case 'D':
127 opt.mDaemon = true;
128 break;
129 case 'g':
130 if (!parseMemArg(optarg, &opt.mMemGrow)) {
131 optopt = c;
132 goto optArgInvalid;
134 break;
135 case 'h':
136 goto help;
137 case 'l':
138 opt.mLibraryConfigFile = optarg;
139 break;
140 case 'm':
141 if (!parseMemArg(optarg, &opt.mMemSpace)) {
142 optopt = c;
143 goto optArgInvalid;
145 break;
146 case 'r':
147 opt.mCallRun = true;
148 break;
149 case 's':
150 opt.mCallStop = true;
151 break;
152 case 'u':
153 if (!parsePortArg(optarg, &opt.mPort)) {
154 optopt = c;
155 goto optArgInvalid;
157 break;
158 case '?':
159 goto optInvalid;
160 break;
161 case ':':
162 goto optArgExpected;
163 break;
164 case 'i':
165 gIdeName = optarg;
166 break;
167 default:
168 ::post("%s: unknown error (getopt)\n", getName());
169 quit(255);
170 return false;
174 argv += optind;
175 argc -= optind;
177 return true;
179 help:
180 printUsage();
181 quit(0);
182 return false;
184 optInvalid:
185 ::post("%s: invalid option -%c\n", getName(), optopt);
186 quit(1);
187 return false;
189 optArgExpected:
190 ::post("%s: missing argument for option -%c\n", getName(), optopt);
191 quit(1);
192 return false;
194 optArgInvalid:
195 ::post("%s: invalid argument for option -%c -- %s\n", getName(), optopt, optarg);
196 quit(1);
197 return false;
200 int SC_TerminalClient::run(int argc, char** argv)
202 Options& opt = mOptions;
204 if (!parseOptions(argc, argv, opt)) {
205 return mReturnCode;
208 // finish argv processing
209 const char* codeFile = 0;
211 if (argc > 0) {
212 codeFile = argv[0];
213 opt.mDaemon = true;
214 argv++; argc--;
217 opt.mArgc = argc;
218 opt.mArgv = argv;
220 // read library configuration file
221 bool success;
222 if (opt.mLibraryConfigFile) {
223 readLibraryConfig(opt.mLibraryConfigFile, opt.mLibraryConfigFile);
224 } else {
225 readDefaultLibraryConfig();
228 // initialize runtime
229 initRuntime(opt);
231 // startup library
232 mShouldBeRunning = true;
233 compileLibrary();
235 // enter main loop
236 if (codeFile) executeFile(codeFile);
237 if (opt.mCallRun) runMain();
239 if (opt.mDaemon) daemonLoop();
240 else commandLoop();
242 if (opt.mCallStop) stopMain();
244 // shutdown library
245 shutdownLibrary();
246 flush();
248 return mReturnCode;
251 void SC_TerminalClient::quit(int code)
253 mReturnCode = code;
254 mShouldBeRunning = false;
257 bool SC_TerminalClient::readCmdLine(int fd, SC_StringBuffer& cmdLine)
259 const int bufSize = 256;
260 char buf[bufSize];
262 int n = read(fd, buf, bufSize);
264 if (n > 0) {
265 char* ptr = buf;
266 while (n--) {
267 char c = *ptr++;
268 if (c == kInterpretCmdLine) {
269 interpretCmdLine(s_interpretCmdLine, cmdLine);
270 } else if (c == kInterpretPrintCmdLine) {
271 interpretCmdLine(s_interpretPrintCmdLine, cmdLine);
272 } else {
273 cmdLine.append(c);
276 return true;
279 if (n == 0) {
280 quit(0);
281 } else if (errno != EAGAIN) {
282 perror(getName());
283 quit(1);
286 return false;
289 void SC_TerminalClient::interpretCmdLine(PyrSymbol* method, SC_StringBuffer& cmdLine)
291 setCmdLine(cmdLine);
292 cmdLine.reset();
293 runLibrary(method);
294 flush();
297 void SC_TerminalClient::commandLoop()
299 #ifndef SC_WIN32
300 const int fd = 0;
301 struct pollfd pfds[1] = { fd, POLLIN, 0 };
302 SC_StringBuffer cmdLine;
304 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
305 perror(getName());
306 quit(1);
307 return;
310 while (shouldBeRunning()) {
311 tick();
312 int nfds = poll(pfds, POLLIN, 50);
313 if (nfds > 0) {
314 while (readCmdLine(fd, cmdLine));
315 #ifdef SC_DARWIN
316 if(pfds[0].revents == POLLNVAL){
317 // we reach here when reading directly from CLI, but not if being piped data! (osx 10.4.11 and 10.5.7 at least)
318 usleep(20011);
320 #endif
321 } else if (nfds == -1) {
322 perror(getName());
323 quit(1);
324 return;
327 #else
328 assert(0);
329 #endif
332 #ifdef SC_WIN32
333 # define nanosleep(tv, tz) win32_nanosleep(tv, tz)
334 #endif
336 void SC_TerminalClient::daemonLoop()
338 struct timespec tv = { 0, 500000 };
340 while (shouldBeRunning()) {
341 tick(); // also flushes post buffer
342 if (nanosleep(&tv, 0) == -1) {
343 perror(getName());
344 quit(1);
345 break;
350 int SC_TerminalClient::prArgv(struct VMGlobals* g, int)
352 int argc = ((SC_TerminalClient*)SC_TerminalClient::instance())->options().mArgc;
353 char** argv = ((SC_TerminalClient*)SC_TerminalClient::instance())->options().mArgv;
355 PyrSlot* argvSlot = g->sp;
357 PyrObject* argvObj = newPyrArray(g->gc, argc * sizeof(PyrObject), 0, true);
358 SetObject(argvSlot, argvObj);
360 for (int i=0; i < argc; i++) {
361 PyrString* str = newPyrString(g->gc, argv[i], 0, true);
362 SetObject(argvObj->slots+i, str);
363 argvObj->size++;
364 g->gc->GCWrite(argvObj, (PyrObject*)str);
367 return errNone;
370 int SC_TerminalClient::prExit(struct VMGlobals* g, int)
372 int code;
374 int err = slotIntVal(g->sp, &code);
375 if (err) return err;
377 ((SC_TerminalClient*)SC_LanguageClient::instance())->quit(code);
379 return errNone;
382 void SC_TerminalClient::onLibraryStartup()
384 int base, index = 0;
385 base = nextPrimitiveIndex();
386 definePrimitive(base, index++, "_Argv", &SC_TerminalClient::prArgv, 1, 0);
387 definePrimitive(base, index++, "_Exit", &SC_TerminalClient::prExit, 1, 0);
390 // EOF