Support execution of command script arguments.
authorEric S. Raymond <esr@thyrsus.com>
Tue, 5 Apr 2022 12:31:10 +0000 (08:31 -0400)
committerEric S. Raymond <esr@thyrsus.com>
Tue, 5 Apr 2022 18:33:29 +0000 (14:33 -0400)
Makefile
advent.adoc
advent.h
cheat.c
main.c
misc.c
saveresume.c

index 70d004eebe364743e46b8a8c467331c20fb3d3a8..80ac01f3b4a10c506305cf3ac9c1b72280281553 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ VERS=$(shell sed -n <NEWS '/^[0-9]/s/:.*//p' | head -1)
 .PHONY: check coverage
 
 CC?=gcc
-CCFLAGS+=-std=c99 -D_DEFAULT_SOURCE -DVERSION=\"$(VERS)\" -O2 -D_FORTIFY_SOURCE=2 -fstack-protector-all $(CFLAGS)
+CCFLAGS+=-std=c99 -D_DEFAULT_SOURCE -DVERSION=\"$(VERS)\" -O2 -D_FORTIFY_SOURCE=2 -fstack-protector-all $(CFLAGS) -g
 LIBS=$(shell pkg-config --libs libedit)
 INC+=$(shell pkg-config --cflags libedit)
 
index 3215faa7461aa8bcd28203a9dc8394d9288e6db5..fa69ddceae1e78bcdde226b8f9da3d4ed566b663 100644 (file)
@@ -5,7 +5,7 @@
 advent - Colossal Cave Adventure
 
 == SYNOPSIS ==
-*advent* [-l logfile] [-o] [-r savefile]
+*advent* [-l logfile] [-o] [-r savefile] [script...]
 
 == DESCRIPTION ==
 The original Colossal Cave Adventure from 1976-77 was the origin of all
@@ -46,6 +46,10 @@ There have been no gameplay changes.
      Also ignores new-school one-letter commands l, x, g, z, i. Also
      case-smashes and truncates unrecognized text when echoed.
 
+Normally, game input is taken from standard input.  If script file
+arguments are given, input is taken fron them instead.  A script file
+argument of '-' is taken as a directive to read from standard input.
+
 == BUGS ==
 
 The binary save file format is fragile, dependent on your machine word
index a1fc4542da778986a9f4e83315ab96144d61f69a..840974905f0ca012cae93b6cdecc7d9b9c736d8f 100644 (file)
--- a/advent.h
+++ b/advent.h
@@ -45,6 +45,8 @@
  * which has its own meaning. */
 #define STASHED(obj)   (-1 - game.prop[obj])
 
+#define PROMPT "> "
+
 /*
  *  DESTROY(N)  = Get rid of an item by putting it in LOC_NOWHERE
  *  MOD(N,M)    = Arithmetic modulus
@@ -194,6 +196,10 @@ struct settings_t {
     FILE *logfp;
     bool oldstyle;
     bool prompt;
+    char **argv;
+    int argc;
+    int optind;
+    FILE *scriptfp;
 };
 
 typedef struct {
@@ -215,6 +221,7 @@ typedef struct {
 extern struct game_t game;
 extern struct settings_t settings;
 
+extern char *myreadline(const char *);
 extern bool get_command_input(command_t *);
 extern void clear_command(command_t *);
 extern void speak(const char*, ...);
diff --git a/cheat.c b/cheat.c
index 0eee14bfb2d44b29be7d0d3aad4639cbe538cf2a..d25e218fdf9a70b153b16cf836e8758037683105 100644 (file)
--- a/cheat.c
+++ b/cheat.c
@@ -12,6 +12,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdbool.h>
+#include <editline/readline.h>
 #include "advent.h"
 
 int main(int argc, char *argv[])
@@ -96,3 +97,14 @@ int main(int argc, char *argv[])
 
     return EXIT_SUCCESS;
 }
+
+/* 
+ * Ugh...unused, but required for linkage.
+ * See thje actually useful version of this in main.c
+ */
+
+char *myreadline(const char *prompt)
+{
+    return readline(prompt);
+}
+
diff --git a/main.c b/main.c
index ea9bf8fcb49dcdd370c044f334aa8751f4b2ade0..dfc682e5b032d805e282ae62018ff44562400919 100644 (file)
--- a/main.c
+++ b/main.c
@@ -11,6 +11,8 @@
 #include <signal.h>
 #include <string.h>
 #include <ctype.h>
