1
0
mirror of https://github.com/janet-lang/janet synced 2026-04-06 15:01:28 +00:00

Compare commits

..

28 Commits

Author SHA1 Message Date
Calvin Rose
f089b2001f Add several math functions to the math module. 2020-04-04 12:52:34 -05:00
Calvin Rose
9f8420bf50 Add jpm repl subcommand and post-deps macro for jpm.
This will allow more flexibility in writing jpm project files.
2020-04-03 19:33:54 -05:00
Calvin Rose
8275da63fb Address #331 - Add :octal-permissions 2020-04-03 18:29:45 -05:00
Calvin Rose
72696600d8 Add :deps opiton to declare-executable.
This allows the addition of custom dependencies.
2020-04-03 17:53:41 -05:00
Calvin Rose
1aeb317863 Revise, revise, revise, and proofread. 2020-04-03 17:04:05 -05:00
Calvin Rose
b49b510732 Update os/link docstring. 2020-04-03 16:58:45 -05:00
Calvin Rose
a0d61e45d5 Change os/perm-str to os/perm-string. 2020-04-03 15:23:29 -05:00
Calvin Rose
95f1ef7561 Add umask support for windows, and allow parsing mode strings. 2020-04-03 15:14:11 -05:00
Calvin Rose
edb2fab64c Merge branch 'master' of github.com:janet-lang/janet 2020-04-03 15:04:39 -05:00
Calvin Rose
464fb73d83 Add os/perm-int and os/perm-str.
This helps address #331. While we could also
make os/stat return an integer, we don't do that yet
for api breakage reasons.

This also lets us use this logic on other functions
that take permission strings.
2020-04-03 15:02:12 -05:00
Calvin Rose
6a4e63a17d Merge pull request #333 from andrewchambers/umask
Add os/umask.
2020-04-03 14:48:52 -05:00
Calvin Rose
168f94d29a Merge pull request #330 from DEADB17/patch-1
Correct typo and match wording for consistency
2020-04-03 14:46:15 -05:00
Andrew Chambers
3c2b1baff2 Add os/umask. 2020-04-02 23:33:50 +13:00
Calvin Rose
f2815d7068 Actually run the installer in build_win.bat. 2020-04-01 09:26:20 -05:00
Calvin Rose
f48d9465f5 Fix appveyor.yml 2020-04-01 09:23:19 -05:00
Calvin Rose
6b1d5c6d7b Work on improving deployment for windows. 2020-04-01 09:22:27 -05:00
Calvin Rose
789ef3608b Make format. 2020-04-01 08:54:01 -05:00
DEADB17
57b08a57a0 Corret typo and match wording for consistency 2020-03-31 23:32:17 -04:00
Calvin Rose
5b6b9f1597 Prepare for 1.8.1 release. 2020-03-31 09:49:09 -05:00
Calvin Rose
47f246ba66 Merge pull request #329 from pepe/master
Fix typo flie
2020-03-31 09:17:39 -05:00
Josef Pospíšil
b6b70d54ef Fix typo flie 2020-03-31 15:31:27 +02:00
Calvin Rose
417d9a14cc s/yaml/yml/g in README.md 2020-03-31 08:03:38 -05:00
Calvin Rose
244566ccd4 Remove manual feature definitions in boot.
Instead, reuse features as defined in features.h
2020-03-31 07:52:20 -05:00
Calvin Rose
ca4a35c90a Update CHANGELOG.md 2020-03-30 16:59:51 -05:00
Calvin Rose
e4ea8bc867 Fix features for bsd.
Don't define XOPEN_SOURCE unless we actually need it.
2020-03-30 15:38:03 -05:00
q66
5d840b944b Fix wrong check on big endian systems
We can't randomly type pun random-sized types on big endian
systems.
2020-03-30 13:38:49 -05:00
q66
1e28876494 Fix typo in big endian unmarshalling code
This was subtly breaking everything.
2020-03-30 13:38:49 -05:00
q66
a40b2767c5 Fix endian check for little endian PowerPC and maybe others
This fixes various subtle breakage on ppc64le at very least.
2020-03-30 13:38:49 -05:00
17 changed files with 311 additions and 132 deletions

View File

@@ -1,6 +1,21 @@
# Changelog
All notable changes to this project will be documented in this file.
## Unreleased - ???
- Add `math/erf`
- Add `math/erfc`
- Add `math/log1p`
- Add `math/next`
- Add os/umask
- Add os/perm-int
- Add os/perm-string
- Add :octal-permissions option for os/stat.
- Add `jpm repl` subcommand, as well as `post-deps` macro in project.janet files.
## 1.8.1 - 2020-03-31
- Fix bugs for big endian systems
- Fix 1.8.0 regression on BSDs
## 1.8.0 - 2020-03-29
- Add `reduce2`, `accumulate`, and `accumulate2`.
- Add lockfiles to `jpm` via `jpm make-lockfile` and `jpm load-lockfile`.

