about summary refs log tree commit diff
path: root/Src/builtin.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/builtin.c')
-rw-r--r--Src/builtin.c97
1 files changed, 79 insertions, 18 deletions
diff --git a/Src/builtin.c b/Src/builtin.c
index 72c519037..99af38e3a 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -58,7 +58,7 @@ static struct builtin builtins[] =
     BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmrs", NULL),
     BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL),
     BUILTIN("echo", BINF_SKIPINVALID, bin_print, 0, -1, BIN_ECHO, "neE", "-"),
-    BUILTIN("emulate", 0, bin_emulate, 1, 1, 0, "LR", NULL),
+    BUILTIN("emulate", 0, bin_emulate, 0, 3, 0, "LR", NULL),
     BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmrs", NULL),
     BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL),
     BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL),
@@ -4744,24 +4744,12 @@ bin_dot(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
     return ret ? ret : lastval;
 }
 
-/**/
-int
-bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
-{
-    emulate(*argv, OPT_ISSET(ops,'R'));
-    if (OPT_ISSET(ops,'L'))
-	opts[LOCALOPTIONS] = opts[LOCALTRAPS] = 1;
-    return 0;
-}
-
-/* eval: simple evaluation */
-
-/**/
-mod_export int ineval;
+/*
+ * common for bin_emulate and bin_eval
+ */
 
-/**/
-int
-bin_eval(UNUSED(char *nam), char **argv, UNUSED(Options ops), UNUSED(int func))
+static int
+eval(char **argv)
 {
     Eprog prog;
     char *oscriptname = scriptname;
@@ -4838,6 +4826,79 @@ bin_eval(UNUSED(char *nam), char **argv, UNUSED(Options ops), UNUSED(int func))
     return lastval;
 }
 
+/* emulate: set emulation mode and optionally evaluate shell code */
+
+/**/
+int
+bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
+{
+    int opt_L = OPT_ISSET(ops, 'L');
+    int opt_R = OPT_ISSET(ops, 'R');
+    int saveemulation ;
+    int ret;
+    char saveopts[OPT_SIZE];
+
+    /* without arguments just print current emulation */
+    if (!*argv) {
+	if (opt_L || opt_R) {
+	    zwarnnam("emulate", "not enough arguments");
+	    return 1;
+	}
+
+	printf("%s\n", emulation == EMULATE_CSH ? "csh" :
+		       emulation == EMULATE_KSH ? "ksh" :
+		       emulation == EMULATE_SH  ? "sh" :
+		       "zsh");
+	return 0;
+    }
+
+    /* with single argument set current emulation */
+    if (!argv[1]) {
+	emulate(*argv, OPT_ISSET(ops,'R'));
+	if (OPT_ISSET(ops,'L'))
+	    opts[LOCALOPTIONS] = opts[LOCALTRAPS] = 1;
+	return 0;
+    }
+
+    /* If "-c command" is given, evaluate command using specified
+     * emulation mode.
+     */
+    if (strcmp(argv[1], "-c")) {
+	zwarnnam("emulate", "unknown argument %s", argv[1]);
+	return 1;
+    }
+
+    if (!argv[2]) {
+	zwarnnam("emulate", "not enough arguments");
+	return 1;
+    }
+
+    if (opt_L) {
+	zwarnnam("emulate", "option -L incompatible with -c");
+	return 1;
+    }
+
+    memcpy(saveopts, opts, sizeof(opts));
+    saveemulation = emulation;
+    emulate(*argv, OPT_ISSET(ops,'R'));
+    ret = eval(argv+2);
+    memcpy(opts, saveopts, sizeof(opts));
+    emulation = saveemulation;
+    return ret;
+}
+
+/* eval: simple evaluation */
+
+/**/
+mod_export int ineval;
+
+/**/
+int
+bin_eval(UNUSED(char *nam), char **argv, UNUSED(Options ops), UNUSED(int func))
+{
+    return eval(argv);
+}
+
 static char *zbuf;
 static int readfd;