+#include <unistd.h>
+#include <editline/readline.h>
 #include "advent.h"
 #include "dungeon.h"
 
@@ -50,11 +52,11 @@ int main(int argc, char *argv[])
 
 #ifndef ADVENT_NOSAVE
     const char* opts = "l:or:";
-    const char* usage = "Usage: %s [-l logfilename] [-o] [-r restorefilename]\n";
+    const char* usage = "Usage: %s [-l logfilename] [-o] [-r restorefilename] [script...]\n";
     FILE *rfp = NULL;
 #else
     const char* opts = "l:o";
-    const char* usage = "Usage: %s [-l logfilename] [-o]\n";
+    const char* usage = "Usage: %s [-l logfilename] [-o] [script...]\n";
 #endif
     while ((ch = getopt(argc, argv, opts)) != EOF) {
         switch (ch) {
@@ -95,6 +97,11 @@ int main(int argc, char *argv[])
         }
     }
 
+    /* copy inncation line part after switches */
+    settings.argc = argc - optind;
+    settings.argv = argv + optind;
+    settings.optind = 0;
+
     /*  Initialize game variables */
     int seedval = initialise();
 
@@ -129,6 +136,48 @@ int main(int argc, char *argv[])
     terminate(quitgame);
 }
 
+char *myreadline(const char *prompt)
+{
+    /*
+     * This function isbn't required for gameplay, readline() straight
+     * up would suffice for tat.  It's where we interpret command-line 
+     * logfiles for testing purposes.
+     */
+    /* Normal case - no script arguments */
+    if (settings.argc == 0)
+       return readline(prompt);
+
+    for (;;) {
+       if (settings.scriptfp == NULL || feof(settings.scriptfp)) {
+           if (settings.optind >= settings.argc) {
+               return NULL;
+           }
+
+           char *next = settings.argv[settings.optind++];
+       
+           if (settings.scriptfp != NULL && feof(settings.scriptfp))
+               fclose(settings.scriptfp);
+           if (strcmp(next, "-") == 0)
+               settings.scriptfp = stdin;
+           else
+               settings.scriptfp = fopen(next, "r");
+       }
+
+       if (isatty(fileno(settings.scriptfp))) {
+           return readline(prompt);
+       } else {
+           char *ln = fgets(malloc(BUFSIZ), BUFSIZ-1, settings.scriptfp);
+           if (ln != NULL) {
+               fputs(PROMPT, stdout);
+               fputs(ln, stdout);
+               return ln;
+           }
+       }
+    }
+
+    return NULL;
+}
+
 /*  Check if this loc is eligible for any hints.  If been here int
  *  enough, display.  Ignore "HINTS" < 4 (special stuff, see database
  *  notes). */
diff --git a/misc.c b/misc.c
index f2d674248d065951400bad163468a8c1d09f673c..a0f6c36140ba169fc1d50ee8ce29fc0921306213 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -211,7 +211,7 @@ static int word_count(char* str)
 static char* get_input(void)
 {
     // Set up the prompt
-    char input_prompt[] = "> ";
+    char input_prompt[] = PROMPT;
     if (!settings.prompt)
         input_prompt[0] = '\0';
 
@@ -220,7 +220,7 @@ static char* get_input(void)
 
     char* input;
     while (true) {
-        input = readline(input_prompt);
+        input = myreadline(input_prompt);
 
         if (input == NULL) // Got EOF; return with it.
             return (input);
index 15d14c1472dbbdc09b784581ee30f9e3c9fd1d80..fb247c91df8679ef669839d1c2d044d4f354fd44 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <stdlib.h>
 #include <string.h>
-#include <editline/readline.h>
 #include <time.h>
 #include <inttypes.h>
 
@@ -74,7 +73,7 @@ int suspend(void)
     game.saved = game.saved + 5;
 
     while (fp == NULL) {
-        char* name = readline("\nFile name: ");
+        char* name = myreadline("\nFile name: ");
         if (name == NULL)
             return GO_TOP;
         fp = fopen(name, WRITE_MODE);
@@ -107,7 +106,7 @@ int resume(void)
     }
 
     while (fp == NULL) {
-        char* name = readline("\nFile name: ");
+        char* name = myreadline("\nFile name: ");
        // Autocomplete can leave the input with an extra traoling space.
        if (name != NULL && strlen(name) > 0 && name[strlen(name) - 1] == ' ')
            name[strlen(name) - 1] = '\0';