Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / lang / LangPrimSource / PyrUnixPrim.cpp
blob47e21466ea78bd9fbc076128bf7fbed4600e7689
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 Primitives for Unix.
26 #include <cstring>
27 #include <errno.h>
28 #include <pthread.h>
29 #include <signal.h>
31 #include "PyrPrimitive.h"
32 #include "PyrObject.h"
33 #include "PyrKernel.h"
34 #include "PyrSched.h"
35 #include "VMGlobals.h"
36 #include "GC.h"
37 #include "SC_RGen.h"
38 #include "SC_DirUtils.h"
39 #include "sc_popen.h"
40 #include "SCBase.h"
42 #ifdef SC_WIN32
43 #include "SC_Win32Utils.h"
44 #else
45 #include <libgen.h>
46 #endif
48 extern bool compiledOK;
49 PyrSymbol* s_unixCmdAction;
51 int prString_System(struct VMGlobals *g, int numArgsPushed);
52 int prString_System(struct VMGlobals *g, int numArgsPushed)
54 PyrSlot *a = g->sp;
56 char cmdline[1024];
57 int err = slotStrVal(a, cmdline, 1023);
58 if (err) return err;
60 int res = system(cmdline);
61 SetInt(a, res);
63 return errNone;
66 int prString_Basename(struct VMGlobals *g, int numArgsPushed);
67 int prString_Basename(struct VMGlobals *g, int numArgsPushed)
69 PyrSlot *a = g->sp;
71 char path[PATH_MAX];
72 int err = slotStrVal(a, path, PATH_MAX);
73 if (err) return err;
75 char *basename0 = basename(path);
77 int size = strlen(basename0);
78 PyrString *strobj = newPyrStringN(g->gc, size, 0, true);
79 memcpy(strobj->s, basename0, size);
81 SetObject(a, strobj);
83 return errNone;
86 int prString_Dirname(struct VMGlobals *g, int numArgsPushed);
87 int prString_Dirname(struct VMGlobals *g, int numArgsPushed)
89 PyrSlot *a = g->sp;
91 char path[PATH_MAX];
92 int err = slotStrVal(a, path, PATH_MAX);
93 if (err) return err;
95 char *dirname0 = dirname(path);
97 int size = strlen(dirname0);
98 PyrString *strobj = newPyrStringN(g->gc, size, 0, true);
99 memcpy(strobj->s, dirname0, size);
101 SetObject(a, strobj);
103 return errNone;
106 struct sc_process {
107 pid_t pid;
108 FILE *stream;
109 bool postOutput;
112 void* string_popen_thread_func(void *data);
113 void* string_popen_thread_func(void *data)
115 struct sc_process *process = (struct sc_process *)data;
116 FILE *stream = process->stream;
117 pid_t pid = process->pid;
118 char buf[1024];
120 while (process->postOutput) {
121 char *string = fgets(buf, 1024, stream);
122 if (!string) break;
123 postText(string, strlen(string));
126 int res;
127 res = sc_pclose(stream, pid);
128 res = WEXITSTATUS(res);
130 if(process->postOutput)
131 postfl("RESULT = %d\n", res);
133 free(process);
135 pthread_mutex_lock (&gLangMutex);
136 if(compiledOK) {
137 VMGlobals *g = gMainVMGlobals;
138 g->canCallOS = true;
139 ++g->sp; SetObject(g->sp, class_string);
140 ++g->sp; SetInt(g->sp, res);
141 ++g->sp; SetInt(g->sp, pid);
142 runInterpreter(g, s_unixCmdAction, 3);
143 g->canCallOS = false;
145 pthread_mutex_unlock (&gLangMutex);
147 return 0;
150 int prString_POpen(struct VMGlobals *g, int numArgsPushed);
151 int prString_POpen(struct VMGlobals *g, int numArgsPushed)
153 struct sc_process *process;
154 PyrSlot *a = g->sp - 1;
155 PyrSlot *b = g->sp;
156 int err;
158 if (!isKindOfSlot(a, class_string)) return errWrongType;
160 char *cmdline = (char*)malloc(slotRawObject(a)->size + 1);
161 err = slotStrVal(a, cmdline, slotRawObject(a)->size + 1);
162 if(err) {
163 free(cmdline);
164 return errFailed;
167 #ifdef SC_IPHONE
168 SetInt(a, 0);
169 return errNone;
170 #endif
172 process = (struct sc_process *)malloc(sizeof(struct sc_process));
173 process->stream = sc_popen(cmdline, &process->pid, "r");
174 setvbuf(process->stream, 0, _IONBF, 0);
176 process->postOutput = IsTrue(b);
178 free(cmdline);
180 if(process->stream == NULL) {
181 free(process);
182 return errFailed;
185 pthread_t thread;
186 pthread_create(&thread, NULL, string_popen_thread_func, (void*)process);
187 pthread_detach(thread);
189 SetInt(a, process->pid);
190 return errNone;
193 int prPidRunning(VMGlobals *g, int numArgsPushed);
194 int prPidRunning(VMGlobals *g, int numArgsPushed)
196 PyrSlot *a;
198 a = g->sp;
200 #ifdef SC_WIN32
201 HANDLE handle;
203 handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, slotRawInt(a));
204 if(handle) {
205 unsigned long exitCode;
207 if(GetExitCodeProcess(handle, &exitCode) == 0)
208 SetFalse(a);
209 else if(exitCode == STILL_ACTIVE)
210 SetTrue(a);
212 CloseHandle(handle);
214 else
215 SetFalse(a);
216 #else
217 if(kill(slotRawInt(a), 0) == 0)
218 SetTrue(a);
219 else
220 SetFalse(a);
221 #endif
223 return errNone;
226 int prUnix_Errno(struct VMGlobals *g, int numArgsPushed);
227 int prUnix_Errno(struct VMGlobals *g, int numArgsPushed)
229 PyrSlot *a = g->sp;
231 SetInt(a, errno);
233 return errNone;
236 #include <time.h>
238 #ifndef SC_WIN32
239 #include <sys/time.h>
240 #endif
242 double bootSeconds();
244 int prLocalTime(struct VMGlobals *g, int numArgsPushed);
245 int prLocalTime(struct VMGlobals *g, int numArgsPushed)
247 PyrSlot *a = g->sp;
248 PyrSlot *slots = slotRawObject(a)->slots;
250 struct timeval tv;
251 gettimeofday(&tv, 0);
253 struct tm* tm = localtime((const time_t*)&tv.tv_sec);
255 SetInt(slots+0, tm->tm_year + 1900);
256 SetInt(slots+1, tm->tm_mon + 1); // 0 based month ??
257 SetInt(slots+2, tm->tm_mday);
258 SetInt(slots+3, tm->tm_hour);
259 SetInt(slots+4, tm->tm_min);
260 SetInt(slots+5, tm->tm_sec);
261 SetInt(slots+6, tm->tm_wday);
262 SetFloat(slots+7, tv.tv_sec + 1e-6 * tv.tv_usec);
263 SetFloat(slots+8, bootSeconds());
265 return errNone;
268 int prGMTime(struct VMGlobals *g, int numArgsPushed);
269 int prGMTime(struct VMGlobals *g, int numArgsPushed)
271 PyrSlot *a = g->sp;
272 PyrSlot *slots = slotRawObject(a)->slots;
274 struct timeval tv;
275 gettimeofday(&tv, 0);
277 struct tm* tm = gmtime((const time_t*)&tv.tv_sec);
279 SetInt(slots+0, tm->tm_year + 1900);
280 SetInt(slots+1, tm->tm_mon + 1);
281 SetInt(slots+2, tm->tm_mday);
282 SetInt(slots+3, tm->tm_hour);
283 SetInt(slots+4, tm->tm_min);
284 SetInt(slots+5, tm->tm_sec);
285 SetInt(slots+6, tm->tm_wday);
286 SetFloat(slots+7, tv.tv_sec + 1e-6 * tv.tv_usec);
287 SetFloat(slots+8, bootSeconds());
289 return errNone;
292 int prAscTime(struct VMGlobals *g, int numArgsPushed);
293 int prAscTime(struct VMGlobals *g, int numArgsPushed)
295 PyrSlot *a = g->sp;
296 PyrSlot *slots = slotRawObject(a)->slots;
298 if (IsNil(slots + 0)) {
299 SetNil(a);
300 return errNone;
303 struct tm tm0;
305 if (slotIntVal(slots+0, &tm0.tm_year)) return errWrongType;
306 tm0.tm_year -= 1900;
307 if (slotIntVal(slots+1, &tm0.tm_mon)) return errWrongType;
308 tm0.tm_mon -- ;
309 if (slotIntVal(slots+2, &tm0.tm_mday)) return errWrongType;
310 if (slotIntVal(slots+3, &tm0.tm_hour)) return errWrongType;
311 if (slotIntVal(slots+4, &tm0.tm_min)) return errWrongType;
312 if (slotIntVal(slots+5, &tm0.tm_sec)) return errWrongType;
313 if (slotIntVal(slots+6, &tm0.tm_wday)) return errWrongType;
315 const char *text = asctime(&tm0);
317 int size = strlen(text) - 1; // Discard trailing newline
318 PyrString *strobj = newPyrStringN(g->gc, size, 0, true);
319 memcpy(strobj->s, text, size);
321 SetObject(a, strobj);
323 return errNone;
326 int prStrFTime(struct VMGlobals *g, int numArgsPushed);
327 int prStrFTime(struct VMGlobals *g, int numArgsPushed)
329 PyrSlot *a = g->sp - 1;
330 PyrSlot *b = g->sp;
332 PyrSlot *slots = slotRawObject(a)->slots;
334 if (IsNil(slots + 0)) {
335 SetNil(a);
336 return errNone;
339 struct tm tm0;
341 if (slotIntVal(slots+0, &tm0.tm_year)) return errWrongType;
342 tm0.tm_year -= 1900;
343 if (slotIntVal(slots+1, &tm0.tm_mon)) return errWrongType;
344 tm0.tm_mon --;
345 if (slotIntVal(slots+2, &tm0.tm_mday)) return errWrongType;
346 if (slotIntVal(slots+3, &tm0.tm_hour)) return errWrongType;
347 if (slotIntVal(slots+4, &tm0.tm_min)) return errWrongType;
348 if (slotIntVal(slots+5, &tm0.tm_sec)) return errWrongType;
349 if (slotIntVal(slots+6, &tm0.tm_wday)) return errWrongType;
351 char format[1024];
352 if (slotStrVal(b, format, 1024)) return errWrongType;
354 char buffer[1024];
355 if (strftime(buffer, 1024, format, &tm0) != 0) {
356 int size = strlen(buffer);
357 PyrString *strobj = newPyrStringN(g->gc, size, 0, true);
358 memcpy(strobj->s, buffer, size);
360 SetObject(a, strobj);
361 } else {
362 error("could not convert the date to string with the give format");
363 return errFailed;
365 return errNone;
368 int32 timeseed();
370 int prTimeSeed(struct VMGlobals *g, int numArgsPushed);
371 int prTimeSeed(struct VMGlobals *g, int numArgsPushed)
373 PyrSlot *a = g->sp;
374 SetInt(a, timeseed());
375 return errNone;
378 int prGetPid(VMGlobals *g, int numArgsPushed);
379 int prGetPid(VMGlobals *g, int numArgsPushed)
381 PyrSlot *a = g->sp;
382 SetInt(a,
383 #ifndef SC_WIN32
384 getpid()
385 #else
386 GetCurrentProcessId()
387 #endif
389 return errNone;
393 void initUnixPrimitives();
394 void initUnixPrimitives()
396 int base, index = 0;
398 base = nextPrimitiveIndex();
400 s_unixCmdAction = getsym("doUnixCmdAction");
402 definePrimitive(base, index++, "_String_System", prString_System, 1, 0);
403 definePrimitive(base, index++, "_String_Basename", prString_Basename, 1, 0);
404 definePrimitive(base, index++, "_String_Dirname", prString_Dirname, 1, 0);
405 definePrimitive(base, index++, "_String_POpen", prString_POpen, 2, 0);
406 definePrimitive(base, index++, "_Unix_Errno", prUnix_Errno, 1, 0);
407 definePrimitive(base, index++, "_LocalTime", prLocalTime, 1, 0);
408 definePrimitive(base, index++, "_GMTime", prGMTime, 1, 0);
409 definePrimitive(base, index++, "_AscTime", prAscTime, 1, 0);
410 definePrimitive(base, index++, "_prStrFTime", prStrFTime, 2, 0);
411 definePrimitive(base, index++, "_TimeSeed", prTimeSeed, 1, 0);
412 definePrimitive(base, index++, "_PidRunning", prPidRunning, 1, 0);
413 definePrimitive(base, index++, "_GetPid", prGetPid, 1, 0);