Skip to content

Up for discussion: Move the "main runtime" of es out of C and into es script #79

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 30 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d4e750d
Experimental "put everything in es script" change.
jpco Jun 1, 2023
ea50881
Use fancy "match" syntax
jpco Jun 1, 2023
c38d1a5
move -p out of main as well
jpco Jun 1, 2023
96617cf
Move GC flag parsing out of main()
jpco Jun 1, 2023
5464e3d
Cleanup and fix %dispatch for -c
jpco Jun 1, 2023
59aa719
Man page update
jpco Jun 1, 2023
de1cafd
Tweak $&batchloop
jpco Jun 2, 2023
65b3071
remove last vestiges of getopt :)
jpco Jun 2, 2023
ba242e9
Remove last last bits of getopt from main.c
jpco Aug 4, 2023
018867a
Merge upstream wryun/master
jpco Dec 3, 2023
efbfdc9
Get a little kludgey, but make trip.es pass
jpco Dec 3, 2023
68da275
Cleanup debug stuff
jpco Dec 3, 2023
571c1ed
Move more things out of the main es binary.
jpco Jan 14, 2024
ad847aa
A bit more concision
jpco Jan 14, 2024
365bbed
Update comment
jpco Jan 14, 2024
1a94d49
Runflags updates. Namely, don't allow the -GLI flags if support isn'…
jpco Jan 15, 2024
3b5a43a
Reorganize runtime.es to read top-to-bottom instead of C-style bottom…
jpco Jan 16, 2024
a5b8190
Fix up man page to reflect the last few commits correctly.
jpco Jan 16, 2024
7d161b1
Dump improvements:
jpco Jan 16, 2024
5a39571
Shore up the "root exception handler" story.
jpco Jan 16, 2024
d460f96
Fix incorrect (old) references to %run-input/$&runinput.
jpco Jan 16, 2024
ac08c75
Fix memory-unsafe $&conditionalflags.
jpco Jan 17, 2024
98a1139
Nitpicks:
jpco Jan 17, 2024
e15ed3f
Complete migration of option-parsing into pure es.
jpco Jan 19, 2024
5de1c46
Missed a couple old references to "es:main"
jpco Jan 19, 2024
aa7e1e9
Actually remove opt.c
jpco Jan 19, 2024
bc15306
Fix breaking typos -_-
jpco Jan 20, 2024
5dd39fe
Only try to run .esrc on login if it exists
jpco Jan 20, 2024
2a11f1f
Add $&getpid primitive and use that to initialize $pid at startup.
jpco Nov 24, 2024
2c716ea
Merge remote-tracking branch 'upstream/master' into es-main
jpco Jun 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ LIBS = @READLINE_LIBS@ @LIBS@ $(ADDLIBS)
HFILES = config.h es.h gc.h input.h prim.h print.h sigmsgs.h \
stdenv.h syntax.h term.h var.h
CFILES = access.c closure.c conv.c dict.c eval.c except.c fd.c gc.c glob.c \
glom.c input.c heredoc.c history.c list.c main.c match.c open.c opt.c \
prim-ctl.c prim-etc.c prim-io.c prim-sys.c prim.c print.c proc.c \
glom.c input.c heredoc.c history.c list.c main.c match.c open.c \
prim-ctl.c prim-etc.c prim-io.c prim-sys.c prim-dump.c prim.c print.c proc.c \
sigmsgs.c signal.c split.c status.c str.c syntax.c term.c token.c \
tree.c util.c var.c vec.c version.c y.tab.c dump.c
OFILES = access.o closure.o conv.o dict.o eval.o except.o fd.o gc.o glob.o \
glom.o input.o heredoc.o history.o list.o main.o match.o open.o opt.o \
prim-ctl.o prim-etc.o prim-io.o prim-sys.o prim.o print.o proc.o \
glom.o input.o heredoc.o history.o list.o main.o match.o open.o \
prim-ctl.o prim-etc.o prim-io.o prim-sys.o prim-dump.o prim.o print.o proc.o \
sigmsgs.o signal.o split.o status.o str.o syntax.o term.o token.o \
tree.o util.o var.o vec.o version.o y.tab.o
OTHER = Makefile parse.y mksignal
Expand Down Expand Up @@ -112,7 +112,7 @@ y.tab.c : y.tab.h
token.h : y.tab.h
-cmp -s y.tab.h token.h || cp y.tab.h token.h

initial.c : esdump $(srcdir)/initial.es
initial.c : esdump $(srcdir)/initial.es $(srcdir)/runtime.es
./esdump < $(srcdir)/initial.es > initial.c

sigmsgs.c : mksignal $(SIGFILES)
Expand Down Expand Up @@ -141,7 +141,6 @@ list.o : list.c es.h config.h stdenv.h gc.h
main.o : main.c es.h config.h stdenv.h
match.o : match.c es.h config.h stdenv.h
open.o : open.c es.h config.h stdenv.h
opt.o : opt.c es.h config.h stdenv.h
prim.o : prim.c es.h config.h stdenv.h prim.h
prim-ctl.o : prim-ctl.c es.h config.h stdenv.h prim.h
prim-etc.o : prim-etc.c es.h config.h stdenv.h prim.h
Expand Down
131 changes: 43 additions & 88 deletions access.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,103 +80,58 @@ static int testfile(char *path, unsigned int perm, unsigned int type) {
return testperm(&st, perm);
}

