diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4a385ab3..e99c3503 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -132,7 +132,7 @@ jobs: steps: - name: Checkout the repository uses: actions/checkout@master - - name: Do Qemu build and test - run: | - docker run --rm --privileged multiarch/qemu-user-static --reset -p yes - docker run --rm -v .:/janet --platform linux/s390x ubuntu bash -c "apt-get -y update && apt-get -y install git build-essential && cd /janet && make -j3 && make test" + - name: Enable qemu + run: docker run --privileged --rm tonistiigi/binfmt --install s390x + - name: Build and run on emulated architecture + run: docker run --rm -v .:/janet --platform linux/s390x alpine sh -c "apk update && apk add --no-interactive git build-base && cd /janet && make -j3 && make test" diff --git a/CHANGELOG.md b/CHANGELOG.md index 11eebf84..da897093 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,12 @@ # Changelog All notable changes to this project will be documented in this file. -## ??? - Unreleased +## Unreleased - ??? +- Make `ffi/write` append to a buffer instead of insert at 0 by default. + +## 1.38.0 - 2025-03-18 +- Add `bundle/replace` +- Add CLI flags for the `bundle/` module to install and manage bundles. - Improve `?` peg special termination behavior - Add IEEE hex floats to grammar. - Add buffer peg literal support diff --git a/LICENSE b/LICENSE index 440e8c30..ceaa6a0e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2023 Calvin Rose and contributors +Copyright (c) 2025 Calvin Rose and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/Makefile b/Makefile index 8e411d3b..5e474233 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2024 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to @@ -57,6 +57,7 @@ LDFLAGS?=-rdynamic LIBJANET_LDFLAGS?=$(LD_FLAGS) RUN:=$(RUN) + COMMON_CFLAGS:=-std=c99 -Wall -Wextra -Isrc/include -Isrc/conf -fvisibility=hidden -fPIC BOOT_CFLAGS:=-DJANET_BOOTSTRAP -DJANET_BUILD=$(JANET_BUILD) -O0 $(COMMON_CFLAGS) -g BUILD_CFLAGS:=$(CFLAGS) $(COMMON_CFLAGS) @@ -94,12 +95,18 @@ endif endif # Mingw +MINGW_COMPILER= ifeq ($(findstring MINGW,$(UNAME)), MINGW) + MINGW_COMPILER=gcc CLIBS:=-lws2_32 -lpsapi -lwsock32 LDFLAGS:=-Wl,--out-implib,$(JANET_IMPORT_LIB) LIBJANET_LDFLAGS:=-Wl,--out-implib,$(JANET_LIBRARY_IMPORT_LIB) JANET_TARGET:=$(JANET_TARGET).exe JANET_BOOT:=$(JANET_BOOT).exe + COMPILER_VERSION:=$(shell $(CC) --version) + ifeq ($(findstring clang,$(COMPILER_VERSION)), clang) + MINGW_COMPILER=clang + endif endif @@ -209,9 +216,14 @@ build/%.bin.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS) Makefile ######################## ifeq ($(UNAME), Darwin) -SONAME=libjanet.1.37.dylib +SONAME=libjanet.1.38.dylib else -SONAME=libjanet.so.1.37 +SONAME=libjanet.so.1.38 +endif + +ifeq ($(MINGW_COMPILER), clang) + SONAME= + SONAME_SETTER= endif build/c/shell.c: src/mainclient/shell.c diff --git a/meson.build b/meson.build index 137d7809..afd84e7a 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -# Copyright (c) 2024 Calvin Rose and contributors +# Copyright (c) 2025 Calvin Rose and contributors # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to @@ -20,7 +20,7 @@ project('janet', 'c', default_options : ['c_std=c99', 'build.c_std=c99', 'b_lundef=false', 'default_library=both'], - version : '1.37.1') + version : '1.38.0') # Global settings janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet') @@ -39,6 +39,15 @@ native_thread_dep = dependency('threads', native : true) # Deps m_dep = cc.find_library('m', required : false) dl_dep = cc.find_library('dl', required : false) + +# for MINGW/MSYS2 +native_ws2_dep = native_cc.find_library('ws2_32', required: false) +native_psapi_dep = native_cc.find_library('psapi', required: false) +native_wsock_dep = native_cc.find_library('wsock32', required: false) +ws2_dep = cc.find_library('ws2_32', required: false) +psapi_dep = cc.find_library('psapi', required: false) +wsock_dep = cc.find_library('wsock32', required: false) + android_spawn_dep = cc.find_library('android-spawn', required : false) thread_dep = dependency('threads') @@ -176,8 +185,8 @@ mainclient_src = [ 'src/mainclient/shell.c' ] -janet_dependencies = [m_dep, dl_dep, android_spawn_dep] -janet_native_dependencies = [native_m_dep, native_dl_dep, native_android_spawn_dep] +janet_dependencies = [m_dep, dl_dep, android_spawn_dep, ws2_dep, psapi_dep, wsock_dep] +janet_native_dependencies = [native_m_dep, native_dl_dep, native_android_spawn_dep, native_ws2_dep, native_psapi_dep, native_wsock_dep] if not get_option('single_threaded') janet_dependencies += thread_dep janet_native_dependencies += native_thread_dep diff --git a/src/boot/array_test.c b/src/boot/array_test.c index 39022a3e..e1b545cc 100644 --- a/src/boot/array_test.c +++ b/src/boot/array_test.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/boot/boot.c b/src/boot/boot.c index 0ccc8ddb..df1b180f 100644 --- a/src/boot/boot.c +++ b/src/boot/boot.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/boot/boot.janet b/src/boot/boot.janet index 75f8bf2f..c3e292ec 100644 --- a/src/boot/boot.janet +++ b/src/boot/boot.janet @@ -1,5 +1,5 @@ # The core janet library -# Copyright 2024 © Calvin Rose +# Copyright 2025 © Calvin Rose ### ### @@ -3984,7 +3984,7 @@ (def- safe-forms {'defn true 'varfn true 'defn- true 'defmacro true 'defmacro- true 'def is-safe-def 'var is-safe-def 'def- is-safe-def 'var- is-safe-def - 'defglobal is-safe-def 'varglobal is-safe-def}) + 'defglobal is-safe-def 'varglobal is-safe-def 'defdyn true}) (def- importers {'import true 'import* true 'dofile true 'require true}) (defn- use-2 [evaluator args] @@ -4118,7 +4118,11 @@ [manifest] (def bn (get manifest :name)) (def manifest-name (get-manifest-filename bn)) - (spit manifest-name (string/format "%j\n" manifest))) + (def b @"") + (buffer/format b "%j" manifest) # make sure it is valid jdn + (buffer/clear b) + (buffer/format b "%.99m\n" manifest) + (spit manifest-name b)) (defn bundle/manifest "Get the manifest for a give installed bundle" @@ -4137,7 +4141,7 @@ (os/cd workdir) ([_] (print "cannot enter source directory " workdir " for bundle " bundle-name))) (defer (os/cd dir) - (def new-env (make-env (curenv))) + (def new-env (make-env)) (put new-env *module-cache* @{}) (put new-env *module-loading* @{}) (put new-env *module-make-env* (fn make-bundle-env [&] (make-env new-env))) @@ -4152,7 +4156,6 @@ [module bundle-name hook & args] (def hookf (module/value module (symbol hook))) (unless hookf (break)) - (def manifest (bundle/manifest bundle-name)) (def dir (os/cwd)) (os/cd (get module :workdir ".")) (defer (os/cd dir) @@ -4271,8 +4274,8 @@ (assertf (not (string/check-set "\\/" bundle-name)) "bundle name %v cannot contain path separators" bundle-name) (assert (next bundle-name) "cannot use empty bundle-name") - (assert (not (fexists (get-manifest-filename bundle-name))) - "bundle is already installed") + (assertf (not (fexists (get-manifest-filename bundle-name))) + "bundle %v is already installed" bundle-name) # Setup installed paths (prime-bundle-paths) (os/mkdir (bundle-dir bundle-name)) @@ -4345,14 +4348,15 @@ (spit install-hook b)) dest-dir) - (defn bundle/reinstall - "Reinstall an existing bundle from the local source code." - [bundle-name &keys new-config] + (defn bundle/replace + "Reinstall an existing bundle from a new directory. Similar to bundle/reinstall, + but installs the replacement bundle from any directory. This is necesarry to replace a package without + breaking any dependencies." + [bundle-name path &keys new-config] (def manifest (bundle/manifest bundle-name)) - (def path (get manifest :local-source)) (def config (get manifest :config @{})) (def s (sep)) - (assert (= :directory (os/stat path :mode)) "local source not available") + (assertf (= :directory (os/stat path :mode)) "local source %v not available" path) (def backup-dir (string (dyn *syspath*) s bundle-name ".backup")) (rmrf backup-dir) (def backup-bundle-source (bundle/pack bundle-name backup-dir true)) @@ -4365,6 +4369,14 @@ (rmrf backup-bundle-source) bundle-name) + (defn bundle/reinstall + "Reinstall an existing bundle from the local source code." + [bundle-name &keys new-config] + (def manifest (bundle/manifest bundle-name)) + (def path (get manifest :local-source)) + (bundle/replace bundle-name path ;(kvs new-config)) + bundle-name) + (defn bundle/add-directory "Add a directory during the install process relative to `(dyn *syspath*)`" [manifest dest &opt chmod-mode] @@ -4431,10 +4443,11 @@ `Shorthand for adding scripts during an install. Scripts will be installed to (string (dyn *syspath*) "/bin") by default and will be set to be executable.` [manifest src &opt dest chmod-mode] - (default dest (last (string/split "/" src))) + (def s (sep)) + (default dest (last (string/split s src))) (default chmod-mode 8r755) - (os/mkdir (string (dyn *syspath*) (sep) "bin")) - (bundle/add-file manifest src (string "bin" (sep) dest) chmod-mode)) + (os/mkdir (string (dyn *syspath*) s "bin")) + (bundle/add-file manifest src (string "bin" s dest) chmod-mode)) (defn bundle/update-all "Reinstall all bundles" @@ -4497,6 +4510,12 @@ "-nocolor" "n" "-color" "N" "-library" "l" + "-install" "b" + "-reinstall" "B" + "-uninstall" "u" + "-update-all" "U" + "-list" "L" + "-prune" "P" "-lint-warn" "w" "-lint-error" "x"}) @@ -4507,7 +4526,7 @@ (setdyn *args* args) - (var should-repl false) + (var should-repl nil) (var no-file true) (var quiet false) (var raw-stdin false) @@ -4562,6 +4581,12 @@ --library (-l) lib : Use a module before processing more arguments --lint-warn (-w) level : Set the lint warning level - default is "normal" --lint-error (-x) level : Set the lint error level - default is "none" + --install (-b) dirpath : Install a bundle from a directory + --reinstall (-B) name : Reinstall a bundle by bundle name + --uninstall (-u) name : Uninstall a bundle by bundle name + --update-all (-U) : Reinstall all installed bundles + --prune (-P) : Uninstalled all bundles that are orphaned + --list (-L) : List all installed bundles -- : Stop handling options ```) (os/exit 0) @@ -4606,6 +4631,30 @@ ((thunk) ;subargs) (error (get thunk :error))) math/inf) + "b" + (compif (dyn 'bundle/install) + (fn [i &] (bundle/install (in args (+ i 1))) (set no-file false) (if (= nil should-repl) (set should-repl false)) 2) + (fn [i &] (eprint "--install not supported with reduced os") 2)) + "B" + (compif (dyn 'bundle/reinstall) + (fn [i &] (bundle/reinstall (in args (+ i 1))) (set no-file false) (if (= nil should-repl) (set should-repl false)) 2) + (fn [i &] (eprint "--reinstall not supported with reduced os") 2)) + "u" + (compif (dyn 'bundle/uninstall) + (fn [i &] (bundle/uninstall (in args (+ i 1))) (set no-file false) (if (= nil should-repl) (set should-repl false)) 2) + (fn [i &] (eprint "--uninstall not supported with reduced os") 2)) + "P" + (compif (dyn 'bundle/prune) + (fn [i &] (bundle/prune) (set no-file false) (if (= nil should-repl) (set should-repl false)) 1) + (fn [i &] (eprint "--prune not supported with reduced os") 1)) + "U" + (compif (dyn 'bundle/update-all) + (fn [i &] (bundle/update-all) (set no-file false) (if (= nil should-repl) (set should-repl false)) 1) + (fn [i &] (eprint "--update-all not supported with reduced os") 1)) + "L" + (compif (dyn 'bundle/list) + (fn [i &] (each l (bundle/list) (print l)) (set no-file false) (if (= nil should-repl) (set should-repl false)) 1) + (fn [i &] (eprint "--list not supported with reduced os") 1)) "d" (fn [&] (set debug-flag true) 1) "w" (fn [i &] (set warn-level (get-lint-level i)) 2) "x" (fn [i &] (set error-level (get-lint-level i)) 2) diff --git a/src/boot/buffer_test.c b/src/boot/buffer_test.c index f53be7b8..0698e3c9 100644 --- a/src/boot/buffer_test.c +++ b/src/boot/buffer_test.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/boot/number_test.c b/src/boot/number_test.c index 4c469ba8..15bd085f 100644 --- a/src/boot/number_test.c +++ b/src/boot/number_test.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/boot/system_test.c b/src/boot/system_test.c index 9e1ced24..4fcd4c66 100644 --- a/src/boot/system_test.c +++ b/src/boot/system_test.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/boot/table_test.c b/src/boot/table_test.c index 121a07e1..1b07a577 100644 --- a/src/boot/table_test.c +++ b/src/boot/table_test.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/conf/janetconf.h b/src/conf/janetconf.h index 7fc77bc0..35f1b58d 100644 --- a/src/conf/janetconf.h +++ b/src/conf/janetconf.h @@ -4,10 +4,10 @@ #define JANETCONF_H #define JANET_VERSION_MAJOR 1 -#define JANET_VERSION_MINOR 37 -#define JANET_VERSION_PATCH 1 +#define JANET_VERSION_MINOR 38 +#define JANET_VERSION_PATCH 0 #define JANET_VERSION_EXTRA "" -#define JANET_VERSION "1.37.1" +#define JANET_VERSION "1.38.0" /* #define JANET_BUILD "local" */ diff --git a/src/core/abstract.c b/src/core/abstract.c index 3a97e9b8..dab8536d 100644 --- a/src/core/abstract.c +++ b/src/core/abstract.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/array.c b/src/core/array.c index e11ae52f..bda15159 100644 --- a/src/core/array.c +++ b/src/core/array.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/asm.c b/src/core/asm.c index 7ec4292f..4f54623a 100644 --- a/src/core/asm.c +++ b/src/core/asm.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/buffer.c b/src/core/buffer.c index d2e89f8c..06e3f9f9 100644 --- a/src/core/buffer.c +++ b/src/core/buffer.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/bytecode.c b/src/core/bytecode.c index 121811e7..7f1acdac 100644 --- a/src/core/bytecode.c +++ b/src/core/bytecode.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/capi.c b/src/core/capi.c index af6ea582..5a6a2e68 100644 --- a/src/core/capi.c +++ b/src/core/capi.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/cfuns.c b/src/core/cfuns.c index b9c8a95b..960bd502 100644 --- a/src/core/cfuns.c +++ b/src/core/cfuns.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/compile.c b/src/core/compile.c index 3ceb04fb..ea81a660 100644 --- a/src/core/compile.c +++ b/src/core/compile.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/compile.h b/src/core/compile.h index b5111f4a..197f034c 100644 --- a/src/core/compile.h +++ b/src/core/compile.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/corelib.c b/src/core/corelib.c index cf1d9ab5..52d445f3 100644 --- a/src/core/corelib.c +++ b/src/core/corelib.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/debug.c b/src/core/debug.c index 2cbd6aa3..6e03f78d 100644 --- a/src/core/debug.c +++ b/src/core/debug.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/emit.c b/src/core/emit.c index 59d447a4..47127800 100644 --- a/src/core/emit.c +++ b/src/core/emit.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/emit.h b/src/core/emit.h index 2fdf0d47..64a6a268 100644 --- a/src/core/emit.h +++ b/src/core/emit.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/ev.c b/src/core/ev.c index e51fee80..c6e99d6b 100644 --- a/src/core/ev.c +++ b/src/core/ev.c @@ -112,6 +112,13 @@ typedef struct { JanetHandle write_pipe; } JanetEVThreadInit; +/* Structure used to initialize threads that run timeouts */ +typedef struct { + double sec; + JanetVM *vm; + JanetFiber *fiber; +} JanetThreadedTimeout; + #define JANET_MAX_Q_CAPACITY 0x7FFFFFF static void janet_q_init(JanetQueue *q) { @@ -623,6 +630,7 @@ void janet_addtimeout(double sec) { to.curr_fiber = NULL; to.sched_id = fiber->sched_id; to.is_error = 1; + to.has_worker = 0; add_timeout(to); } @@ -635,9 +643,54 @@ void janet_addtimeout_nil(double sec) { to.curr_fiber = NULL; to.sched_id = fiber->sched_id; to.is_error = 0; + to.has_worker = 0; add_timeout(to); } +#ifdef JANET_WINDOWS +static VOID CALLBACK janet_timeout_stop(ULONG_PTR ptr) { + UNREFERENCED_PARAMETER(ptr); + ExitThread(0); +} +#endif + +static void janet_timeout_cb(JanetEVGenericMessage msg) { + (void) msg; + janet_interpreter_interrupt_handled(&janet_vm); +} + +#ifdef JANET_WINDOWS +static DWORD WINAPI janet_timeout_body(LPVOID ptr) { + JanetThreadedTimeout tto = *(JanetThreadedTimeout *)ptr; + janet_free(ptr); + SleepEx((DWORD)(tto.sec * 1000), TRUE); + if (janet_fiber_can_resume(tto.fiber)) { + janet_interpreter_interrupt(tto.vm); + JanetEVGenericMessage msg = {0}; + janet_ev_post_event(tto.vm, janet_timeout_cb, msg); + } + return 0; +} +#else +static void *janet_timeout_body(void *ptr) { + JanetThreadedTimeout tto = *(JanetThreadedTimeout *)ptr; + janet_free(ptr); + struct timespec ts; + ts.tv_sec = (time_t) tto.sec; + ts.tv_nsec = (tto.sec <= UINT32_MAX) + ? (long)((tto.sec - ((uint32_t)tto.sec)) * 1000000000) + : 0; + nanosleep(&ts, &ts); + if (janet_fiber_can_resume(tto.fiber)) { + janet_interpreter_interrupt(tto.vm); + JanetEVGenericMessage msg = {0}; + janet_ev_post_event(tto.vm, janet_timeout_cb, msg); + } + return NULL; +} +#endif + + void janet_ev_inc_refcount(void) { janet_atomic_inc(&janet_vm.listener_count); } @@ -1431,6 +1484,17 @@ JanetFiber *janet_loop1(void) { while ((has_timeout = peek_timeout(&to))) { if (to.curr_fiber != NULL) { if (!janet_fiber_can_resume(to.curr_fiber)) { + if (to.has_worker) { +#ifdef JANET_WINDOWS + QueueUserAPC(janet_timeout_stop, to.worker, 0); + WaitForSingleObject(to.worker, INFINITE); + CloseHandle(to.worker); +#else + pthread_cancel(to.worker); + void *res; + pthread_join(to.worker, &res); +#endif + } janet_table_remove(&janet_vm.active_tasks, janet_wrap_fiber(to.curr_fiber)); pop_timeout(0); continue; @@ -3103,26 +3167,53 @@ JANET_CORE_FN(cfun_ev_sleep, } JANET_CORE_FN(cfun_ev_deadline, - "(ev/deadline sec &opt tocancel tocheck)", - "Schedules the event loop to try to cancel the `tocancel` " - "task as with `ev/cancel`. After `sec` seconds, the event " - "loop will attempt cancellation of `tocancel` if the " - "`tocheck` fiber is resumable. `sec` is a number that can " - "have a fractional part. `tocancel` defaults to " - "`(fiber/root)`, but if specified, must be a task (root " - "fiber). `tocheck` defaults to `(fiber/current)`, but if " - "specified, should be a fiber. Returns `tocancel` " - "immediately.") { - janet_arity(argc, 1, 3); + "(ev/deadline sec &opt tocancel tocheck intr?)", + "Schedules the event loop to try to cancel the `tocancel` task as with `ev/cancel`. " + "After `sec` seconds, the event loop will attempt cancellation of `tocancel` if the " + "`tocheck` fiber is resumable. `sec` is a number that can have a fractional part. " + "`tocancel` defaults to `(fiber/root)`, but if specified, must be a task (root " + "fiber). `tocheck` defaults to `(fiber/current)`, but if specified, must be a fiber. " + "Returns `tocancel` immediately. If `interrupt?` is set to true, will create a " + "background thread to try to interrupt the VM if the timeout expires.") { + janet_arity(argc, 1, 4); double sec = janet_getnumber(argv, 0); + sec = (sec < 0) ? 0 : sec; JanetFiber *tocancel = janet_optfiber(argv, argc, 1, janet_vm.root_fiber); JanetFiber *tocheck = janet_optfiber(argv, argc, 2, janet_vm.fiber); + int use_interrupt = janet_optboolean(argv, argc, 3, 0); JanetTimeout to; to.when = ts_delta(ts_now(), sec); to.fiber = tocancel; to.curr_fiber = tocheck; to.is_error = 0; to.sched_id = to.fiber->sched_id; + if (use_interrupt) { + JanetThreadedTimeout *tto = janet_malloc(sizeof(JanetThreadedTimeout)); + if (NULL == tto) { + JANET_OUT_OF_MEMORY; + } + tto->sec = sec; + tto->vm = &janet_vm; + tto->fiber = tocheck; +#ifdef JANET_WINDOWS + HANDLE worker = CreateThread(NULL, 0, janet_timeout_body, tto, 0, NULL); + if (NULL == worker) { + janet_free(tto); + janet_panic("failed to create thread"); + } +#else + pthread_t worker; + int err = pthread_create(&worker, NULL, janet_timeout_body, tto); + if (err) { + janet_free(tto); + janet_panicf("%s", janet_strerror(err)); + } +#endif + to.has_worker = 1; + to.worker = worker; + } else { + to.has_worker = 0; + } add_timeout(to); return janet_wrap_fiber(tocancel); } diff --git a/src/core/features.h b/src/core/features.h index 591c2bad..d799880a 100644 --- a/src/core/features.h +++ b/src/core/features.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/ffi.c b/src/core/ffi.c index c95642ad..f14ff2f7 100644 --- a/src/core/ffi.c +++ b/src/core/ffi.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -1686,7 +1686,7 @@ JANET_CORE_FN(cfun_ffi_buffer_write, JanetFFIType type = decode_ffi_type(argv[0]); uint32_t el_size = (uint32_t) type_size(type); JanetBuffer *buffer = janet_optbuffer(argv, argc, 2, el_size); - int32_t index = janet_optnat(argv, argc, 3, 0); + int32_t index = janet_optnat(argv, argc, 3, buffer->count); int32_t old_count = buffer->count; if (index > old_count) janet_panic("index out of bounds"); buffer->count = index; diff --git a/src/core/fiber.c b/src/core/fiber.c index c1a0b2f6..72d8f2de 100644 --- a/src/core/fiber.c +++ b/src/core/fiber.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/fiber.h b/src/core/fiber.h index a83610e4..8626e89c 100644 --- a/src/core/fiber.h +++ b/src/core/fiber.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/filewatch.c b/src/core/filewatch.c index f515feb0..85f1d266 100644 --- a/src/core/filewatch.c +++ b/src/core/filewatch.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/gc.c b/src/core/gc.c index 942cd272..038c9106 100644 --- a/src/core/gc.c +++ b/src/core/gc.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/gc.h b/src/core/gc.h index c7502b61..37318eee 100644 --- a/src/core/gc.h +++ b/src/core/gc.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/inttypes.c b/src/core/inttypes.c index 855793d7..db0d2b28 100644 --- a/src/core/inttypes.c +++ b/src/core/inttypes.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose & contributors +* Copyright (c) 2025 Calvin Rose & contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/io.c b/src/core/io.c index 0f6703e9..4d45caba 100644 --- a/src/core/io.c +++ b/src/core/io.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/marsh.c b/src/core/marsh.c index 58433095..13b3344b 100644 --- a/src/core/marsh.c +++ b/src/core/marsh.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/math.c b/src/core/math.c index f27b6ffd..400ed7e4 100644 --- a/src/core/math.c +++ b/src/core/math.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/net.c b/src/core/net.c index 21f4bdb1..e9254027 100644 --- a/src/core/net.c +++ b/src/core/net.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose and contributors. +* Copyright (c) 2025 Calvin Rose and contributors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/os.c b/src/core/os.c index c814ef3a..fe1184e9 100644 --- a/src/core/os.c +++ b/src/core/os.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose and contributors. +* Copyright (c) 2025 Calvin Rose and contributors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -541,11 +541,12 @@ static void janet_proc_wait_cb(JanetEVGenericMessage args) { proc->flags &= ~JANET_PROC_WAITING; janet_gcunroot(janet_wrap_abstract(proc)); janet_gcunroot(janet_wrap_fiber(args.fiber)); - if ((status != 0) && (proc->flags & JANET_PROC_ERROR_NONZERO)) { - JanetString s = janet_formatc("command failed with non-zero exit code %d", status); - janet_cancel(args.fiber, janet_wrap_string(s)); - } else { - if (janet_fiber_can_resume(args.fiber)) { + uint32_t sched_id = (uint32_t) args.argi; + if (janet_fiber_can_resume(args.fiber) && args.fiber->sched_id == sched_id) { + if ((status != 0) && (proc->flags & JANET_PROC_ERROR_NONZERO)) { + JanetString s = janet_formatc("command failed with non-zero exit code %d", status); + janet_cancel(args.fiber, janet_wrap_string(s)); + } else { janet_schedule(args.fiber, janet_wrap_integer(status)); } } @@ -603,6 +604,7 @@ os_proc_wait_impl(JanetProc *proc) { memset(&targs, 0, sizeof(targs)); targs.argp = proc; targs.fiber = janet_root_fiber(); + targs.argi = (uint32_t) targs.fiber->sched_id; janet_gcroot(janet_wrap_abstract(proc)); janet_gcroot(janet_wrap_fiber(targs.fiber)); janet_ev_threaded_call(janet_proc_wait_subr, targs, janet_proc_wait_cb); @@ -629,16 +631,15 @@ os_proc_wait_impl(JanetProc *proc) { JANET_CORE_FN(os_proc_wait, "(os/proc-wait proc)", - "Suspend the current fiber until the subprocess completes. Returns the subprocess return code. " - "os/proc-wait cannot be called twice on the same process. If `ev/with-deadline` cancels `os/proc-wait` " - "with an error or os/proc-wait is cancelled with any error caused by anything else, os/proc-wait still " - "finishes in the background. Only after os/proc-wait finishes, a process is cleaned up by the operating " - "system. Thus, a process becomes a zombie process if os/proc-wait is not called.") { + "Suspend the current fiber until the subprocess `proc` completes. Once `proc` " + "completes, return the exit code of `proc`. If called more than once on the same " + "core/process value, will raise an error. When creating subprocesses using " + "`os/spawn`, this function should be called on the returned value to avoid zombie " + "processes.") { janet_fixarity(argc, 1); JanetProc *proc = janet_getabstract(argv, 0, &ProcAT); #ifdef JANET_EV os_proc_wait_impl(proc); - return janet_wrap_nil(); #else return os_proc_wait_impl(proc); #endif @@ -743,12 +744,13 @@ static int get_signal_kw(const Janet *argv, int32_t n) { JANET_CORE_FN(os_proc_kill, "(os/proc-kill proc &opt wait signal)", - "Kill a subprocess by sending SIGKILL to it on posix systems, or by closing the process " - "handle on windows. If os/proc-wait already finished for proc, os/proc-kill raises an error. After " - "sending signal to proc, if `wait` is truthy, will wait for the process to finish and return the exit " - "code by calling os/proc-wait. Otherwise, returns `proc`. If signal is specified, send it instead. " - "Signal keywords are named after their C counterparts but in lowercase with the leading `SIG` stripped. " - "Signals are ignored on windows.") { + "Kill the subprocess `proc` by sending SIGKILL to it on POSIX systems, or by closing " + "the process handle on Windows. If `proc` has already completed, raise an error. If " + "`wait` is truthy, will wait for `proc` to complete and return the exit code (this " + "will raise an error if `proc` is being waited for). Otherwise, return `proc`. If " + "`signal` is provided, send it instead of SIGKILL. Signal keywords are named after " + "their C counterparts but in lowercase with the leading SIG stripped. `signal` is " + "ignored on Windows.") { janet_arity(argc, 1, 3); JanetProc *proc = janet_getabstract(argv, 0, &ProcAT); if (proc->flags & JANET_PROC_WAITED) { @@ -776,7 +778,6 @@ JANET_CORE_FN(os_proc_kill, if (argc > 1 && janet_truthy(argv[1])) { #ifdef JANET_EV os_proc_wait_impl(proc); - return janet_wrap_nil(); #else return os_proc_wait_impl(proc); #endif @@ -787,9 +788,9 @@ JANET_CORE_FN(os_proc_kill, JANET_CORE_FN(os_proc_close, "(os/proc-close proc)", - "Close pipes created by `os/spawn` if they have not been closed. Then, if os/proc-wait was not already " - "called on proc, os/proc-wait is called on it, and it returns the exit code returned by os/proc-wait. " - "Otherwise, returns nil.") { + "Close pipes created for subprocess `proc` by `os/spawn` if they have not been " + "closed. Then, if `proc` is not being waited for, wait. If this function waits, when " + "`proc` completes, return the exit code of `proc`. Otherwise, return nil.") { janet_fixarity(argc, 1); JanetProc *proc = janet_getabstract(argv, 0, &ProcAT); #ifdef JANET_EV @@ -807,7 +808,6 @@ JANET_CORE_FN(os_proc_close, } #ifdef JANET_EV os_proc_wait_impl(proc); - return janet_wrap_nil(); #else return os_proc_wait_impl(proc); #endif @@ -1268,9 +1268,6 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, JanetExecuteMode mode) { /* exec mode */ if (mode == JANET_EXECUTE_EXEC) { -#ifdef JANET_WINDOWS - janet_panic("not supported on windows"); -#else int status; if (!use_environ) { environ = envp; @@ -1283,7 +1280,6 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, JanetExecuteMode mode) { } } while (status == -1 && errno == EINTR); janet_panicf("%p: %s", cargv[0], janet_strerror(errno ? errno : ENOENT)); -#endif } /* Use posix_spawn to spawn new process */ @@ -1384,45 +1380,56 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, JanetExecuteMode mode) { JANET_CORE_FN(os_execute, "(os/execute args &opt flags env)", - "Execute a program on the system and pass it string arguments. `flags` " - "is a keyword that modifies how the program will execute.\n" - "* :e - enables passing an environment to the program. Without :e, the " + "Execute a program on the system and return the exit code. `args` is an array/tuple " + "of strings. The first string is the name of the program and the remainder are " + "arguments passed to the program. `flags` is a keyword made from the following " + "characters that modifies how the program executes:\n" + "* :e - enables passing an environment to the program. Without 'e', the " "current environment is inherited.\n" - "* :p - allows searching the current PATH for the binary to execute. " - "Without this flag, binaries must use absolute paths.\n" - "* :x - raise error if exit code is non-zero.\n" - "* :d - Don't try and terminate the process on garbage collection (allow spawning zombies).\n" - "`env` is a table or struct mapping environment variables to values. It can also " - "contain the keys :in, :out, and :err, which allow redirecting stdio in the subprocess. " - ":in, :out, and :err should be core/file values or core/stream values. core/file values and core/stream " - "values passed to :in, :out, and :err should be closed manually because os/execute doesn't close them. " - "Returns the exit code of the program.") { + "* :p - allows searching the current PATH for the program to execute. " + "Without this flag, the first element of `args` must be an absolute path.\n" + "* :x - raises error if exit code is non-zero.\n" + "* :d - prevents the garbage collector terminating the program (if still running) " + "and calling the equivalent of `os/proc-wait` (allows zombie processes).\n" + "`env` is a table/struct mapping environment variables to values. It can also " + "contain the keys :in, :out, and :err, which allow redirecting stdio in the " + "subprocess. :in, :out, and :err should be core/file or core/stream values. " + "If core/stream values are used, the caller is responsible for ensuring pipes do not " + "cause the program to block and deadlock.") { return os_execute_impl(argc, argv, JANET_EXECUTE_EXECUTE); } JANET_CORE_FN(os_spawn, "(os/spawn args &opt flags env)", - "Execute a program on the system and return a handle to the process. Otherwise, takes the " - "same arguments as `os/execute`. Does not wait for the process. For each of the :in, :out, and :err keys " - "of the `env` argument, one can also pass in the keyword `:pipe` to get streams for standard IO of the " - "subprocess that can be read from and written to. The returned value `proc` has the fields :in, :out, " - ":err, and the additional field :pid on unix-like platforms. `(os/proc-wait proc)` must be called to " - "rejoin the subprocess. After `(os/proc-wait proc)` finishes, proc gains a new field, :return-code. " - "If :x flag is passed to os/spawn, non-zero exit code will cause os/proc-wait to raise an error. " - "If pipe streams created with :pipe keyword are not closed in time, janet can run out of file " - "descriptors. They can be closed individually, or `os/proc-close` can close all pipe streams on proc. " - "If pipe streams aren't read before `os/proc-wait` finishes, then pipe buffers become full, and the " - "process cannot finish because the process cannot print more on pipe buffers which are already full. " - "If the process cannot finish, os/proc-wait cannot finish, either.") { + "Execute a program on the system and return a core/process value representing the " + "spawned subprocess. Takes the same arguments as `os/execute` but does not wait for " + "the subprocess to complete. Unlike `os/execute`, the value `:pipe` can be used for " + ":in, :out and :err keys in `env`. If used, the returned core/process will have a " + "writable stream in the :in field and readable streams in the :out and :err fields. " + "On non-Windows systems, the subprocess PID will be in the :pid field. The caller is " + "responsible for waiting on the process (e.g. by calling `os/proc-wait` on the " + "returned core/process value) to avoid creating zombie process. After the subprocess " + "completes, the exit value is in the :return-code field. If `flags` includes 'x', a " + "non-zero exit code will cause a waiting fiber to raise an error. The use of " + "`:pipe` may fail if there are too many active file descriptors. The caller is " + "responsible for closing pipes created by `:pipe` (either individually or using " + "`os/proc-close`). Similar to `os/execute`, the caller is responsible for ensuring " + "pipes do not cause the program to block and deadlock.") { return os_execute_impl(argc, argv, JANET_EXECUTE_SPAWN); } JANET_CORE_FN(os_posix_exec, "(os/posix-exec args &opt flags env)", "Use the execvpe or execve system calls to replace the current process with an interface similar to os/execute. " - "However, instead of creating a subprocess, the current process is replaced. Is not supported on windows, and " + "However, instead of creating a subprocess, the current process is replaced. Is not supported on Windows, and " "does not allow redirection of stdio.") { +#ifdef JANET_WINDOWS + (void) argc; + (void) argv; + janet_panic("not supported on Windows"); +#else return os_execute_impl(argc, argv, JANET_EXECUTE_EXEC); +#endif } JANET_CORE_FN(os_posix_fork, @@ -1433,7 +1440,7 @@ JANET_CORE_FN(os_posix_fork, janet_fixarity(argc, 0); (void) argv; #ifdef JANET_WINDOWS - janet_panic("not supported"); + janet_panic("not supported on Windows"); #else pid_t result; do { @@ -1880,7 +1887,6 @@ JANET_CORE_FN(os_mktime, /* utc time */ #ifdef JANET_NO_UTC_MKTIME janet_panic("os/mktime UTC not supported on this platform"); - return janet_wrap_nil(); #else t = timegm(&t_info); #endif @@ -1947,8 +1953,7 @@ JANET_CORE_FN(os_link, #ifdef JANET_WINDOWS (void) argc; (void) argv; - janet_panic("os/link not supported on Windows"); - return janet_wrap_nil(); + janet_panic("not supported on Windows"); #else const char *oldpath = janet_getcstring(argv, 0); const char *newpath = janet_getcstring(argv, 1); @@ -1966,8 +1971,7 @@ JANET_CORE_FN(os_symlink, #ifdef JANET_WINDOWS (void) argc; (void) argv; - janet_panic("os/symlink not supported on Windows"); - return janet_wrap_nil(); + janet_panic("not supported on Windows"); #else const char *oldpath = janet_getcstring(argv, 0); const char *newpath = janet_getcstring(argv, 1); @@ -2069,8 +2073,7 @@ JANET_CORE_FN(os_readlink, #ifdef JANET_WINDOWS (void) argc; (void) argv; - janet_panic("os/readlink not supported on Windows"); - return janet_wrap_nil(); + janet_panic("not supported on Windows"); #else static char buffer[PATH_MAX]; const char *path = janet_getcstring(argv, 0); @@ -2326,7 +2329,6 @@ static Janet os_stat_or_lstat(int do_lstat, int32_t argc, Janet *argv) { return sg->fn(&st); } janet_panicf("unexpected keyword %v", janet_wrap_keyword(key)); - return janet_wrap_nil(); } } diff --git a/src/core/parse.c b/src/core/parse.c index c9177316..5b5ffff8 100644 --- a/src/core/parse.c +++ b/src/core/parse.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/pp.c b/src/core/pp.c index 74022b8f..0c9e81ce 100644 --- a/src/core/pp.c +++ b/src/core/pp.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/regalloc.c b/src/core/regalloc.c index 7bc1d8ca..ef8768eb 100644 --- a/src/core/regalloc.c +++ b/src/core/regalloc.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/regalloc.h b/src/core/regalloc.h index bd1e76e6..ca6c833e 100644 --- a/src/core/regalloc.h +++ b/src/core/regalloc.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/run.c b/src/core/run.c index 9942f07b..0be7f6db 100644 --- a/src/core/run.c +++ b/src/core/run.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/specials.c b/src/core/specials.c index b9d79f68..1a17257e 100644 --- a/src/core/specials.c +++ b/src/core/specials.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/state.c b/src/core/state.c index 003dd796..3d84dcd1 100644 --- a/src/core/state.c +++ b/src/core/state.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/state.h b/src/core/state.h index d121f559..918c1ade 100644 --- a/src/core/state.h +++ b/src/core/state.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -27,7 +27,9 @@ #include #ifdef JANET_EV -#ifndef JANET_WINDOWS +#ifdef JANET_WINDOWS +#include +#else #include #endif #endif @@ -53,13 +55,21 @@ typedef struct { void *data; } JanetQueue; +#ifdef JANET_EV typedef struct { JanetTimestamp when; JanetFiber *fiber; JanetFiber *curr_fiber; uint32_t sched_id; int is_error; + int has_worker; +#ifdef JANET_WINDOWS + HANDLE worker; +#else + pthread_t worker; +#endif } JanetTimeout; +#endif /* Registry table for C functions - contains metadata that can * be looked up by cfunction pointer. All strings here are pointing to diff --git a/src/core/string.c b/src/core/string.c index 6a67482c..24181cbc 100644 --- a/src/core/string.c +++ b/src/core/string.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/strtod.c b/src/core/strtod.c index 33857027..3873a6fd 100644 --- a/src/core/strtod.c +++ b/src/core/strtod.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/struct.c b/src/core/struct.c index 2e4be627..1b1cad7b 100644 --- a/src/core/struct.c +++ b/src/core/struct.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/symcache.c b/src/core/symcache.c index 4d1af72c..68ddf8bf 100644 --- a/src/core/symcache.c +++ b/src/core/symcache.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/symcache.h b/src/core/symcache.h index ea55627e..5e3fbbe0 100644 --- a/src/core/symcache.h +++ b/src/core/symcache.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/table.c b/src/core/table.c index 229d8fa3..910ceba2 100644 --- a/src/core/table.c +++ b/src/core/table.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/tuple.c b/src/core/tuple.c index 97aa483f..7c004751 100644 --- a/src/core/tuple.c +++ b/src/core/tuple.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/util.c b/src/core/util.c index 9ad64c56..db65deb2 100644 --- a/src/core/util.c +++ b/src/core/util.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/util.h b/src/core/util.h index a2da921a..4e16f5e0 100644 --- a/src/core/util.h +++ b/src/core/util.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -205,9 +205,9 @@ int janet_make_pipe(JanetHandle handles[2], int mode); #ifdef JANET_FILEWATCH void janet_lib_filewatch(JanetTable *env); #endif +#endif #ifdef JANET_FFI void janet_lib_ffi(JanetTable *env); #endif -#endif #endif diff --git a/src/core/value.c b/src/core/value.c index 74486371..b278a1bc 100644 --- a/src/core/value.c +++ b/src/core/value.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/vector.c b/src/core/vector.c index 4fe49572..64f1e780 100644 --- a/src/core/vector.c +++ b/src/core/vector.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/vector.h b/src/core/vector.h index 9cf90387..5aa24c13 100644 --- a/src/core/vector.h +++ b/src/core/vector.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/core/vm.c b/src/core/vm.c index 4fe179d3..6ad79053 100644 --- a/src/core/vm.c +++ b/src/core/vm.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -798,14 +798,14 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) { vm_pcnext(); VM_OP(JOP_JUMP) - pc += DS; vm_maybe_auto_suspend(DS <= 0); + pc += DS; vm_next(); VM_OP(JOP_JUMP_IF) if (janet_truthy(stack[A])) { - pc += ES; vm_maybe_auto_suspend(ES <= 0); + pc += ES; } else { pc++; } @@ -815,15 +815,15 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) { if (janet_truthy(stack[A])) { pc++; } else { - pc += ES; vm_maybe_auto_suspend(ES <= 0); + pc += ES; } vm_next(); VM_OP(JOP_JUMP_IF_NIL) if (janet_checktype(stack[A], JANET_NIL)) { - pc += ES; vm_maybe_auto_suspend(ES <= 0); + pc += ES; } else { pc++; } @@ -833,8 +833,8 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) { if (janet_checktype(stack[A], JANET_NIL)) { pc++; } else { - pc += ES; vm_maybe_auto_suspend(ES <= 0); + pc += ES; } vm_next(); diff --git a/src/core/wrap.c b/src/core/wrap.c index 98214fe0..c4fc1d16 100644 --- a/src/core/wrap.c +++ b/src/core/wrap.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/include/janet.h b/src/include/janet.h index 988e8016..de82b5fb 100644 --- a/src/include/janet.h +++ b/src/include/janet.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/mainclient/shell.c b/src/mainclient/shell.c index 3b20f629..3d95ee2d 100644 --- a/src/mainclient/shell.c +++ b/src/mainclient/shell.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/test/amalg/main.c b/test/amalg/main.c index 39d89317..3bcc688b 100644 --- a/test/amalg/main.c +++ b/test/amalg/main.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/test/suite-array.janet b/test/suite-array.janet index f0fecbaa..13e2407d 100644 --- a/test/suite-array.janet +++ b/test/suite-array.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-asm.janet b/test/suite-asm.janet index e435094d..075fe4e1 100644 --- a/test/suite-asm.janet +++ b/test/suite-asm.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-boot.janet b/test/suite-boot.janet index ec7c4133..c1fb8460 100644 --- a/test/suite-boot.janet +++ b/test/suite-boot.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-buffer.janet b/test/suite-buffer.janet index e5de3f86..45d077b9 100644 --- a/test/suite-buffer.janet +++ b/test/suite-buffer.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2024 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-bundle.janet b/test/suite-bundle.janet index f860c1fd..0d228cc9 100644 --- a/test/suite-bundle.janet +++ b/test/suite-bundle.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2024 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-capi.janet b/test/suite-capi.janet index 52f05433..dfa86fc0 100644 --- a/test/suite-capi.janet +++ b/test/suite-capi.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-cfuns.janet b/test/suite-cfuns.janet index d06323bf..3e36c3f7 100644 --- a/test/suite-cfuns.janet +++ b/test/suite-cfuns.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-compile.janet b/test/suite-compile.janet index e52c4057..204a91f8 100644 --- a/test/suite-compile.janet +++ b/test/suite-compile.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-corelib.janet b/test/suite-corelib.janet index 119ec768..d2a5d4d5 100644 --- a/test/suite-corelib.janet +++ b/test/suite-corelib.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-debug.janet b/test/suite-debug.janet index 3ed87e46..e0d8793d 100644 --- a/test/suite-debug.janet +++ b/test/suite-debug.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-ev.janet b/test/suite-ev.janet index c773e960..cf040e2c 100644 --- a/test/suite-ev.janet +++ b/test/suite-ev.janet @@ -526,4 +526,32 @@ (assert (= maxconn connect-count)) (:close s) +# Cancel os/proc-wait with ev/deadline +(let [p (os/spawn [;run janet "-e" "(os/sleep 4)"] :p)] + (var terminated-normally false) + (assert-error "deadline expired" + (ev/with-deadline 0.01 + (os/proc-wait p) + (print "uhoh") + (set terminated-normally true))) + (assert (not terminated-normally) "early termination failure") + # Without this kill, janet will wait the full 4 seconds for the subprocess to complete before exiting. + (assert-no-error "kill proc after wait failed" (os/proc-kill p))) + +# Cancel os/proc-wait with ev/deadline 2 +(let [p (os/spawn [;run janet "-e" "(os/sleep 0.1)"] :p)] + (var terminated-normally false) + (assert-error "deadline expired" + (ev/with-deadline 0.05 + (os/proc-wait p) + (print "uhoh") + (set terminated-normally true))) + (assert (not terminated-normally) "early termination failure 2") + (ev/sleep 0.15) + (assert (not terminated-normally) "early termination failure 3")) + +(let [f (coro (forever :foo))] + (ev/deadline 0.01 nil f true) + (assert-error "deadline expired" (resume f))) + (end-suite) diff --git a/test/suite-ffi.janet b/test/suite-ffi.janet index 6305651e..c6237736 100644 --- a/test/suite-ffi.janet +++ b/test/suite-ffi.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose & contributors +# Copyright (c) 2025 Calvin Rose & contributors # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to @@ -55,4 +55,11 @@ (compwhen has-ffi (assert-error "bad struct issue #1512" (ffi/struct :void))) +(compwhen has-ffi + (def buf @"") + (ffi/write :u8 10 buf) + (assert (= 1 (length buf))) + (ffi/write :u8 10 buf) + (assert (= 2 (length buf)))) + (end-suite) diff --git a/test/suite-filewatch.janet b/test/suite-filewatch.janet index 90bb82b9..9c3f7404 100644 --- a/test/suite-filewatch.janet +++ b/test/suite-filewatch.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2024 Calvin Rose & contributors +# Copyright (c) 2025 Calvin Rose & contributors # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-inttypes.janet b/test/suite-inttypes.janet index 67272130..91b38590 100644 --- a/test/suite-inttypes.janet +++ b/test/suite-inttypes.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose & contributors +# Copyright (c) 2025 Calvin Rose & contributors # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-io.janet b/test/suite-io.janet index 826ae755..726b7aa4 100644 --- a/test/suite-io.janet +++ b/test/suite-io.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose & contributors +# Copyright (c) 2025 Calvin Rose & contributors # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-marsh.janet b/test/suite-marsh.janet index 1bcfb0d5..9defbc55 100644 --- a/test/suite-marsh.janet +++ b/test/suite-marsh.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-math.janet b/test/suite-math.janet index 235ecc43..58b4ff18 100644 --- a/test/suite-math.janet +++ b/test/suite-math.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-os.janet b/test/suite-os.janet index c4d2bda6..40e62bfd 100644 --- a/test/suite-os.janet +++ b/test/suite-os.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-parse.janet b/test/suite-parse.janet index 3cf8b595..1cb3c71a 100644 --- a/test/suite-parse.janet +++ b/test/suite-parse.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-peg.janet b/test/suite-peg.janet index 59e9353b..cf7e86d6 100644 --- a/test/suite-peg.janet +++ b/test/suite-peg.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-pp.janet b/test/suite-pp.janet index 153cff09..4030d64f 100644 --- a/test/suite-pp.janet +++ b/test/suite-pp.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose & contributors +# Copyright (c) 2025 Calvin Rose & contributors # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-specials.janet b/test/suite-specials.janet index b6fdb078..edabf8c3 100644 --- a/test/suite-specials.janet +++ b/test/suite-specials.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-string.janet b/test/suite-string.janet index 43774f2d..49c67120 100644 --- a/test/suite-string.janet +++ b/test/suite-string.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-strtod.janet b/test/suite-strtod.janet index 888123fe..d14985b9 100644 --- a/test/suite-strtod.janet +++ b/test/suite-strtod.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-struct.janet b/test/suite-struct.janet index 32f6e9b4..3178a9e2 100644 --- a/test/suite-struct.janet +++ b/test/suite-struct.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-symcache.janet b/test/suite-symcache.janet index 8ad6d3a7..29b6c541 100644 --- a/test/suite-symcache.janet +++ b/test/suite-symcache.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-table.janet b/test/suite-table.janet index 4234194b..4f954778 100644 --- a/test/suite-table.janet +++ b/test/suite-table.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-tuple.janet b/test/suite-tuple.janet index 6a74e9ec..f2010080 100644 --- a/test/suite-tuple.janet +++ b/test/suite-tuple.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-unknown.janet b/test/suite-unknown.janet index 9f034612..f35d3ab4 100644 --- a/test/suite-unknown.janet +++ b/test/suite-unknown.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-value.janet b/test/suite-value.janet index bbd443a6..16a6d455 100644 --- a/test/suite-value.janet +++ b/test/suite-value.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/test/suite-vm.janet b/test/suite-vm.janet index 5fc375a2..e1019379 100644 --- a/test/suite-vm.janet +++ b/test/suite-vm.janet @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Calvin Rose +# Copyright (c) 2025 Calvin Rose # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to diff --git a/tools/symcharsgen.c b/tools/symcharsgen.c index e818bf9e..8193cd5c 100644 --- a/tools/symcharsgen.c +++ b/tools/symcharsgen.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024 Calvin Rose +* Copyright (c) 2025 Calvin Rose * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/tools/update_copyright.janet b/tools/update_copyright.janet new file mode 100644 index 00000000..71fdf611 --- /dev/null +++ b/tools/update_copyright.janet @@ -0,0 +1,44 @@ +(def usage (string "usage: janet " (first (dyn :args)) " ")) + +(def ignores [".git"]) +(def exts ["LICENSE" "Makefile" ".build" ".c" ".h" ".janet"]) + +(defn arg [i] + (defn bail [] (print usage) (quit)) + (if-not (= 3 (length (dyn :args))) + (bail) + (if-let [val (get (dyn :args) i)] + val + (bail)))) + +(def oy (arg 1)) +(def ny (arg 2)) +(def od (string "Copyright (c) " oy " Calvin Rose")) +(def nd (string "Copyright (c) " ny " Calvin Rose")) + +(defn join [dir name] + (os/realpath (string dir "/" name))) + +(defn add-children [dir paths] + (loop [name :in (os/dir dir) + :unless (has-value? ignores name)] + (array/push paths (join dir name)))) + +(defn ends-in? [exts s] + (find (fn [ext] (string/has-suffix? ext s)) exts)) + +(defn update-disclaimer [path] + (if-let [_ (ends-in? exts path) + oc (slurp path) + pos (string/find od oc) + nc (string (string/slice oc 0 pos) nd (string/slice oc (+ pos (length od))))] + (spit path nc))) + +(def cwd (os/cwd)) +(def paths (if (string/has-suffix? "janet" cwd) + @[cwd] + @[(join cwd "..")])) +(loop [p :in paths] + (if (= :directory ((os/stat p) :mode)) + (add-children p paths) + (update-disclaimer p)))