View File

@@ -2,8 +2,8 @@
 
[![Appveyor Status](https://ci.appveyor.com/api/projects/status/bjraxrxexmt3sxyv/branch/master?svg=true)](https://ci.appveyor.com/project/bakpakin/janet/branch/master)
[![Build Status](https://travis-ci.org/janet-lang/janet.svg?branch=master)](https://travis-ci.org/janet-lang/janet)
[![builds.sr.ht status](https://builds.sr.ht/~bakpakin/janet/.freebsd.yaml.svg)](https://builds.sr.ht/~bakpakin/janet/.freebsd.yaml?)
[![builds.sr.ht status](https://builds.sr.ht/~bakpakin/janet/.openbsd.yaml.svg)](https://builds.sr.ht/~bakpakin/janet/.openbsd.yaml?)
[![builds.sr.ht status](https://builds.sr.ht/~bakpakin/janet/freebsd.yml.svg)](https://builds.sr.ht/~bakpakin/janet/freebsd.yml?)
[![builds.sr.ht status](https://builds.sr.ht/~bakpakin/janet/openbsd.yml.svg)](https://builds.sr.ht/~bakpakin/janet/openbsd.yml?)
<img src="https://raw.githubusercontent.com/janet-lang/janet/master/assets/janet-w200.png" alt="Janet logo" width=200 align="left">

View File

@@ -30,7 +30,7 @@ install:
- call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" %platform%
- build_win test-install
- set janet_outname=%appveyor_repo_tag_name%
- if "%janet_outname%"=="" set janet_outname=v1.8.0
- if "%janet_outname%"=="" set /P janet_outname=<build\version.txt
build: off
artifacts:
@@ -49,8 +49,7 @@ artifacts:
- name: "janet-$(janet_outname)-windows-%platform%"
path: dist
type: Zip
- path: "janet-$(janet_outname)-windows-installer.exe"
name: "janet-$(janet_outname)-windows-%platform%-installer.exe"
- path: "janet-$(janet_outname)-windows-%platform%-installer.exe"
type: File
deploy:

View File

@@ -181,11 +181,12 @@
(put into k (x k))))
into)
(defn import-rules
"Import another file that defines more rules. This ruleset
is merged into the current ruleset."
[path]
(defn require-jpm
"Require a jpm file project file. This is different from a normal require
in that code is loaded in the jpm environment."
[path &opt no-deps]
(def env (make-env))
(put env :jpm-no-deps no-deps)
(unless (os/stat path :mode)
(error (string "cannot open " path)))
(loop [k :keys _env :when (symbol? k)]
@@ -194,9 +195,24 @@
(loop [k :keys currenv :when (keyword? k)]
(put env k (currenv k)))
(dofile path :env env :exit true)
env)
(defn import-rules
"Import another file that defines more rules. This ruleset
is merged into the current ruleset."
[path &opt no-deps]
(def env (require-jpm path no-deps))
(when-let [rules (env :rules)] (merge-into (getrules) rules))
env)
(defmacro post-deps
"Run code at the top level if jpm dependencies are installed. Build
code that imports dependencies should be wrapped with this macro, as project.janet
needs to be able to run successfully even without dependencies installed."
[& body]
(unless (dyn :jpm-no-deps)
~',(reduce |(eval $1) nil body)))
#
# OS and shell helpers
#
@@ -799,13 +815,15 @@ int main(int argc, const char **argv) {
is marshalled into bytecode which is then embedded in a final executable for distribution.\n\n
This executable can be installed as well to the --binpath given."
[&keys {:install install :name name :entry entry :headers headers
:cflags cflags :lflags lflags}]
:cflags cflags :lflags lflags :deps deps}]
(def name (if is-win (string name ".exe") name))
(def dest (string "build" sep name))
(create-executable @{:cflags cflags :lflags lflags} entry dest)
(add-dep "build" dest)
(when headers
(each h headers (add-dep dest h)))
(when deps
(each d deps (add-dep dest d)))
(when install
(install-rule dest (dyn :binpath JANET_BINPATH))))
@@ -912,8 +930,8 @@ int main(int argc, const char **argv) {
'(* "--" '(some (if-not "=" 1)) (+ (* "=" '(any 1)) -1))))
(defn- local-rule
[rule]
(import-rules "./project.janet")
[rule &opt no-deps]
(import-rules "./project.janet" no-deps)
(do-rule rule))
(defn- help
@@ -948,6 +966,8 @@ Subcommands are:
name is lockfile.janet.
load-lockfile (lockfile) : Install modules from a lockfile in a reproducible way. The
default lockfile name is lockfile.janet.
repl : Run a repl in the context of the current project.janet file. This lets you run rules and
otherwise debug the current project.janet file.
Keys are:
--modpath : The directory to install modules to. Defaults to $JANET_MODPATH, $JANET_PATH, or (dyn :syspath)
@@ -961,15 +981,16 @@ Keys are:
--pkglist : URL of git repository for package listing. Defaults to $JANET_PKGLIST or https://github.com/janet-lang/pkgs.git
Flags are:
--nocolor : Disable color in the jpm repl.
--verbose : Print shell commands as they are executed.
--test : If passed to jpm install, runs tests before installing. Will run tests recursively on dependencies.
`))
(defn- show-help
(defn show-help
[]
(print help))
(defn- show-paths
(defn show-paths
[]
(print "binpath: " (dyn :binpath JANET_BINPATH))
(print "modpath: " (dyn :modpath JANET_MODPATH))
@@ -977,21 +998,21 @@ Flags are:
(print "headerpath: " (dyn :headerpath JANET_HEADERPATH))
(print "syspath: " (dyn :syspath)))
(defn- build
(defn build
[]
(local-rule "build"))
(defn- clean
(defn clean
[]
(local-rule "clean"))
(defn- install
(defn install
[&opt repo]
(if repo
(install-git repo)
(local-rule "install")))
(defn- test
(defn test
[]
(local-rule "test"))
@@ -1001,25 +1022,40 @@ Flags are:
(uninstall what)
(local-rule "uninstall")))
(defn- deps
(defn deps
[]
(local-rule "install-deps"))
(local-rule "install-deps" true))
(defn- list-rules
[]
(import-rules "./project.janet")
(defn list-rules
[&opt ctx]
(import-rules "./project.janet" true)
(def ks (sort (seq [k :keys (dyn :rules)] k)))
(each k ks (print k)))
(defn- update-pkgs
(defn update-pkgs
[]
(install-git (dyn :pkglist default-pkglist)))
(defn- quickbin
(defn quickbin
[input output]
(create-executable @{} input output)
(do-rule output))
(defn jpm-repl
[]
(def env (require-jpm "./project.janet"))
(def p (env :project))
(def name (p :name))
(setdyn :pretty-format (if-not (dyn :nocolor) "%.20Q" "%.20q"))
(setdyn :err-color (if-not (dyn :nocolor) true))
(print "Project: " name)
(print "Repository: " (p :repo))
(print "Author: " (p :author))
(defn getchunk [buf p]
(def [line] (parser/where p))
(getline (string "jpm[" name "]:" line ":" (parser/state p :delimiters) "> ") buf env))
(repl getchunk nil env))
(def- subcommands
{"build" build
"clean" clean
@@ -1028,6 +1064,7 @@ Flags are:
"test" test
"help" help
"deps" deps
"repl" jpm-repl
"show-paths" show-paths
"clear-cache" clear-cache
"run" local-rule

View File

@@ -131,7 +131,7 @@ exit /b 0
@rem Run the installer. (Installs to the local user with default settings)
:INSTALL
@echo Running Installer...
FOR %%a in (janet-*-windows-installer.exe) DO (
FOR %%a in (janet-*-windows-*-installer.exe) DO (
%%a /S /CurrentUser
)
exit /b 0

View File

@@ -1,3 +1,6 @@
# This file is invoked by build_win.bat
# Relevant configuration variables are set there.
Unicode True
!echo "Program Files: ${PROGRAMFILES}"
@@ -20,6 +23,9 @@ VIFileVersion "${PRODUCT_VERSION}"
!if ${SIXTYFOUR} == "true"
!define MULTIUSER_USE_PROGRAMFILES64
!define PLATNAME "x64"
!else
!define PLATNAME "x86"
!endif
# Includes
@@ -36,12 +42,12 @@ Name "Janet"
!define DOLLAR "$"
!ifdef CHECK_${DOLLAR}%APPVEYOR_REPO_TAG_NAME%
# We are not in the appveyor environment, use version name
!define OUTNAME_PART v${VERSION}
!define OUTNAME_PART ${VERSION}
!else
# We are in appveyor, use git tag name for installer
!define OUTNAME_PART ${OUTNAME}
!endif
OutFile "janet-${OUTNAME_PART}-windows-installer.exe"
OutFile "janet-${OUTNAME_PART}-windows-${PLATNAME}-installer.exe"
# Some Configuration
!define APPNAME "Janet"

9
jpm.1
View File

@@ -24,6 +24,10 @@ More interesting are the local commands. For more information on jpm usage, see
.SH FLAGS
.TP
.BR \-\-nocolor
Disable color in the jpm repl.
.TP
.BR \-\-verbose
Print detailed messages of what jpm is doing, including compilation commands and other shell commands.
@@ -154,6 +158,11 @@ The main function is the entry point of the program and will receive command lin
as function arguments. The entry file can import other modules, including native C modules, and
jpm will attempt to include the dependencies into the generated executable.
.TP
.BR repl
Load the current project.janet file and start a repl in it's environment. This lets a user better
debug the project file, as well as run rules manually.
.SH ENVIRONMENT
.B JANET_PATH

View File

@@ -20,7 +20,7 @@
project('janet', 'c',
default_options : ['c_std=c99', 'b_lundef=false', 'default_library=both'],
version : '1.8.0')
version : '1.8.1')
# Global settings
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')

View File

@@ -942,7 +942,7 @@
(reduce fop x forms))
(defmacro -?>
"Short circuit threading macro. Inserts x as the last value in the first form
"Short circuit threading macro. Inserts x as the second value in the first form
in forms, and inserts the modified first form into the second form
in the same manner, and so on. The pipeline will return nil
if an intermediate value is nil.
@@ -958,7 +958,7 @@
(reduce fop x forms))
(defmacro -?>>
"Threading macro. Inserts x as the last value in the first form
"Short circuit threading macro. Inserts x as the last value in the first form
in forms, and inserts the modified first form into the second form
in the same manner, and so on. The pipeline will return nil
if an intermediate value is nil.
@@ -2528,9 +2528,10 @@
# Create amalgamation
(def feature-header "src/core/features.h")
(def local-headers
["src/core/features.h"
"src/core/util.h"
["src/core/util.h"
"src/core/state.h"
"src/core/gc.h"
"src/core/vector.h"
@@ -2584,22 +2585,23 @@
(print "/* Generated from janet version " janet/version "-" janet/build " */")
(print "#define JANET_BUILD \"" janet/build "\"")
(print ```#define JANET_AMALG```)
(print ```#define _POSIX_C_SOURCE 200112L```)
(print ```#define _XOPEN_SOURCE 500```)
(print ```#include "janet.h"```)
(defn do-one-flie
(defn do-one-file
[fname]
(print "\n/* " fname " */")
(print "#line 0 \"" fname "\"\n")
(def source (slurp fname))
(print (string/replace-all "\r" "" source)))
(do-one-file feature-header)
(print ```#include "janet.h"```)
(each h local-headers
(do-one-flie h))
(do-one-file h))
(each s core-sources
(do-one-flie s))
(do-one-file s))
# Create C source file that contains images a uint8_t buffer. This
# can be compiled and linked statically into the main janet library

View File

@@ -28,9 +28,9 @@
#define JANET_VERSION_MAJOR 1
#define JANET_VERSION_MINOR 8
#define JANET_VERSION_PATCH 0
#define JANET_VERSION_PATCH 1
#define JANET_VERSION_EXTRA ""
#define JANET_VERSION "1.8.0"
#define JANET_VERSION "1.8.1"
/* #define JANET_BUILD "local" */

View File

@@ -29,7 +29,8 @@
#define _POSIX_C_SOURCE 200112L
#endif
#ifndef _XOPEN_SOURCE
/* Needed for realpath on linux */
#if !defined(_XOPEN_SOURCE) && defined(__linux__)
#define _XOPEN_SOURCE 500
#endif

View File

@@ -1141,7 +1141,7 @@ static const uint8_t *unmarshal_one(
u.bytes[0] = data[8];
u.bytes[1] = data[7];
u.bytes[2] = data[6];
u.bytes[5] = data[5];
u.bytes[3] = data[5];
u.bytes[4] = data[4];
u.bytes[5] = data[3];
u.bytes[6] = data[2];

View File

@@ -255,6 +255,10 @@ JANET_DEFINE_MATHOP(fabs, fabs)
JANET_DEFINE_MATHOP(floor, floor)
JANET_DEFINE_MATHOP(trunc, trunc)
JANET_DEFINE_MATHOP(round, round)
JANET_DEFINE_MATHOP(gamma, lgamma)
JANET_DEFINE_MATHOP(log1p, log1p)
JANET_DEFINE_MATHOP(erf, erf)
JANET_DEFINE_MATHOP(erfc, erfc)
#define JANET_DEFINE_MATH2OP(name, fop)\
static Janet janet_##name(int32_t argc, Janet *argv) {\
@@ -267,6 +271,7 @@ static Janet janet_##name(int32_t argc, Janet *argv) {\
JANET_DEFINE_MATH2OP(atan2, atan2)
JANET_DEFINE_MATH2OP(pow, pow)
JANET_DEFINE_MATH2OP(hypot, hypot)
JANET_DEFINE_MATH2OP(nextafter, nextafter)
static Janet janet_not(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
@@ -438,6 +443,26 @@ static const JanetReg math_cfuns[] = {
JDOC("(math/exp2 x)\n\n"
"Returns 2 to the power of x.")
},
{
"math/log1p", janet_log1p,
JDOC("(math/log1p x)\n\n"
"Returns (log base e of x) + 1 more accurately than (+ (math/log x) 1)")
},
{
"math/gamma", janet_gamma,
JDOC("(math/gamma x)\n\n"
"Returns gamma(x).")
},
{
"math/erfc", janet_erfc,
JDOC("(math/erfc x)\n\n"
"Returns the complementary error function of x.")
},
{
"math/erf", janet_erf,
JDOC("(math/erf x)\n\n"
"Returns the error function of x.")
},
{
"math/expm1", janet_expm1,
JDOC("(math/expm1 x)\n\n"
@@ -453,6 +478,11 @@ static const JanetReg math_cfuns[] = {
JDOC("(math/round x)\n\n"
"Returns the integer nearest to x.")
},
{
"math/next", janet_nextafter,
JDOC("(math/next y)\n\n"
"Returns the next representable floating point value after x in the direction of y.")
},
{NULL, NULL, NULL}
};

View File

@@ -880,40 +880,23 @@ static Janet os_readlink(int32_t argc, Janet *argv) {
}
#ifdef JANET_WINDOWS
static const uint8_t *janet_decode_permissions(unsigned short m) {
uint8_t flags[9] = {0};
flags[0] = flags[3] = flags[6] = (m & S_IREAD) ? 'r' : '-';
flags[1] = flags[4] = flags[7] = (m & S_IWRITE) ? 'w' : '-';
flags[2] = flags[5] = flags[8] = (m & S_IEXEC) ? 'x' : '-';
return janet_string(flags, sizeof(flags));
typedef struct _stat jstat_t;
typedef unsigned short jmode_t;
static int32_t janet_perm_to_unix(unsigned short m) {
int32_t ret = 0;
if (m & S_IEXEC) ret |= 0111;
if (m & S_IWRITE) ret |= 0222;
if (m & S_IREAD) ret |= 0444;
return ret;
}
static unsigned short janet_encode_permissions(Janet *argv, int32_t n) {
if (janet_checkint(argv[n])) {
int32_t x = janet_unwrap_integer(argv[n]);
if (x < 0 || x > 0777) {
janet_panicf("expected integer in range [0, 8r777], got %v", argv[n]);
}
unsigned short m = 0;
if (x & 1 || x & 010 || x & 0100) m |= S_IEXEC;
if (x & 2 || x & 020 || x & 0200) m |= S_IWRITE;
if (x & 4 || x & 040 || x & 0400) m |= S_IREAD;
return m;
}
JanetString perm = janet_getstring(argv, n);
if (janet_string_length(perm) != 9) {
janet_panicf("expected string of length 9, got %S", perm);
}
static unsigned short janet_perm_from_unix(int32_t x) {
unsigned short m = 0;
if (perm[0] == 'r') m |= S_IREAD;
if (perm[1] == 'w') m |= S_IWRITE;
if (perm[2] == 'x') m |= S_IEXEC;
if (perm[3] == 'r') m |= S_IREAD;
if (perm[4] == 'w') m |= S_IWRITE;
if (perm[5] == 'x') m |= S_IEXEC;
if (perm[6] == 'r') m |= S_IREAD;
if (perm[7] == 'w') m |= S_IWRITE;
if (perm[8] == 'x') m |= S_IEXEC;
if (x & 111) m |= S_IEXEC;
if (x & 222) m |= S_IWRITE;
if (x & 444) m |= S_IREAD;
return m;
}
@@ -924,44 +907,22 @@ static const uint8_t *janet_decode_mode(unsigned short m) {
else if (m & _S_IFCHR) str = "character";
return janet_ckeyword(str);
}
#else
static const uint8_t *janet_decode_permissions(mode_t m) {
uint8_t flags[9] = {0};
flags[0] = (m & S_IRUSR) ? 'r' : '-';
flags[1] = (m & S_IWUSR) ? 'w' : '-';
flags[2] = (m & S_IXUSR) ? 'x' : '-';
flags[3] = (m & S_IRGRP) ? 'r' : '-';
flags[4] = (m & S_IWGRP) ? 'w' : '-';
flags[5] = (m & S_IXGRP) ? 'x' : '-';
flags[6] = (m & S_IROTH) ? 'r' : '-';
flags[7] = (m & S_IWOTH) ? 'w' : '-';
flags[8] = (m & S_IXOTH) ? 'x' : '-';
return janet_string(flags, sizeof(flags));
static int32_t janet_decode_permissions(jmode_t mode) {
return (int32_t)(mode & (S_IEXEC | S_IWRITE | S_IREAD));
}
static mode_t janet_encode_permissions(Janet *argv, int32_t n) {
if (janet_checkint(argv[n])) {
int32_t x = janet_unwrap_integer(argv[n]);
if (x < 0 || x > 0777) {
janet_panicf("expected integer in range [0, 8r777], got %v", argv[n]);
}
return (mode_t) x;
}
JanetString perm = janet_getstring(argv, n);
if (janet_string_length(perm) != 9) {
janet_panicf("expected string of length 9, got %S", perm);
}
mode_t m = 0;
if (perm[0] == 'r') m |= S_IRUSR;
if (perm[1] == 'w') m |= S_IWUSR;
if (perm[2] == 'x') m |= S_IXUSR;
if (perm[3] == 'r') m |= S_IRGRP;
if (perm[4] == 'w') m |= S_IWGRP;
if (perm[5] == 'x') m |= S_IXGRP;
if (perm[6] == 'r') m |= S_IROTH;
if (perm[7] == 'w') m |= S_IWOTH;
if (perm[8] == 'x') m |= S_IXOTH;
return m;
#else
typedef struct stat jstat_t;
typedef mode_t jmode_t;
static int32_t janet_perm_to_unix(mode_t m) {
return (int32_t) m;
}
static mode_t janet_perm_from_unix(int32_t x) {
return (mode_t) x;
}
static const uint8_t *janet_decode_mode(mode_t m) {
@@ -975,13 +936,64 @@ static const uint8_t *janet_decode_mode(mode_t m) {
else if (S_ISCHR(m)) str = "character";
return janet_ckeyword(str);
}
static int32_t janet_decode_permissions(jmode_t mode) {
return (int32_t)(mode & 0777);
}
#endif
#ifdef JANET_WINDOWS
typedef struct _stat jstat_t;
#else
typedef struct stat jstat_t;
#endif
static int32_t os_parse_permstring(const uint8_t *perm) {
int32_t m = 0;
if (perm[0] == 'r') m |= 0400;
if (perm[1] == 'w') m |= 0200;
if (perm[2] == 'x') m |= 0100;
if (perm[3] == 'r') m |= 0040;
if (perm[4] == 'w') m |= 0020;
if (perm[5] == 'x') m |= 0010;
if (perm[6] == 'r') m |= 0004;
if (perm[7] == 'w') m |= 0002;
if (perm[8] == 'x') m |= 0001;
return m;
}
static Janet os_make_permstring(int32_t permissions) {
uint8_t bytes[9] = {0};
bytes[0] = (permissions & 0400) ? 'r' : '-';
bytes[1] = (permissions & 0200) ? 'w' : '-';
bytes[2] = (permissions & 0100) ? 'x' : '-';
bytes[3] = (permissions & 0040) ? 'r' : '-';
bytes[4] = (permissions & 0020) ? 'w' : '-';
bytes[5] = (permissions & 0010) ? 'x' : '-';
bytes[6] = (permissions & 0004) ? 'r' : '-';
bytes[7] = (permissions & 0002) ? 'w' : '-';
bytes[8] = (permissions & 0001) ? 'x' : '-';
return janet_stringv(bytes, sizeof(bytes));
}
static int32_t os_get_unix_mode(const Janet *argv, int32_t n) {
int32_t unix_mode;
if (janet_checkint(argv[n])) {
/* Integer mode */
int32_t x = janet_unwrap_integer(argv[n]);
if (x < 0 || x > 0777) {
janet_panicf("bad slot #%d, expected integer in range [0, 8r777], got %v", n, argv[n]);
}
unix_mode = x;
} else {
/* Bytes mode */
JanetByteView bytes = janet_getbytes(argv, n);
if (bytes.len != 9) {
janet_panicf("bad slot #%d: expected byte sequence of length 9, got %v", n, argv[n]);
}
unix_mode = os_parse_permstring(bytes.bytes);
}
return unix_mode;
}
static jmode_t os_getmode(const Janet *argv, int32_t n) {
return janet_perm_from_unix(os_get_unix_mode(argv, n));
}
/* Getters */
static Janet os_stat_dev(jstat_t *st) {
@@ -993,8 +1005,11 @@ static Janet os_stat_inode(jstat_t *st) {
static Janet os_stat_mode(jstat_t *st) {
return janet_wrap_keyword(janet_decode_mode(st->st_mode));
}
static Janet os_stat_int_permissions(jstat_t *st) {
return janet_wrap_integer(janet_perm_to_unix(janet_decode_permissions(st->st_mode)));
}
static Janet os_stat_permissions(jstat_t *st) {
return janet_wrap_string(janet_decode_permissions(st->st_mode));
return os_make_permstring(janet_perm_to_unix(janet_decode_permissions(st->st_mode)));
}
static Janet os_stat_uid(jstat_t *st) {
return janet_wrap_number(st->st_uid);
@@ -1045,6 +1060,7 @@ static const struct OsStatGetter os_stat_getters[] = {
{"dev", os_stat_dev},
{"inode", os_stat_inode},
{"mode", os_stat_mode},
{"octal-permissions", os_stat_int_permissions},
{"permissions", os_stat_permissions},
{"uid", os_stat_uid},
{"gid", os_stat_gid},
@@ -1122,14 +1138,25 @@ static Janet os_chmod(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
const char *path = janet_getcstring(argv, 0);
#ifdef JANET_WINDOWS
int res = _chmod(path, janet_encode_permissions(argv, 1));
int res = _chmod(path, os_getmode(argv, 1));
#else
int res = chmod(path, janet_encode_permissions(argv, 1));
int res = chmod(path, os_getmode(argv, 1));
#endif
if (-1 == res) janet_panicf("%s: %s", strerror(errno), path);
return janet_wrap_nil();
}
static Janet os_umask(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
int mask = (int) os_getmode(argv, 0);
#ifdef JANET_WINDOWS
int res = _umask(mask);
#else
int res = umask(mask);
#endif
return janet_wrap_integer(janet_perm_to_unix(res));
}
static Janet os_dir(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 2);
const char *dir = janet_getcstring(argv, 0);
@@ -1191,6 +1218,16 @@ static Janet os_realpath(int32_t argc, Janet *argv) {
#endif
}
static Janet os_permission_string(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
return os_make_permstring(os_get_unix_mode(argv, 0));
}
static Janet os_permission_int(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
return janet_wrap_integer(os_get_unix_mode(argv, 0));
}
#endif /* JANET_REDUCED_OS */
static const JanetReg os_cfuns[] = {
@@ -1249,7 +1286,8 @@ static const JanetReg os_cfuns[] = {
" only that information from stat. If the file or directory does not exist, returns nil. The keys are\n\n"
"\t:dev - the device that the file is on\n"
"\t:mode - the type of file, one of :file, :directory, :block, :character, :fifo, :socket, :link, or :other\n"
"\t:permissions - A unix permission string like \"rwx--x--x\". On windows, a string like \"rwx\".\n"
"\t:octal-permissions - A Unix permission integer like 8r744\n"
"\t:permissions - A Unix permission string like \"rwxr--r--\"\n"
"\t:uid - File uid\n"
"\t:gid - File gid\n"
"\t:nlink - number of links to file\n"
@@ -1270,9 +1308,9 @@ static const JanetReg os_cfuns[] = {
"os/chmod", os_chmod,
JDOC("(os/chmod path mode)\n\n"
"Change file permissions, where mode is a permission string as returned by "
"os/stat, or an integer. "
"When mode is an integer, it is interpreted as a unix permission value, best specified in octal, like "
"8r666 or 8r400. Windows will not differentiate between user, group, and other permissions. Returns nil.")
"os/perm-string, or an integer as returned by os/perm-int. "
"When mode is an integer, it is interpreted as a Unix permission value, best specified in octal, like "
"8r666 or 8r400. Windows will not differentiate between user, group, and other permissions, and thus will combine all of these permissions. Returns nil.")
},
{
"os/touch", os_touch,
@@ -1285,11 +1323,16 @@ static const JanetReg os_cfuns[] = {
JDOC("(os/cd path)\n\n"
"Change current directory to path. Returns nil on success, errors on failure.")
},
{
"os/umask", os_umask,
JDOC("(os/umask mask)\n\n"
"Set a new umask, returns the old umask.")
},
{
"os/mkdir", os_mkdir,
JDOC("(os/mkdir path)\n\n"
"Create a new directory. The path will be relative to the current directory if relative, otherwise "
"it will be an absolute path. Returns true if the directory was create, false if the directoyr already exists, and "
"it will be an absolute path. Returns true if the directory was created, false if the directory already exists, and "
"errors otherwise.")
},
{
@@ -1305,8 +1348,10 @@ static const JanetReg os_cfuns[] = {
{
"os/link", os_link,
JDOC("(os/link oldpath newpath &opt symlink)\n\n"
"Create a symlink from oldpath to newpath, returning nil. The 3rd optional paramater "
"enables a symlink iff truthy, hard link otherwise or if not provided. Does not work on Windows.")
"Create a link at newpath that points to oldpath and returns nil. "
"Iff symlink is truthy, creates a symlink. "
"Iff symlink is falsey or not provided, "
"creates a hard link. Does not work on Windows.")
},
{
"os/symlink", os_symlink,
@@ -1376,14 +1421,14 @@ static const JanetReg os_cfuns[] = {
{
"os/cryptorand", os_cryptorand,
JDOC("(os/cryptorand n &opt buf)\n\n"
"Get or append n bytes of good quality random data provided by the os. Returns a new buffer or buf.")
"Get or append n bytes of good quality random data provided by the OS. Returns a new buffer or buf.")
},
{
"os/date", os_date,
JDOC("(os/date &opt time local)\n\n"
"Returns the given time as a date struct, or the current time if no time is given. "
"Returns a struct with following key values. Note that all numbers are 0-indexed. "
"Date is given in UTC unless local is truthy, in which case the date is formated for "
"Date is given in UTC unless local is truthy, in which case the date is formatted for "
"the local timezone.\n\n"
"\t:seconds - number of seconds [0-61]\n"
"\t:minutes - number of minutes [0-59]\n"
@@ -1403,8 +1448,21 @@ static const JanetReg os_cfuns[] = {
{
"os/realpath", os_realpath,
JDOC("(os/realpath path)\n\n"
"Get the absolute path for a given path, following ../, ./, and symlinks. "
"Returns an absolute path as a string. Will raise an error on Windows.")
"Get the absolute path for a given path, following ../, ./, and symlinks. "
"Returns an absolute path as a string. Will raise an error on Windows.")
},
{
"os/perm-string", os_permission_string,
JDOC("(os/perm-string int)\n\n"
"Convert a Unix octal permission value from a permission integer as returned by os/stat "
"to a human readable string, that follows the formatting "
"of unix tools like ls. Returns the string as a 9 character string of r, w, x and - characters. Does not "
"include the file/directory/symlink character as rendered by `ls`.")
},
{
"os/perm-int", os_permission_int,
JDOC("(os/perm-int bytes)\n\n"
"Parse a 9 character permission string and return an integer that can be used by chmod.")
},
#endif
{NULL, NULL, NULL}

View File

@@ -97,7 +97,14 @@ extern "C" {
#endif
/* Check big endian */
#if defined(__MIPSEB__) /* MIPS 32-bit */ \
#if defined(__LITTLE_ENDIAN__) || \
(defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
/* If we know the target is LE, always use that - e.g. ppc64 little endian
* defines the __LITTLE_ENDIAN__ macro in the ABI spec, so we can rely
* on that and if that's not defined, fall back to big endian assumption
*/
#define JANET_LITTLE_ENDIAN 1
#elif defined(__MIPSEB__) /* MIPS 32-bit */ \
|| defined(__ppc__) || defined(__PPC__) /* CPU(PPC) - PowerPC 32-bit */ \
|| defined(__powerpc__) || defined(__powerpc) || defined(__POWERPC__) \
|| defined(_M_PPC) || defined(__PPC) \
@@ -656,7 +663,7 @@ struct Janet {
#define janet_type(x) ((x).type)
#define janet_checktype(x, t) ((x).type == (t))
#define janet_truthy(x) \
((x).type != JANET_NIL && ((x).type != JANET_BOOLEAN || ((x).as.integer & 0x1)))
((x).type != JANET_NIL && ((x).type != JANET_BOOLEAN || ((x).as.u64 & 0x1)))
#define janet_unwrap_struct(x) ((const JanetKV *)(x).as.pointer)
#define janet_unwrap_tuple(x) ((const Janet *)(x).as.pointer)

View File

@@ -8,7 +8,8 @@
(defn assert
"Override's the default assert with some nice error handling."
[x e]
[x &opt e]
(default e "assert error")
(++ num-tests-run)
(when x (++ num-tests-passed))
(if x

View File

@@ -194,4 +194,18 @@
(assert (deep= @[] (accumulate2 + [])) "accumulate2 2")
(assert (deep= @[] (accumulate 0 + [])) "accumulate 2")
# Perm strings
(assert (= (os/perm-int "rwxrwxrwx") 8r777) "perm 1")
(assert (= (os/perm-int "rwxr-xr-x") 8r755) "perm 2")
(assert (= (os/perm-int "rw-r--r--") 8r644) "perm 3")
(assert (= (band (os/perm-int "rwxrwxrwx") 8r077) 8r077) "perm 4")
(assert (= (band (os/perm-int "rwxr-xr-x") 8r077) 8r055) "perm 5")
(assert (= (band (os/perm-int "rw-r--r--") 8r077) 8r044) "perm 6")
(assert (= (os/perm-string 8r777) "rwxrwxrwx") "perm 7")
(assert (= (os/perm-string 8r755) "rwxr-xr-x") "perm 8")
(assert (= (os/perm-string 8r644) "rw-r--r--") "perm 9")
(end-suite)