static char *pathcat(char *prefix, char *suffix) {
char *s;
size_t plen, slen, len;
static char *pathbuf = NULL;
static size_t pathlen = 0;

if (*prefix == '\0')
return suffix;
if (*suffix == '\0')
return prefix;

plen = strlen(prefix);
slen = strlen(suffix);
len = plen + slen + 2; /* one for '/', one for '\0' */
if (pathlen < len) {
pathlen = len;
pathbuf = erealloc(pathbuf, pathlen);
}

memcpy(pathbuf, prefix, plen);
s = pathbuf + plen;
if (s[-1] != '/')
*s++ = '/';
memcpy(s, suffix, slen + 1);
return pathbuf;
}
static int *permtab[256] = { NULL };
static int *typetab[256] = { NULL };

PRIM(access) {
int c, estatus = ENOENT;
unsigned int perm = 0, type = 0;
Boolean first = FALSE, throws = FALSE;
char *suffix = NULL;
List *lp;
const char * const usage = "access [-n name] [-1e] [-rwx] [-fdcblsp] path ...";

gcdisable();
esoptbegin(list, "$&access", usage, TRUE);
while ((c = esopt("bcdefln:prswx1")) != EOF)
switch (c) {
case 'n': suffix = getstr(esoptarg()); break;
case '1': first = TRUE; break;
case 'e': throws = TRUE; break;
case 'r': perm |= READ; break;
case 'w': perm |= WRITE; break;
case 'x': perm |= EXEC; break;
case 'f': type = IFREG; break;
case 'd': type = IFDIR; break;
case 'c': type = IFCHR; break;
case 'b': type = IFBLK; break;
case 'l': type = IFLNK; break;
case 's': type = IFSOCK; break;
case 'p': type = IFIFO; break;
default:
esoptend();
fail("$&access", "access -%c is not supported on this system", c);
}
list = esoptend();

for (lp = NULL; list != NULL; list = list->next) {
int error;
char *name;

name = getstr(list->term);
if (suffix != NULL)
name = pathcat(name, suffix);
error = testfile(name, perm, type);

if (first) {
if (error == 0) {
Ref(List *, result,
mklist(mkstr(suffix == NULL
? name
: gcdup(name)),
NULL));
gcenable();
RefReturn(result);
} else if (error != ENOENT)
estatus = error;
} else
lp = mklist(mkstr(error == 0 ? "0" : gcdup(esstrerror(error))),
lp);
}
int c, *p, perm = 0, type = 0, estatus;

if (length(list) != 3)
fail("$&access", "usage: access access-type file-type name");

if (first && throws) {
gcenable();
if (suffix)
fail("$&access", "%s: %s", suffix, esstrerror(estatus));
else
fail("$&access", "%s", esstrerror(estatus));
Ref(List *, result, NULL);
Ref(char *, atype, getstr(list->term));
Ref(char *, ftype, getstr(list->next->term));
Ref(char *, name, getstr(list->next->next->term));

for (c = 0; atype[c] != '\0'; c++) {
if ((p = permtab[(unsigned char)atype[c]]) == NULL)
fail("$&access", "bad access type '%c'", c);
perm |= *p;
}

Ref(List *, result, reverse(lp));
gcenable();
if (ftype[0] == '\0' || ftype[1] != '\0')
fail("$&access", "file type argument must be one character");
if ((p = typetab[(unsigned char)ftype[0]]) == NULL)
fail("$&access", "bad file type argument '%c'", ftype[0]);
type = *p;

estatus = testfile(name, perm, type);
result = mklist(mkstr(estatus == 0 ? "0" : esstrerror(estatus)), NULL);

RefEnd3(name, ftype, atype);
RefReturn(result);
}

#define FLAGTAB(type, c, def) \
STMT(static int CONCAT(type,c) = def; \
CONCAT(type,tab)[(unsigned char)(STRING(c)[0])] = &CONCAT(type,c))

extern Dict *initprims_access(Dict *primdict) {
FLAGTAB(perm, e, 0);
FLAGTAB(perm, r, READ);
FLAGTAB(perm, w, WRITE);
FLAGTAB(perm, x, EXEC);

FLAGTAB(type, a, 0);
FLAGTAB(type, f, IFREG);
FLAGTAB(type, d, IFDIR);
FLAGTAB(type, c, IFCHR);
FLAGTAB(type, b, IFBLK);
FLAGTAB(type, l, IFLNK);
FLAGTAB(type, s, IFSOCK);
FLAGTAB(type, p, IFIFO);

X(access);
return primdict;
}
Expand Down
130 changes: 105 additions & 25 deletions doc/es.1
Original file line number Diff line number Diff line change
Expand Up @@ -1778,6 +1778,56 @@ in
.Cr $signals ;
other values will be on the list if the shell starts up with
some signals ignored.
.TP
.Cr runflags
Contains a list of flags which control the execution of the
.I es
interpreter context.
Several of these correspond with shell options.
Any word can belong to the value of
.Cr $runflags ,
but only certain words have meaning to the
.I es
interpreter.
These words are
.IS
.TP
.Cr exitonfalse
Exit if any command returns a non-zero status.
Corresponds with the
.Cr \-e
option.
.TP
.Cr interactive
Run as an interactive shell.
Corresponds with the
.Cr \-i
option.
.TP
.Cr noexec
Turn off execution of commands.
Corresponds with the
.Cr \-n
option.
.TP
.Cr echoinput
Echo input to standard error.
Corresponds with the
.Cr \-v
option.
.TP
.Cr printcmds
Print commands to standard error before executing them.
Corresponds with the
.Cr \-x
option.
.TP
.Cr login
Run as a login shell.
Mainly this controls whether
.Cr .esrc
is run at startup.
.IE
.PP
The values of
.Cr path
Expand Down Expand Up @@ -2283,8 +2333,9 @@ Runs the command in the background.
The shell variable
.Cr apid
contains the process ID of the background process,
which is printed if the shell is interactive (according to
.Cr %is-interactive ).
which is printed if the shell is interactive (according to the
.Cr interactive
runflag.
.TP
.Cr "%backquote \fIseparator cmd\fP"
Runs the command in a child process and returns its
Expand Down Expand Up @@ -2383,6 +2434,17 @@ into one string,
separated by the string
.IR separator .
.TP
.Cr "%getopt \fIoptfunc args ...\fP"
This performs common
.Rc getopt
behavior, iterating through
.I args
and passing the args and the individual options they contain to
.IR optfunc .
All built-in
.I es
option parsing works via this function.
.TP
.Cr "%here \fIfd word ... cmd\fP"
Runs the command with the
.IR word s
Expand Down Expand Up @@ -2601,16 +2663,6 @@ Repeated instances of separator characters cause null strings to
appear in the result.
(This function is used by some builtin settor functions.)
.TP
.Cr "%is-interactive"
Returns true if the current interpreter context is interactive;
that is, if shell command input is currently coming from an
interactive user.
More precisely, this is true if the innermost enclosing read-eval-print
loop is
.Cr %interactive-loop
rather than
.Cr %batch-loop .
.TP
.Cr "%newfd"
Returns a file descriptor that the shell thinks is not currently in use.
.TP
Expand All @@ -2623,6 +2675,25 @@ This builtin can be used to set
(by convention, the name of the program)
to something other than file name.
.TP
.Cr "%run-file \fI[file]\fP"
Runs either
.Cr %interactive-loop
or
.Cr %batch-loop
reading the
.I file
for input.
stdin is used as input if no file is given.
.TP
.Cr "%run-string \fIstring\fP"
Runs either
.Cr %interactive-loop
or
.Cr %batch-loop
using the
.I string
directly as input.
.TP
.Cr "%split \fIseparator \fR[\fPargs ...\fR]"
Splits its arguments into separate strings at every occurrence
of any of the characters in the string
Expand Down Expand Up @@ -2667,20 +2738,13 @@ builtin functions with the same names:
.ta 1.75i 3.5i
.Ds
.ft \*(Cf
access forever throw
catch fork umask
echo if wait
exec newpgrp
exit result
forever throw catch
fork umask echo
if wait exec
newpgrp exit result
.ft R
.De
.PP
In addition, the primitive
.Cr dot
implements the
.Rc \(lq . \(rq
builtin function.
.PP
The
.Cr cd
primitive is used in the implementation of the
Expand All @@ -2694,6 +2758,11 @@ and
primitives are used by the implementation of the
.Cr vars
builtin.
The
.Cr access
primitive is used by the implementation of the
.Cr access
builtin.
.PP
The following primitives implement the hook functions
of the same names, with
Expand All @@ -2718,7 +2787,7 @@ prefixes and internal hyphens:
.ta 1.75i 3.5i
.Ds
.ft \*(Cf
batchloop exitonfalse isinteractive
exitonfalse runfile runstring
.ft R
.De
.PP
Expand Down Expand Up @@ -2749,7 +2818,7 @@ The following primitives implement the similarly named settor functions:
.ta 1.75i 3.5i
.Ds
.ft \*(Cf
setnoexport setsignals
setnoexport setsignals setrunflags
.ft R
.De
.PP
Expand Down Expand Up @@ -2810,6 +2879,17 @@ The garbage collector in
runs rather frequently;
there should be no reason for a user to issue this command.
.TP
.Cr "$&importenvfuncs"
Imports functions and settor functions from the environment.
This is used during
.I es
startup.
It is hardcoded to have no effect (and return false) if it has
already been called.
.TP
.Cr "$&isatty"
Tests whether the given fd is a TTY or not.
.TP
.Cr "$&noreturn \fIlambda args ...\fP"
Call the
.IR lambda ,
Expand Down
Loading