mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-05 12:16:53 +08:00
OS module implemented
This commit is contained in:
parent
176a0dc0c8
commit
916424da5a
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
/*****************************************************************************/
|
||||
|
@ -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
224
src/libs/std_os.c
Normal 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
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user