module_os.c
1 #include <assert.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <unistd.h>
6 #include <signal.h>
7 #include <fcntl.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #ifndef _WIN32
11 #include <sys/utsname.h>
12 #include <sys/ioctl.h>
13 #include <termios.h>
14 #else
15 #include <windows.h>
16 #endif
17 
18 #include <kuroko/vm.h>
19 #include <kuroko/value.h>
20 #include <kuroko/object.h>
21 #include <kuroko/util.h>
22 
23 /* Did you know this is actually specified to not exist in a header? */
24 extern char ** environ;
25 
26 static KrkClass * os_Environ;
27 static KrkClass * os_stat_result;
28 
29 #define DO_KEY(key) krk_attachNamedObject(AS_DICT(result), #key, (KrkObj*)krk_copyString(buf. key, strlen(buf .key)))
30 #define S_KEY(key,val) krk_attachNamedObject(AS_DICT(result), #key, (KrkObj*)val);
31 
32 #ifndef _WIN32
33 KRK_Function(uname) {
34  struct utsname buf;
35  if (uname(&buf) < 0) return NONE_VAL();
36 
37  KrkValue result = krk_dict_of(0, NULL, 0);
38  krk_push(result);
39 
40  DO_KEY(sysname);
41  DO_KEY(nodename);
42  DO_KEY(release);
43  DO_KEY(version);
44  DO_KEY(machine);
45 
46  return krk_pop();;
47 }
48 #else
49 KRK_Function(uname) {
50  KrkValue result = krk_dict_of(0, NULL, 0);
51  krk_push(result);
52 
53  TCHAR buffer[256] = TEXT("");
54  DWORD dwSize = sizeof(buffer);
55  GetComputerName(buffer, &dwSize);
56 
57  OSVERSIONINFOA versionInfo = {0};
58  versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
59  GetVersionExA(&versionInfo);
60 
61  if (versionInfo.dwMajorVersion == 10) {
62  S_KEY(release,S("10"));
63  } else if (versionInfo.dwMajorVersion == 6) {
64  if (versionInfo.dwMinorVersion == 3) {
65  S_KEY(release,S("8.1"));
66  } else if (versionInfo.dwMinorVersion == 2) {
67  S_KEY(release,S("8.0"));
68  } else if (versionInfo.dwMinorVersion == 1) {
69  S_KEY(release,S("7"));
70  } else if (versionInfo.dwMinorVersion == 0) {
71  S_KEY(release,S("Vista"));
72  }
73  } else {
74  S_KEY(release,S("XP or earlier"));
75  }
76 
77  char tmp[256];
78  size_t len = snprintf(tmp, 256, "%ld", versionInfo.dwBuildNumber);
79 
80  S_KEY(version, krk_copyString(tmp,len));
81  if (sizeof(void *) == 8) {
82  S_KEY(machine,S("x64"));
83  } else {
84  S_KEY(machine,S("x86"));
85  }
86 
87  S_KEY(sysname,S("Windows"));
88  S_KEY(nodename,krk_copyString(buffer,dwSize));
89 
90  return krk_pop();
91 }
92 #endif
93 
94 #define AS_Environ(o) (AS_INSTANCE(o))
95 #define IS_Environ(o) (krk_isInstanceOf(o,os_Environ))
96 #define CURRENT_CTYPE KrkInstance*
97 
98 static int _setVar(KrkString * key, KrkString * val) {
99 #ifndef _WIN32
100  return setenv(key->chars, val->chars, 1);
101 #else
102  size_t len = key->length + val->length + 3;
103  char * tmp = malloc(len);
104  snprintf(tmp, len, "%s=%s", key->chars, val->chars);
105  return putenv(tmp);
106 #endif
107 }
108 
109 KRK_Method(Environ,__setitem__) {
110  METHOD_TAKES_EXACTLY(2);
111  CHECK_ARG(1,str,KrkString*,key);
112  CHECK_ARG(2,str,KrkString*,val);
113  int r = _setVar(key,val);
114  if (r == 0) {
115  krk_push(argv[0]);
116  krk_push(argv[1]);
117  krk_push(argv[2]);
118  return krk_callDirect(vm.baseClasses->dictClass->_setter, 3);
119  }
120 
121  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
122 }
123 
124 static void _unsetVar(KrkString * str) {
125 #ifndef _WIN32
126  unsetenv(str->chars);
127 #else
128  size_t len = str->length + 2;
129  char * tmp = malloc(len);
130  snprintf(tmp, len, "%s", str->chars);
131  putenv(tmp);
132  free(tmp);
133 #endif
134 }
135 
136 KRK_Method(Environ,__delitem__) {
137  METHOD_TAKES_EXACTLY(1);
138  CHECK_ARG(1,str,KrkString*,key);
139  _unsetVar(key);
140  krk_push(argv[0]);
141  krk_push(argv[1]);
142  return krk_callDirect(vm.baseClasses->dictClass->_delitem, 2);
143 }
144 
145 static void _loadEnviron(KrkInstance * module) {
146  /* Create a new class to subclass `dict` */
147  KrkClass * Environ = krk_makeClass(module, &os_Environ, "_Environ", vm.baseClasses->dictClass);
148  krk_attachNamedObject(&module->fields, "_Environ", (KrkObj*)Environ);
149 
150  /* Add our set method that should also call dict's set method */
151  BIND_METHOD(Environ,__setitem__);
152  BIND_METHOD(Environ,__delitem__);
153  krk_finalizeClass(Environ);
154 
155  /* Start with an empty dictionary */
156  KrkInstance * environObj = AS_INSTANCE(krk_dict_of(0,NULL,0));
157  krk_push(OBJECT_VAL(environObj));
158 
159  /* Transform it into an _Environ */
160  environObj->_class = Environ;
161 
162  /* And attach it to the module */
163  krk_attachNamedObject(&module->fields, "environ", (KrkObj*)environObj);
164  krk_pop();
165 
166  /* Now load the environment into it */
167  if (!environ) return; /* Empty environment */
168 
169  char ** env = environ;
170  for (; *env; env++) {
171  const char * equals = strchr(*env, '=');
172  if (!equals) continue;
173 
174  size_t len = strlen(*env);
175  size_t keyLen = equals - *env;
176  size_t valLen = len - keyLen - 1;
177 
178  KrkValue key = OBJECT_VAL(krk_copyString(*env, keyLen));
179  krk_push(key);
180  KrkValue val = OBJECT_VAL(krk_copyString(equals+1, valLen));
181  krk_push(val);
182 
183  krk_tableSet(AS_DICT(OBJECT_VAL(environObj)), key, val);
184  krk_pop(); /* val */
185  krk_pop(); /* key */
186  }
187 
188 }
189 
190 KRK_Function(system) {
191  const char * cmd;
192  if (!krk_parseArgs("s",(const char*[]){"command"},&cmd)) return NONE_VAL();
193  return INTEGER_VAL(system(cmd));
194 }
195 
196 KRK_Function(getcwd) {
197  FUNCTION_TAKES_NONE();
198  char buf[4096]; /* TODO PATH_MAX? */
199  if (!getcwd(buf, 4096)) return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
200  return OBJECT_VAL(krk_copyString(buf, strlen(buf)));
201 }
202 
203 KRK_Function(chdir) {
204  const char * path;
205  if (!krk_parseArgs("s",(const char*[]){"path"}, &path)) return NONE_VAL();
206  if (chdir(path)) return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
207  return NONE_VAL();
208 }
209 
210 KRK_Function(getpid) {
211  FUNCTION_TAKES_NONE();
212  return INTEGER_VAL(getpid());
213 }
214 
215 KRK_Function(strerror) {
216  int errnum;
217  if (!krk_parseArgs("i",(const char*[]){"errnum"},&errnum)) return NONE_VAL();
218  char *s = strerror(errnum);
219  if (!s) return NONE_VAL();
220  return OBJECT_VAL(krk_copyString(s,strlen(s)));
221 }
222 
223 KRK_Function(access) {
224  const char * path;
225  int mask;
226  if (!krk_parseArgs("si",(const char*[]){"pathname","mode"},&path,&mask)) return NONE_VAL();
227  if (access(path, mask) == 0) return BOOLEAN_VAL(1);
228  return BOOLEAN_VAL(0);
229 }
230 
231 KRK_Function(abort) {
232  abort();
233 }
234 
235 KRK_Function(exit) {
236  int status;
237  if (!krk_parseArgs("i",(const char*[]){"status"},&status)) return NONE_VAL();
238  exit(status);
239 }
240 
241 KRK_Function(remove) {
242  const char * path;
243  if (!krk_parseArgs("s",(const char*[]){"path"}, &path)) return NONE_VAL();
244  if (remove(path) != 0) {
245  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
246  }
247  return NONE_VAL();
248 }
249 
250 KRK_Function(truncate) {
251  const char * path;
252  size_t length;
253  if (!krk_parseArgs("sn",(const char*[]){"path","length"}, &path, &length)) return NONE_VAL();
254  if (truncate(path, length) != 0) {
255  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
256  }
257  return NONE_VAL();
258 }
259 
260 KRK_Function(dup) {
261  int fd;
262  if (!krk_parseArgs("i",(const char*[]){"fd"}, &fd)) return NONE_VAL();
263  int result = dup(fd);
264  if (result < 0) {
265  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
266  }
267  return INTEGER_VAL(result);
268 }
269 
270 KRK_Function(dup2) {
271  int fd, fd2;
272  if (!krk_parseArgs("ii",(const char*[]){"fd","fd2"}, &fd, &fd2)) return NONE_VAL();
273  int result = dup2(fd,fd2);
274  if (result < 0) {
275  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
276  }
277  return INTEGER_VAL(result);
278 }
279 
280 KRK_Function(isatty) {
281  int fd;
282  if (!krk_parseArgs("i",(const char*[]){"fd"}, &fd)) return NONE_VAL();
283  return BOOLEAN_VAL(isatty(fd));
284 }
285 
286 KRK_Function(lseek) {
287  int fd, how;
288  ssize_t offset;
289  if (!krk_parseArgs("ini",(const char*[]){"fd","offset","how"}, &fd, &offset, &how)) return NONE_VAL();
290  off_t result = lseek(fd,offset,how);
291  if (result == -1) {
292  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
293  }
294  return INTEGER_VAL(result);
295 }
296 
297 KRK_Function(open) {
298  const char * path;
299  int flags;
300  int mode = 0777;
301  if (!krk_parseArgs("si|i",(const char*[]){"path","flags","mode"}, &path, &flags, &mode)) return NONE_VAL();
302  int result = open(path, flags, mode);
303  if (result == -1) {
304  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
305  }
306  return INTEGER_VAL(result);
307 }
308 
309 KRK_Function(close) {
310  int fd;
311  if (!krk_parseArgs("i",(const char*[]){"fd"}, &fd)) return NONE_VAL();
312  if (close(fd) == -1) {
313  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
314  }
315  return NONE_VAL();
316 }
317 
318 #ifdef _WIN32
319 #define mkdir(p,m) mkdir(p); (void)m
320 #endif
321 KRK_Function(mkdir) {
322  const char * path;
323  int mode = 0777;
324  if (!krk_parseArgs("s|i",(const char*[]){"path","mode"}, &path, &mode)) return NONE_VAL();
325  int result = mkdir(path, mode);
326  if (result == -1) {
327  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
328  }
329  return NONE_VAL();
330 }
331 
332 KRK_Function(read) {
333  int fd;
334  ssize_t count;
335  if (!krk_parseArgs("in",(const char*[]){"fd","count"}, &fd, &count)) return NONE_VAL();
336 
337  uint8_t * tmp = malloc(count);
338  ssize_t result = read(fd,tmp,count);
339  if (result == -1) {
340  free(tmp);
341  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
342  } else {
343  krk_push(OBJECT_VAL(krk_newBytes(result,tmp)));
344  free(tmp);
345  return krk_pop();
346  }
347 }
348 
349 #ifndef IS_bytes
350 #define IS_bytes(o) IS_BYTES(o)
351 #define AS_bytes(o) AS_BYTES(o)
352 #endif
353 
354 KRK_Function(write) {
355  int fd;
356  KrkBytes * buf;
357  if (!krk_parseArgs("iO!",(const char*[]){"fd","buf"}, &fd, KRK_BASE_CLASS(bytes), &buf)) return NONE_VAL();
358 
359  ssize_t result = write(fd,buf->bytes,buf->length);
360  if (result == -1) {
361  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
362  }
363  return INTEGER_VAL(result);
364 }
365 
366 #ifndef _WIN32
367 KRK_Function(pipe) {
368  FUNCTION_TAKES_NONE();
369  int fds[2];
370  if (pipe(fds) == -1) {
371  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
372  }
373  krk_push(OBJECT_VAL(krk_newTuple(2)));
374  AS_TUPLE(krk_peek(0))->values.values[0] = INTEGER_VAL(fds[0]);
375  AS_TUPLE(krk_peek(0))->values.values[1] = INTEGER_VAL(fds[1]);
376  AS_TUPLE(krk_peek(0))->values.count = 2;
377  return krk_pop();
378 }
379 
380 KRK_Function(kill) {
381  FUNCTION_TAKES_EXACTLY(2);
382  ssize_t pid;
383  int sig;
384  if (!krk_parseArgs("ni",(const char*[]){"pid","sig"}, &pid, &sig)) return NONE_VAL();
385 
386  int result = kill(pid, sig);
387  if (result == -1) {
388  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
389  }
390  return INTEGER_VAL(result);
391 }
392 
393 KRK_Function(fork) {
394  FUNCTION_TAKES_NONE();
395  return INTEGER_VAL(fork());
396 }
397 
398 KRK_Function(symlink) {
399  const char * src;
400  const char * dst;
401  if (!krk_parseArgs("ss",(const char*[]){"target","linkpath"}, &src, &dst)) return NONE_VAL();
402 
403  if (symlink(src, dst) != 0) {
404  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
405  }
406  return NONE_VAL();
407 }
408 
409 KRK_Function(tcgetpgrp) {
410  int fd;
411  if (!krk_parseArgs("i",(const char*[]){"fd"}, &fd)) return NONE_VAL();
412  int result = tcgetpgrp(fd);
413  if (result == -1) {
414  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
415  }
416  return INTEGER_VAL(result);
417 }
418 
419 KRK_Function(tcsetpgrp) {
420  int fd;
421  ssize_t pgrp;
422  if (!krk_parseArgs("in",(const char*[]){"fd","pgrp"}, &fd, &pgrp)) return NONE_VAL();
423  int result = tcsetpgrp(fd,pgrp);
424  if (result == -1) {
425  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
426  }
427  return NONE_VAL();
428 }
429 
430 KRK_Function(ttyname) {
431  int fd;
432  if (!krk_parseArgs("i",(const char*[]){"fd"}, &fd)) return NONE_VAL();
433  char * result = ttyname(fd);
434  if (!result) {
435  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
436  }
437  return OBJECT_VAL(krk_copyString(result,strlen(result)));
438 }
439 
440 KRK_Function(get_terminal_size) {
441  int fd = 1;
442  if (!krk_parseArgs("|i",(const char*[]){"fd"}, &fd)) return NONE_VAL();
443 
444  struct winsize wsz;
445  int res = ioctl(fd, TIOCGWINSZ, &wsz);
446 
447  if (res < 0) {
448  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
449  }
450 
451  krk_push(OBJECT_VAL(krk_newTuple(2)));
452  AS_TUPLE(krk_peek(0))->values.values[0] = INTEGER_VAL(wsz.ws_col);
453  AS_TUPLE(krk_peek(0))->values.values[1] = INTEGER_VAL(wsz.ws_row);
454  AS_TUPLE(krk_peek(0))->values.count = 2;
455  return krk_pop();
456 }
457 #endif
458 
459 static int makeArgs(int count, const KrkValue * values, char *** argsOut, const char * _method_name) {
460  char ** out = malloc(sizeof(char*)*(count+1));
461  for (int i = 0; i < count; ++i) {
462  if (!IS_STRING(values[i])) {
463  free(out);
464  TYPE_ERROR(str,values[i]);
465  return 1;
466  }
467  out[i] = AS_CSTRING(values[i]);
468  }
469  out[count] = NULL;
470  *argsOut = out;
471  return 0;
472 }
473 
474 KRK_Function(execl) {
475  FUNCTION_TAKES_AT_LEAST(1);
476  CHECK_ARG(0,str,KrkString*,path);
477  char ** args;
478  if (makeArgs(argc-1,&argv[1],&args,_method_name)) return NONE_VAL();
479  if (execv(path->chars, args) == -1) {
480  free(args);
481  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
482  }
483  return krk_runtimeError(KRK_EXC(OSError), "Expected to not return from exec, but did.");
484 }
485 
486 KRK_Function(execlp) {
487  FUNCTION_TAKES_AT_LEAST(1);
488  CHECK_ARG(0,str,KrkString*,filename);
489  char ** args;
490  if (makeArgs(argc-1,&argv[1],&args,_method_name)) return NONE_VAL();
491  if (execvp(filename->chars, args) == -1) {
492  free(args);
493  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
494  }
495  return krk_runtimeError(KRK_EXC(OSError), "Expected to not return from exec, but did.");
496 }
497 
498 KRK_Function(execle) {
499  FUNCTION_TAKES_AT_LEAST(1);
500  CHECK_ARG(0,str,KrkString*,path);
501  CHECK_ARG((argc-1),list,KrkList*,envp);
502  char ** args;
503  char ** env;
504  if (makeArgs(argc-2,&argv[1],&args,_method_name)) return NONE_VAL();
505  if (makeArgs(envp->values.count, envp->values.values,&env,_method_name)) {
506  free(args);
507  return NONE_VAL();
508  }
509  if (execve(path->chars, args, env) == -1) {
510  free(args);
511  free(env);
512  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
513  }
514  return krk_runtimeError(KRK_EXC(OSError), "Expected to not return from exec, but did.");
515 }
516 
517 KRK_Function(execv) {
518  FUNCTION_TAKES_EXACTLY(2);
519  CHECK_ARG(0,str,KrkString*,filename);
520  CHECK_ARG(1,list,KrkList*,args);
521  char ** argp;
522  if (makeArgs(args->values.count, args->values.values, &argp,_method_name)) return NONE_VAL();
523  if (execv(filename->chars, argp) == -1) {
524  free(argp);
525  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
526  }
527  return krk_runtimeError(KRK_EXC(OSError), "Expected to not return from exec, but did.");
528 }
529 
530 KRK_Function(execvp) {
531  FUNCTION_TAKES_EXACTLY(2);
532  CHECK_ARG(0,str,KrkString*,path);
533  CHECK_ARG(1,list,KrkList*,args);
534  char ** argp;
535  if (makeArgs(args->values.count, args->values.values, &argp,_method_name)) return NONE_VAL();
536  if (execvp(path->chars, argp) == -1) {
537  free(argp);
538  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
539  }
540  return krk_runtimeError(KRK_EXC(OSError), "Expected to not return from exec, but did.");
541 }
542 
543 #define SET(thing) krk_attachNamedValue(&out->fields, #thing, INTEGER_VAL(buf. thing))
544 #ifdef _WIN32
545 #define STAT_STRUCT struct __stat64
546 #define stat _stat64
547 #else
548 #define STAT_STRUCT struct stat
549 #endif
550 KRK_Function(stat) {
551  const char * path;
552  if (!krk_parseArgs("s",(const char*[]){"path"}, &path)) return NONE_VAL();
553 
554  STAT_STRUCT buf;
555  int result = stat(path, &buf);
556  if (result == -1) {
557  return krk_runtimeError(KRK_EXC(OSError), "%s", strerror(errno));
558  }
559  KrkInstance * out = krk_newInstance(os_stat_result);
560  krk_push(OBJECT_VAL(out));
561 
562  SET(st_dev);
563  SET(st_ino);
564  SET(st_mode);
565  SET(st_nlink);
566  SET(st_uid);
567  SET(st_gid);
568  SET(st_size);
569 
570  /* TODO times */
571  /* TODO block sizes */
572 
573  return krk_pop();
574 }
575 #undef SET
576 
577 #define IS_stat_result(o) (krk_isInstanceOf(o,os_stat_result))
578 #define AS_stat_result(o) AS_INSTANCE(o)
579 #define CURRENT_NAME self
580 
581 #define getProp(name) \
582  KrkValue name = NONE_VAL(); \
583  krk_tableGet(&self->fields, OBJECT_VAL(S(#name)), &name); \
584  if (!IS_INTEGER(name)) return krk_runtimeError(vm.exceptions->valueError, "stat_result is invalid")
585 
586 KRK_Method(stat_result,__repr__) {
587  METHOD_TAKES_NONE();
588  getProp(st_dev);
589  getProp(st_ino);
590  getProp(st_mode);
591  getProp(st_nlink);
592  getProp(st_uid);
593  getProp(st_gid);
594  getProp(st_size);
595 
596  char * buf = malloc(1024);
597  size_t len = snprintf(buf,1024,
598  "os.stat_result("
599  "st_dev=%d,"
600  "st_ino=%d,"
601  "st_mode=%d,"
602  "st_nlink=%d,"
603  "st_uid=%d,"
604  "st_gid=%d,"
605  "st_size=%d)",
606  (int)AS_INTEGER(st_dev),
607  (int)AS_INTEGER(st_ino),
608  (int)AS_INTEGER(st_mode),
609  (int)AS_INTEGER(st_nlink),
610  (int)AS_INTEGER(st_uid),
611  (int)AS_INTEGER(st_gid),
612  (int)AS_INTEGER(st_size));
613 
614  if (len > 1023) len = 1023;
615  krk_push(OBJECT_VAL(krk_copyString(buf,len)));
616  free(buf);
617  return krk_pop();
618 }
619 
620 KRK_Module(os) {
621  KRK_DOC(module, "@brief Provides access to low-level system operations.");
622 
623 #ifdef _WIN32
624  krk_attachNamedObject(&module->fields, "name", (KrkObj*)S("nt"));
625  krk_attachNamedObject(&module->fields, "sep", (KrkObj*)S("\\"));
626  krk_attachNamedObject(&module->fields, "altsep", (KrkObj*)S("/"));
627  krk_attachNamedObject(&module->fields, "pathsep", (KrkObj*)S(";"));
628  krk_attachNamedObject(&module->fields, "linesep", (KrkObj*)S("\r\n"));
629  krk_attachNamedObject(&module->fields, "devnull", (KrkObj*)S("nul"));
630 #else
631  krk_attachNamedObject(&module->fields, "name", (KrkObj*)S("posix"));
632  krk_attachNamedObject(&module->fields, "sep", (KrkObj*)S("/"));
633  krk_attachNamedValue(&module->fields, "altsep", NONE_VAL());
634  krk_attachNamedObject(&module->fields, "pathsep", (KrkObj*)S(":"));
635  krk_attachNamedObject(&module->fields, "linesep", (KrkObj*)S("\n"));
636  krk_attachNamedObject(&module->fields, "devnull", (KrkObj*)S("/dev/null"));
637 #endif
638 
639  krk_attachNamedObject(&module->fields, "curdir", (KrkObj*)S("."));
640  krk_attachNamedObject(&module->fields, "pardir", (KrkObj*)S(".."));
641  krk_attachNamedObject(&module->fields, "extsep", (KrkObj*)S("."));
642 
643 #define DO_INT(name) krk_attachNamedValue(&module->fields, #name, INTEGER_VAL(name))
644 
645  DO_INT(O_RDONLY);
646  DO_INT(O_WRONLY);
647  DO_INT(O_RDWR);
648  DO_INT(O_APPEND);
649  DO_INT(O_CREAT);
650  DO_INT(O_EXCL);
651  DO_INT(O_TRUNC);
652 
653 #ifdef O_CLOEXEC
654  DO_INT(O_CLOEXEC);
655 #endif
656 #ifdef O_DIRECTORY
657  DO_INT(O_DIRECTORY);
658 #endif
659 #ifdef O_PATH
660  DO_INT(O_PATH);
661 #endif
662 #ifdef O_NOFOLLOW
663  DO_INT(O_NOFOLLOW);
664 #endif
665 #ifdef O_NONBLOCK
666  DO_INT(O_NONBLOCK);
667 #endif
668 
669  DO_INT(SEEK_SET);
670  DO_INT(SEEK_CUR);
671  DO_INT(SEEK_END);
672 
673 #ifdef SEEK_HOLE
674  DO_INT(SEEK_HOLE);
675 #endif
676 #ifdef SEEK_DATA
677  DO_INT(SEEK_DATA);
678 #endif
679 
680  KRK_DOC(BIND_FUNC(module,uname),
681  "@brief Returns a @ref dict of attributes describing the current platform.\n\n"
682  "On POSIX platforms, the result should match the contents and layout of a standard @c uname() call. "
683  "On Windows, values are synthesized from available information.");
684  KRK_DOC(BIND_FUNC(module,system),
685  "@brief Call the system shell.\n"
686  "@arguments cmd\n\n"
687  "Runs @p cmd using the system shell and returns the platform-dependent return value.");
688  KRK_DOC(BIND_FUNC(module,getcwd),
689  "@brief Get the name of the current working directory.");
690  KRK_DOC(BIND_FUNC(module,chdir),
691  "@brief Change the current working directory.\n"
692  "@arguments newcwd\n\n"
693  "Attempts to change the working directory to @p newcwd. Raises @ref OSError on failure.");
694  KRK_DOC(BIND_FUNC(module,getpid),
695  "@brief Obtain the system process identifier.");
696  KRK_DOC(BIND_FUNC(module,strerror),
697  "@brief Convert an integer error code to a string.\n"
698  "@arguments errorno\n\n"
699  "Provides the string description for the error code specified by @p errorno.");
700  KRK_DOC(BIND_FUNC(module,abort),
701  "@brief Abort the current process.\n\n"
702  "@bsnote{This will exit the interpreter without calling cleanup routines.}");
703  KRK_DOC(BIND_FUNC(module,exit),
704  "@brief Exit the current process.\n\n"
705  "@bsnote{This will exit the interpreter without calling cleanup routines.}");
706  KRK_DOC(BIND_FUNC(module,remove),
707  "@brief Delete a file.\n"
708  "@arguments path\n\n"
709  "Attempts to delete the file at @p path.");
710  KRK_DOC(BIND_FUNC(module,truncate),
711  "@brief Resize a file.\n"
712  "@arguments path,length\n\n"
713  "Attempts to resize the file at @p path to @p length bytes.");
714  KRK_DOC(BIND_FUNC(module,dup),
715  "@brief Duplicate a file descriptor.\n"
716  "@arguments fd\n\n"
717  "Returns a new file descriptor pointing to the same file as @p fd.");
718  KRK_DOC(BIND_FUNC(module,dup2),
719  "@brief Duplicate a file descriptor.\n"
720  "@arguments oldfd,newfd\n\n"
721  "Like @ref dup but the new file descriptor is placed at @p newfd.\n");
722  KRK_DOC(BIND_FUNC(module,isatty),
723  "@brief Determine if a file descriptor is a terminal.\n"
724  "@arguments fd\n\n"
725  "Returns a @ref bool indicating whether the open file descriptor @p fd refers to a terminal.");
726  KRK_DOC(BIND_FUNC(module,lseek),
727  "@brief Seek an open file descriptor.\n"
728  "@arguments fd,pos,how\n\n"
729  "Seeks the open file descriptor @p fd by @p pos bytes as specified in @p how. "
730  "Use the values @c SEEK_SET, @c SEEK_CUR, and @c SEEK_END for @p how.");
731  KRK_DOC(BIND_FUNC(module,open),
732  "@brief Open a file.\n"
733  "@arguments path,flags,mode=0o777\n\n"
734  "Opens the file at @p path with the specified @p flags and @p mode. Returns a file descriptor.\n\n"
735  "@bsnote{Not to be confused with <a class=\"el\" href=\"mod_fileio.html#open\">fileio.open</a>}");
736  KRK_DOC(BIND_FUNC(module,close),
737  "@brief Close an open file descriptor.\n"
738  "@arguments fd");
739  KRK_DOC(BIND_FUNC(module,read),
740  "@brief Read from an open file descriptor.\n"
741  "@arguments fd,n\n\n"
742  "Reads at most @p n bytes from the open file descriptor @p fd.");
743  KRK_DOC(BIND_FUNC(module,write),
744  "@brief Write to an open file descriptor.\n"
745  "@arguments fd,data\n\n"
746  "Writes the @ref bytes object @p data to the open file descriptor @p fd.");
747  KRK_DOC(BIND_FUNC(module,mkdir),
748  "@brief Create a directory.\n"
749  "@arguments path,mode=0o777\n\n"
750  "Creates a directory at @p path.");
751 
752  KRK_DOC(BIND_FUNC(module,execl),
753  "@brief Replace the current process.\n"
754  "@arguments path,[args...]\n\n"
755  "The @c exec* family of functions replaces the calling process's image with a new one. "
756  "@c execl takes a @p path to a binary and an arbitrary number of @ref str arguments to "
757  "pass to the new executable.");
758  KRK_DOC(BIND_FUNC(module,execle),
759  "@brief Replace the current process.\n"
760  "@arguments path,[args...],env\n\n"
761  "The @c exec* family of functions replaces the calling process's image with a new one. "
762  "@c execle takes a @p path to a binary, an arbitrary number of @ref str arguments to "
763  "pass to the new executable, and @ref list of @c 'KEY=VALUE' pairs to set as the new "
764  "environment.");
765  KRK_DOC(BIND_FUNC(module,execlp),
766  "@brief Replace the current process.\n"
767  "@arguments filename,[args...]\n\n"
768  "The @c exec* family of functions replaces the calling process's image with a new one. "
769  "@c execlp takes a @p filename of a binary and an arbitrary number of @ref str arguments to "
770  "pass to the new executable. @p filename will be searched for in @c $PATH.");
771  KRK_DOC(BIND_FUNC(module,execv),
772  "@brief Replace the current process.\n"
773  "@arguments path,args\n\n"
774  "The @c exec* family of functions replaces the calling process's image with a new one. "
775  "@c execv takes a @p path to a binary and a @ref list @p args of @ref str arguments to "
776  "pass to the new executable.");
777  KRK_DOC(BIND_FUNC(module,execvp),
778  "@brief Replace the current process.\n"
779  "@arguments filename,args\n\n"
780  "The @c exec* family of functions replaces the calling process's image with a new one. "
781  "@c execvp takes a @p filename of a binary and a @ref list @p args of @ref str arguments to "
782  "pass to the new executable. @p filename will be searched for in @c $PATH.");
783 
784  DO_INT(F_OK);
785  DO_INT(R_OK);
786  DO_INT(W_OK);
787  DO_INT(X_OK);
788  KRK_DOC(BIND_FUNC(module,access),
789  "@brief Determine if a file can be accessed.\n"
790  "@arguments path,mask\n\n"
791  "Use the values @c F_OK, @c R_OK, @c W_OK, and @c X_OK to construct @p mask and check if the current "
792  "process has sufficient access rights to perform the requested operations on the file "
793  "at @p path.");
794 
795 #ifndef _WIN32
796  KRK_DOC(BIND_FUNC(module,pipe),
797  "@brief Create a pipe.\n\n"
798  "Creates a _pipe_, returning a two-tuple of file descriptors for the read and write ends respectively.");
799  KRK_DOC(BIND_FUNC(module,kill),
800  "@brief Send a signal to a process.\n"
801  "@arguments pid,signum\n\n"
802  "Send the signal @p signum to the process at @p pid.\n");
803  KRK_DOC(BIND_FUNC(module,fork),
804  "@brief Fork the current process.\n\n"
805  "Returns the PID of the new child process in the original process and @c 0 in the child.");
806  KRK_DOC(BIND_FUNC(module,symlink),
807  "@brief Create a symbolic link.\n"
808  "@arguments src,dst\n\n"
809  "Creates a symbolic link at @p src pointing to @p dst.");
810 
811  KRK_DOC(BIND_FUNC(module,tcgetpgrp),
812  "@brief Get the terminal foreground process group.\n"
813  "@arguments fd\n\n"
814  "Return the PID representing the foreground process group of the terminal specified by the file descriptor @p fd.");
815  KRK_DOC(BIND_FUNC(module,tcsetpgrp),
816  "@brief %Set the terminal foreground process group.\n"
817  "@arguments fd,pgrp\n\n"
818  "%Set the PID representing the foreground process group of the terminal specified by the file descriptor @p fd to @p pgrp.");
819  KRK_DOC(BIND_FUNC(module,ttyname),
820  "@brief Get the path to a terminal device.\n"
821  "@arguments fd\n\n"
822  "Returns a @ref str representing the path to the terminal device provided by the file descriptor @p fd.");
823 
824  KRK_DOC(BIND_FUNC(module,get_terminal_size),
825  "@brief Obtain the size of the terminal window.\n"
826  "@arguments fd=1\n"
827  "Obtain the size of the host terminal as a tuple of columns and lines.");
828 #endif
829 
830  _loadEnviron(module);
831 
832  /* Nothing special */
833  KrkClass * stat_result = krk_makeClass(module, &os_stat_result, "stat_result", vm.baseClasses->objectClass);
834  BIND_METHOD(stat_result,__repr__);
835  krk_finalizeClass(stat_result);
836 
837  KRK_DOC(BIND_FUNC(module,stat),
838  "@brief Get the status of a file\n"
839  "@arguments path\n\n"
840  "Runs the @c stat system call on @p path. Returns a @ref stat_result.\n");
841 }
842 
843 
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
Definition: exceptions.c:460
KRK_Module(socket)
Struct definitions for core object types.
Immutable sequence of bytes.
Definition: object.h:105
size_t length
Length of data in bytes.
Definition: object.h:107
uint8_t * bytes
Pointer to separately-stored bytes data.
Definition: object.h:108
KrkBytes * krk_newBytes(size_t length, uint8_t *source)
Create a new byte array.
Definition: object.c:367
Type object.
Definition: object.h:215
KrkClass * krk_makeClass(KrkInstance *module, KrkClass **_class, const char *name, KrkClass *base)
Convenience function for creating new types.
Definition: vm.c:164
void krk_finalizeClass(KrkClass *_class)
Finalize a class by collecting pointers to core methods.
Definition: vm.c:189
KrkValue krk_dict_of(int argc, const KrkValue argv[], int hasKw)
Create a dict object.
Definition: obj_dict.c:19
An object of a class.
Definition: object.h:281
KrkInstance * krk_newInstance(KrkClass *_class)
Create a new instance of the given class.
Definition: object.c:343
KrkClass * _class
Type.
Definition: object.h:283
KrkTable fields
Attributes table.
Definition: object.h:284
Mutable array of values.
Definition: object.h:335
The most basic object type.
Definition: object.h:41
Immutable sequence of Unicode codepoints.
Definition: object.h:93
KrkString * krk_copyString(const char *chars, size_t length)
Obtain a string object representation of the given C string.
Definition: object.c:224
char * chars
UTF8 canonical data.
Definition: object.h:97
size_t length
String length in bytes.
Definition: object.h:95
int krk_tableSet(KrkTable *table, KrkValue key, KrkValue value)
Assign a value to a key in a table.
Definition: table.c:148
void krk_attachNamedObject(KrkTable *table, const char name[], KrkObj *obj)
Attach an object to an attribute table.
Definition: vm.c:808
void krk_attachNamedValue(KrkTable *table, const char name[], KrkValue obj)
Attach a value to an attribute table.
Definition: vm.c:794
KrkTuple * krk_newTuple(size_t length)
Create a new tuple.
Definition: object.c:357
Stack reference or primative value.
Utilities for creating native bindings.
#define krk_parseArgs(f, n,...)
Parse arguments to a function while accepting keyword arguments.
Definition: util.h:360
#define KRK_DOC(thing, text)
Attach documentation to a thing of various types.
Definition: util.h:304
Definitions for primitive stack references.
Core API for the bytecode virtual machine.
#define vm
Convenience macro for namespacing.
Definition: vm.h:257
KrkValue krk_pop(void)
Pop the top of the stack.
Definition: vm.c:131
void krk_push(KrkValue value)
Push a stack value.
Definition: vm.c:118
KrkValue krk_callDirect(KrkObj *callable, int argCount)
Call a closure or native function with argCount arguments.
Definition: vm.c:740
KrkValue krk_peek(int distance)
Peek down from the top of the stack.
Definition: vm.c:139