OS module implemented

This commit is contained in:
Thakee Nathees 2022-05-28 19:14:44 +05:30
parent 176a0dc0c8
commit 916424da5a
8 changed files with 245 additions and 46 deletions

View File

@ -56,7 +56,7 @@ static PKVM* intializePocketVM() {
GetConsoleMode(handle, &outmode);
SetConsoleMode(handle, outmode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
#endif
config.use_ansi_color = true;
config.use_ansi_escape = true;
}
PKVM* vm = pkNewVM(&config);

View File

@ -15,7 +15,7 @@
// Refactor this. Maybe move to a module, Rgb values are hardcoded ?!
// Should check stderr/stdout etc.
static void _printRed(PKVM* vm, const char* msg) {
if (vm->config.use_ansi_color) {
if (vm->config.use_ansi_escape) {
vm->config.stderr_write(vm, "\033[38;2;220;100;100m");
vm->config.stderr_write(vm, msg);
vm->config.stderr_write(vm, "\033[0m");

View File

@ -185,7 +185,7 @@ struct PkConfiguration {
pkLoadScriptFn load_script_fn;
// If true stderr calls will use ansi color codes.
bool use_ansi_color;
bool use_ansi_escape;
// User defined data associated with VM.
void* user_data;

View File

@ -15,8 +15,11 @@ void registerModuleTypes(PKVM* vm);
void registerModuleTime(PKVM* vm);
void registerModuleIO(PKVM* vm);
void registerModulePath(PKVM* vm);
void registerModuleOS(PKVM* vm);
void registerModuleDummy(PKVM* vm);
// Extra libraries.
void registerModuleTerm(PKVM* vm);
void cleanupModuleTerm(PKVM* vm);
@ -27,6 +30,7 @@ void registerLibs(PKVM* vm) {
registerModuleTime(vm);
registerModuleIO(vm);
registerModulePath(vm);
registerModuleOS(vm);
registerModuleDummy(vm);
registerModuleTerm(vm);

View File

@ -15,10 +15,6 @@
#include <stdio.h>
#include <string.h>
/*****************************************************************************/
/* MODULES INTERNAL */
/*****************************************************************************/
// FIXME:
// Since this are part of the "standard" pocketlang libraries, we can include
// pocketlang internals here using the relative path, however it'll make these
@ -30,6 +26,11 @@
#include "../core/common.h"
#endif // PK_AMALGAMATED
#include <errno.h>
#define REPORT_ERRNO(fn) \
pkSetRuntimeErrorFmt(vm, "C." #fn " errno:%i - %s.", errno, strerror(errno))
/*****************************************************************************/
/* SHARED FUNCTIONS */
/*****************************************************************************/

View File

@ -230,8 +230,7 @@ DEF(_fileRead, "") {
size_t read = fread(buff, sizeof(char), count, file->fp);
if (ferror(file->fp)) {
pkSetRuntimeErrorFmt(vm, "An error occured at C.fread() - '%s'.",
strerror(errno));
REPORT_ERRNO(fread);
goto L_done;
}
@ -293,8 +292,7 @@ DEF(_fileGetLine, "") {
// End of file or error.
if (c == EOF) {
if (ferror(file->fp)) {
pkSetRuntimeErrorFmt(vm, "Error while reading line - '%s'.",
strerror(errno));
REPORT_ERRNO(fgetc);
goto L_done;
}
break; // EOF is reached.
@ -334,8 +332,7 @@ DEF(_fileWrite, "") {
clearerr(file->fp);
fwrite(text, sizeof(char), (size_t) length, file->fp);
if (ferror(file->fp)) {
pkSetRuntimeErrorFmt(vm, "An error occureed at C.fwrite() - '%s'.",
strerror(errno));
REPORT_ERRNO(fwrite);
return;
}
}
@ -351,7 +348,8 @@ DEF(_fileClose, "") {
}
if (fclose(file->fp) != 0) {
pkSetRuntimeError(vm, "fclose() failed!.");
REPORT_ERRNO(fclose);
return;
}
file->fp = NULL;
@ -384,8 +382,7 @@ DEF(_fileSeek,
}
if (fseek(file->fp, offset, whence) != 0) {
pkSetRuntimeErrorFmt(vm, "An error occureed at C.fseek() - '%s'.",
strerror(errno));
REPORT_ERRNO(fseek);
return;
}
}

224
src/libs/std_os.c Normal file
View File

@ -0,0 +1,224 @@
/*
* Copyright (c) 2020-2022 Thakee Nathees
* Copyright (c) 2021-2022 Pocketlang Contributors
* Distributed Under The MIT License
*/
#include <math.h>
#ifndef PK_AMALGAMATED
#include "libs.h"
#endif
#include <stdlib.h>
#include <sys/stat.h>
#if defined(__EMSCRIPTEN__)
#define _PKOS_WEB_
#define OS_NAME "web"
#elif defined(_WIN32) || defined(__NT__)
#define _PKOS_WIN_
#define OS_NAME "windows"
#elif defined(__APPLE__)
#define _PKOS_APPLE_
#define OS_NAME "apple" // TODO: should I use darwin?.
#elif defined(__linux__)
#define _PKOS_LINUX_
#define OS_NAME "linux"
#elif defined(__unix__)
#define _PKOS_UNIX_
#define OS_NAME "unix"
#elif defined(_POSIX_VERSION)
#define _PKOS_POSIX_
#define OS_NAME "posix"
#else
#define _PKOS_UNKNOWN_
#define OS_NAME "<?>"
#endif
#if defined(_MSC_VER) || (defined(_WIN32) && defined(__TINYC__))
#include <windows.h>
#include <direct.h>
#include <io.h>
#define getcwd _getcwd
#define chdir _chdir
#define mkdir _mkdir
#define rmdir _rmdir
#define unlink _unlink
#else
#include <dirent.h>
#include <unistd.h>
#endif
// The maximum path size that pocketlang's default import system supports
// including the null terminator. To be able to support more characters
// override the functions from the host application. Since this is very much
// platform specific we're defining a more general limit.
// See: https://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
#define MAX_PATH_LEN 4096
// Yes both 'os' and 'path' have getcwd functions.
DEF(_osGetCWD,
"os.getcwd() -> String\n"
"Returns the current working directory") {
char cwd[MAX_PATH_LEN];
if (getcwd(cwd, sizeof(cwd)) == NULL) {
// TODO: Handle error.
}
pkSetSlotString(vm, 0, cwd);
}
DEF(_osChdir,
"os.chdir(path:String)\n"
"Change the current working directory") {
const char* path;
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
if (chdir(path)) REPORT_ERRNO(chdir);
}
DEF(_osMkdir,
"os.mkdir(path:String)\n"
"Creates a directory at the path. The path should be valid.") {
const char* path;
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
#if defined(_PKOS_WIN_)
if (mkdir(path)) {
#else
if (mkdir(path, 0x1ff)) { // TODO: mode flags.
#endif
// If the directory exists (errno == EEXIST) should I skip it silently ?
REPORT_ERRNO(mkdir);
}
}
DEF(_osRmdir,
"os.rmdir(path:String)\n"
"Removes an empty directory at the path.") {
const char* path;
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
if (rmdir(path)) REPORT_ERRNO(rmdir);
}
DEF(_osUnlink,
"os.rmdir(path:String)\n"
"Removes a file at the path.") {
const char* path;
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
if (unlink(path)) REPORT_ERRNO(unlink);
}
DEF(_osModitime,
"os.moditime(path:String) -> Number\n"
"Returns the modified timestamp of the file.") {
const char* path;
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
double mtime = 0;
struct stat path_stat;
if (stat(path, &path_stat) == 0) mtime = (double) path_stat.st_mtime;
pkSetSlotNumber(vm, 0, mtime);
}
DEF(_osFileSize,
"os.filesize(path:String) -> Number\n"
"Returns the file size in bytes.") {
const char* path;
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
struct stat path_stat;
if (stat(path, &path_stat) || ((path_stat.st_mode & S_IFMT) != S_IFREG)) {
pkSetRuntimeErrorFmt(vm, "Path '%s' wasn't a file.", path);
return;
}
pkSetSlotNumber(vm, 0, path_stat.st_size);
}
DEF(_osSystem,
"os.system(cmd:String) -> Number\n"
"Execute the command in a subprocess, Returns the exit code of the child "
"process.") {
const char* cmd;
if (!pkValidateSlotString(vm, 1, &cmd, NULL)) return;
errno = 0;
int code = system(cmd);
if (errno != 0) {
REPORT_ERRNO(system);
return;
}
pkSetSlotNumber(vm, 0, (double) code);
}
DEF(_osGetenv,
"os.getenv(name:String) -> String\n"
"Returns the environment variable as String if it exists otherwise it'll "
"return null.") {
const char* name;
if (!pkValidateSlotString(vm, 1, &name, NULL)) return;
const char* value = getenv(name);
if (value == NULL) {
pkSetSlotNull(vm, 0);
return;
}
pkSetSlotString(vm, 0, value);
}
/*****************************************************************************/
/* MODULE REGISTER */
/*****************************************************************************/
void registerModuleOS(PKVM* vm) {
pkReserveSlots(vm, 2);
PkHandle* os = pkNewModule(vm, "os");
pkSetSlotHandle(vm, 0, os); // slots[0] = os
pkSetSlotString(vm, 1, OS_NAME); // slots[1] = "windows"
pkSetAttribute(vm, 0, "NAME", 1); // os.NAME = "windows"
pkModuleAddFunction(vm, os, "getcwd", _osGetCWD, 0);
pkModuleAddFunction(vm, os, "chdir", _osChdir, 1);
pkModuleAddFunction(vm, os, "mkdir", _osMkdir, 1);
pkModuleAddFunction(vm, os, "rmdir", _osRmdir, 1);
pkModuleAddFunction(vm, os, "unlink", _osUnlink, 1);
pkModuleAddFunction(vm, os, "moditime", _osModitime, 1);
pkModuleAddFunction(vm, os, "filesize", _osFileSize, 1);
pkModuleAddFunction(vm, os, "system", _osSystem, 1);
pkModuleAddFunction(vm, os, "getenv", _osGetenv, 1);
// TODO:
// - Implement makedirs which recursively mkdir().
// - Implement copyfile() and copytree()
// - Implement rmtree() which recursively rmdir() and file.
//
//pkModuleAddSource(vm, os, "import path; def makedirs(p) ... end");
pkRegisterModule(vm, os);
pkReleaseHandle(vm, os);
}
#undef OS_NAME
#undef MAX_PATH_LEN

View File

@ -17,7 +17,6 @@
#include "thirdparty/cwalk/cwalk.h" //<< AMALG_INLINE >>
#undef _CWALK_IMPL
#include <errno.h>
#include <sys/stat.h>
#ifdef _WIN32
@ -376,33 +375,6 @@ DEF(_pathListDir, "") {
}
}
// Returns the modified time of the file.
DEF(_pathMtime, "") {
const char* path;
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
double mtime = 0;
struct stat path_stat;
if (stat(path, &path_stat) == 0) mtime = (double) path_stat.st_mtime;
pkSetSlotNumber(vm, 0, mtime);
}
// Returns the file size in bytes.
DEF(_pathSize, "") {
const char* path;
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
struct stat path_stat;
if (stat(path, &path_stat) || ((path_stat.st_mode & S_IFMT) != S_IFREG)) {
pkSetRuntimeErrorFmt(vm, "Path '%s' wasn't a file.", path);
return;
}
pkSetSlotNumber(vm, 0, path_stat.st_size);
}
/*****************************************************************************/
/* MODULE REGISTER */
/*****************************************************************************/
@ -423,9 +395,10 @@ void registerModulePath(PKVM* vm) {
pkModuleAddFunction(vm, path, "isfile", _pathIsFile, 1);
pkModuleAddFunction(vm, path, "isdir", _pathIsDir, 1);
pkModuleAddFunction(vm, path, "listdir", _pathListDir, -1);
pkModuleAddFunction(vm, path, "mtime", _pathMtime, 1);
pkModuleAddFunction(vm, path, "size", _pathSize, 1);
pkRegisterModule(vm, path);
pkReleaseHandle(vm, path);
}
#undef MAX_PATH_LEN
#undef MAX_JOIN_PATHS