aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2025-05-18 18:23:25 +0300
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2025-05-18 18:23:25 +0300
commitfe3535dbeec8f3f0fca9e6b895c993e59846e103 (patch)
tree10a20d25edf32adb45739ce6f2cc626b98a7391d
parent394fe39825cf4fc2f12ad511d8fea2bb61ee4837 (diff)
downloadsciteco-fe3535dbeec8f3f0fca9e6b895c993e59846e103.tar.gz
allow process exit status to be determined by macros
* Any value left on the numeric stack now determines the exit code. This ensures you can call n^C as the SciTECO version of exit(n). It will also work with n$$ in the top level macro. But you don't necessarily need any of these commands. * Could be useful in shell scripting as in `sciteco -e "@EB/file/ :@S/foo/\"F1'"` to fail `foo` is not found.
-rw-r--r--doc/sciteco.1.in7
-rw-r--r--src/core-commands.c9
-rw-r--r--src/main.c14
-rw-r--r--tests/testsuite.at22
4 files changed, 38 insertions, 14 deletions
diff --git a/doc/sciteco.1.in b/doc/sciteco.1.in
index f57415c..c7ad1a9 100644
--- a/doc/sciteco.1.in
+++ b/doc/sciteco.1.in
@@ -223,7 +223,12 @@ Execute \(lqsciteco --help\(rq for more details.
.SCITECO_TOPIC status
.
\*(ST will return a non-null exit code if an error occurred during
-batch mode processing.
+batch mode processing \(em usually 1 on UNIX.
+Otherwise the top value on the numeric stack will determine
+the process' exit code as if passed to libc's
+.BR exit (3)
+function.
+On UNIX systems only numbers between 0 and 255 may be meaningfull.
.
.
.SH ENVIRONMENT
diff --git a/src/core-commands.c b/src/core-commands.c
index 141ce0a..337e8df 100644
--- a/src/core-commands.c
+++ b/src/core-commands.c
@@ -1320,7 +1320,7 @@ teco_state_control_xor(teco_machine_main_t *ctx, GError **error)
}
/*$ ^C exit
- * ^C -- Exit program immediately
+ * [n]^C -- Exit program immediately
*
* Lets the top-level macro return immediately
* regardless of the current macro invocation frame.
@@ -1333,6 +1333,10 @@ teco_state_control_xor(teco_machine_main_t *ctx, GError **error)
* effectively just like \(lq-EX\fB$$\fP\(rq
* (when executed in the top-level macro at least).
*
+ * Any numeric parameter is returned by the process
+ * as its exit status.
+ * By default, the success code is returned.
+ *
* The \fBquit\fP hook is still executed.
*/
static void
@@ -1678,6 +1682,9 @@ teco_state_escape_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
* Returning from the top-level macro in batch mode
* will exit the program or start up interactive mode depending
* on whether program exit has been requested.
+ * If \fB$$\fP exits the program, any remaining numeric parameter
+ * is returned by the process as its exit status.
+ * By default, the success code is returned.
* \(lqEX\fB$$\fP\(rq is thus a common idiom to exit
* prematurely.
*
diff --git a/src/main.c b/src/main.c
index 05f8c41..e57ab6f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -35,6 +35,7 @@
#endif
#include "sciteco.h"
+#include "expressions.h"
#include "file-utils.h"
#include "cmdline.h"
#include "interface.h"
@@ -337,6 +338,7 @@ main(int argc, char **argv)
#endif
{
g_autoptr(GError) error = NULL;
+ teco_int_t ret = EXIT_SUCCESS;
#ifdef DEBUG_PAUSE
/* Windows debugging hack (see above) */
@@ -461,7 +463,8 @@ main(int argc, char **argv)
}
g_clear_error(&error);
- if (!teco_ed_hook(TECO_ED_HOOK_QUIT, &error))
+ if (!teco_expressions_pop_num_calc(&ret, EXIT_SUCCESS, &error) ||
+ !teco_ed_hook(TECO_ED_HOOK_QUIT, &error))
goto cleanup;
goto cleanup;
}
@@ -499,7 +502,8 @@ main(int argc, char **argv)
g_clear_error(&error);
if (teco_quit_requested) {
- if (!teco_ed_hook(TECO_ED_HOOK_QUIT, &error))
+ if (!teco_expressions_pop_num_calc(&ret, EXIT_SUCCESS, &error) ||
+ !teco_ed_hook(TECO_ED_HOOK_QUIT, &error))
goto cleanup;
goto cleanup;
}
@@ -553,8 +557,10 @@ main(int argc, char **argv)
goto cleanup;
cleanup:
- if (error != NULL)
+ if (error != NULL) {
teco_error_display_full(error);
+ ret = EXIT_FAILURE;
+ }
#ifndef NDEBUG
teco_ring_cleanup();
@@ -565,5 +571,5 @@ cleanup:
#endif
teco_interface_cleanup();
- return error ? EXIT_FAILURE : EXIT_SUCCESS;
+ return ret;
}
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 294bb5e..5cf3d4f 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -6,11 +6,11 @@ AT_COLOR_TESTS
AT_ARG_OPTION([valgrind],
AS_HELP_STRING([--valgrind], [Run tests under Valgrind (memcheck)]))
-# NOTE: There is currently no way to influence the return
-# code of SciTECO, except to provoke an error.
-# Since errors cannot be yielded explicitly, we use the
-# idiom "(0/0)" to enforce a "Division by zero" error
-# whenever we want to fail.
+# NOTE: We could use 1^C to get an unsuccessful return code.
+# However, this won't print any stack trace or error message.
+# Therefore, we still use the idiom "(0/0)" to enforce a "Division by zero"
+# error whenever we want to fail.
+# A proper error throwing construct should be used instead once it's available.
#
# NOTE: By convention, we double quote the SciTECO test case
# snippets, ie. put them between [[ and ]].
@@ -44,7 +44,7 @@ m4_define([TE_RUBOUT_WORD], [m4_format([%c], 23)])
AT_BANNER([Language features])
AT_SETUP([Number stack])
-TE_CHECK([[2%a,%a - 3"N(0/0)']], 0, ignore, ignore)
+TE_CHECK([[2%a,%a - 3"N(0/0)' $]], 0, ignore, ignore)
# It's not quite clear what would be the best semantics for comma:
# a) Superfluous commas as in ",," or "(1,)" should be an error.
# b) Superfluous commas should be ignored which is effectively what we do now.
@@ -55,6 +55,12 @@ TE_CHECK([[(1,) "~|(0/0)']], 0, ignore, ignore)
TE_CHECK([[1,(2)==]], 0, ignore, ignore)
AT_CLEANUP
+AT_SETUP([Exit status])
+TE_CHECK([[23]], 23, ignore, ignore)
+TE_CHECK([[42^C]], 42, ignore, ignore)
+TE_CHECK([[13$$]], 13, ignore, ignore)
+AT_CLEANUP
+
AT_SETUP([Radix])
TE_CHECK([[0^R]], 1, ignore, ignore)
TE_CHECK([[0U.^R]], 1, ignore, ignore)
@@ -103,8 +109,8 @@ AT_SETUP([Pass-through loops])
# More elegant would be a command for popping exactly one argument like <:$>.
TE_CHECK([[1,2,3,-1:<"~1;'%a=> Qa-6"N(0/0)']], 0, ignore, ignore)
TE_CHECK([[1,2,3,-1:<"~1;'%a= F>(0/0)> Qa-6"N(0/0)']], 0, ignore, ignore)
-TE_CHECK([[3<%a:>-3"N(0/0)']], 0, ignore, ignore)
-TE_CHECK([[3<%a :F>(0/0):>-3"N(0/0)']], 0, ignore, ignore)
+TE_CHECK([[3<%a:>-3"N(0/0)' $]], 0, ignore, ignore)
+TE_CHECK([[3<%a :F>(0/0):>-3"N(0/0)' $]], 0, ignore, ignore)
AT_CLEANUP
AT_SETUP([String arguments])