]> granicus.if.org Git - nethack/commitdiff
SAFERHANGUP
authorcohrs <cohrs>
Fri, 19 Sep 2003 03:15:49 +0000 (03:15 +0000)
committercohrs <cohrs>
Fri, 19 Sep 2003 03:15:49 +0000 (03:15 +0000)
This is an initial round of SAFERHANGUP hangup changes.  It introduces
SAFERHANGUP, provides the core framework, and enables it for UNIX.

Window-port changes are provided for win/tty, win/X11 and win/gnome.  Qt
changes should be forthcoming after having Warwick look at them.
window.doc is updated so windowport maintainers have an clue what needs to
be done to support SAFERHANGUP.

12 files changed:
doc/fixes35.0
doc/window.doc
include/unixconf.h
src/cmd.c
src/save.c
sys/unix/unixmain.c
sys/unix/unixunix.c
win/X11/winX.c
win/X11/winmap.c
win/gnome/gnbind.c
win/tty/getline.c
win/tty/wintty.c

index aace11f4ebe25d266d6016ffb6e198bdb43ac3f8..7e2a34e6c8041e3f30c3fb4a70024ac3b988d6c1 100644 (file)
@@ -41,6 +41,9 @@ win32gui: better handling of "more" prompt for messages that would have scrolled
 win32gui: set correct checkmark on "Lock Windows" menu item on startup
 win32gui: redraw message window on resizing (it does not update properly otherwise)
 win32gui: fixed copy/paste error in read registry settings function
+platforms that support hangup: SAFERHANGUP to avoid losing objects in transit
+       between lists when hangup occurs, and also avoid cheats due to
+       well-timed hangups to stop a long melee
 
 
 General New Features
index cbfc571474ba4541767c541993886bb9f5583bec..2c79965ad699eb6c98c9ccf02ab389e481e48190 100644 (file)
@@ -120,6 +120,15 @@ int nhgetch()      -- Returns a single character input from the user.
                   will be the routine the OS provides to read a character.
                   Returned character _must_ be non-zero and it must be
                    non meta-zero too (zero with the meta-bit set).
+               -- If platform uses it, should check program_state.done_hup
+                  and immediately return ASCII 033 (escape) if it is.
+                  This is required if the window-port supports SAFERHANGUP.
+               -- ASCII 033 must also be returned rather than EOF (applies
+                  mainly to the tty window-port).
+               -- The program_state.done_hup flag can be set asynchronously
+                  when SAFERHANGUP is defined and in that case, nhgetch()
+                  needs to detect that the value of program_state.done_hup
+                  changed and also return ASCII 033 in this case.
 int nh_poskey(int *x, int *y, int *mod)
                -- Returns a single character input from the user or a
                   a positioning event (perhaps from a mouse).  If the
@@ -133,6 +142,7 @@ int nh_poskey(int *x, int *y, int *mod)
                   The different click types can map to whatever the
                   hardware supports.  If no mouse is supported, this
                   routine always returns a non-zero character.
+               -- Otherwise follows the same behavior as nhgetch().
 
 B.  High-level routines:
 
index fe1b00661df4d4069a476f71e1aa1e01a4c30f22..34eefe29f2e4f0102dec3737128b27d81337ee2d 100644 (file)
 #define SUSPEND                /* let ^Z suspend the game */
 #endif
 
+/*
+ * Define SAFERHANGUP to delay hangup processing until the main command
+ * loop. 'safer' because it avoids certain cheats and also avoids losing
+ * objects being thrown when the hangup occurs.  All unix windowports
+ * support SAFERHANGUP (couldn't define it here otherwise).
+ */
+#define SAFERHANGUP
+
 
 #if defined(BSD) || defined(ULTRIX)
 #include <sys/time.h>
index 522a2c5b89ae3db0d391c75209a5c1915921f099..562d5630a4393a06e905855283bc32e7d8091585 100644 (file)
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -146,7 +146,7 @@ STATIC_PTR boolean NDECL(minimal_enlightenment);
 
 STATIC_DCL void FDECL(enlght_line, (const char *,const char *,const char *));
 STATIC_DCL char *FDECL(enlght_combatinc, (const char *,int,int,char *));
-#ifdef UNIX
+#if defined(UNIX) || defined(SAFERHANGUP)
 static void NDECL(end_of_input);
 #endif
 
@@ -1794,6 +1794,9 @@ register char *cmd;
                firsttime = (cmd == 0);
 
        iflags.menu_requested = FALSE;
+#ifdef SAFERHANGUP
+       if (program_state.done_hup) end_of_input();
+#endif
        if (firsttime) {
                flags.nopick = 0;
                cmd = parse();
@@ -2375,15 +2378,17 @@ parse()
        return(in_line);
 }
 
-#ifdef UNIX
+#if defined(UNIX) || defined(SAFERHANGUP)
 static
 void
 end_of_input()
 {
        exit_nhwindows("End of input?");
 #ifndef NOSAVEONHANGUP
-       if (!program_state.done_hup++ && program_state.something_worth_saving)
-           (void) dosave0();
+# ifndef SAFERHANGUP
+       if (!program_state.done_hup++)
+#endif
+           if (program_state.something_worth_saving) (void) dosave0();
 #endif
        clearlocks();
        terminate(EXIT_SUCCESS);
@@ -2420,8 +2425,14 @@ readchar()
            } while (--cnt && sym == EOF);
        }
 # endif /* NR_OF_EOFS */
-       if (sym == EOF)
+       if (sym == EOF) {
+# ifndef SAFERHANGUP
            end_of_input();
+# else
+           program_state.done_hup++;
+           sym = '\033';
+# endif
+       }
 #endif /* UNIX */
 
        if(sym == 0) {
index 6230788fd20d338aea08c9f12961d591718aaa5a..0ce6d7e853da349ea459cebc155e6e8a49da680e 100644 (file)
@@ -91,6 +91,11 @@ int sig_unused;
 #  endif
 # else /* SAVEONHANGUP */
        if (!program_state.done_hup++) {
+#  ifndef SAFERHANGUP
+           /* When using SAFERHANGUP, the done_hup flag it tested in rhack
+            * and actual hangup behavior occurs then.  This is 'safer'
+            * because it disallows certain cheats and also protects
+            * against losing objects in the process of being thrown. */
            if (program_state.something_worth_saving)
                (void) dosave0();
 #  ifdef VMS
@@ -102,9 +107,9 @@ int sig_unused;
                clearlocks();
                terminate(EXIT_FAILURE);
            }
+#  endif /* !SAFERHANGUP */
        }
 # endif
-       return;
 }
 #endif
 
index 79cb24ba884316b337cebc4c853c9acc4d6f2208..a4b8c86c4c9a04e19a5283c5bc659f5f8ee113e4 100644 (file)
@@ -163,9 +163,28 @@ char *argv[];
         * It seems you really want to play.
         */
        u.uhp = 1;      /* prevent RIP on early quits */
+#ifdef SA_RESTART
+       /* don't want reads to restart.  If SA_RESTART is defined, we know
+        * sigaction exists and can be used to ensure reads won't restart.
+        * If it's not defined, assume reads do not restart.  If reads restart
+        * and a signal occurs, the game won't do anything until the read
+        * succeeds (or the stream returns EOF, which might not happen if
+        * reading from, say, a window manager). */
+       {
+           struct sigaction sact;
+
+           (void) memset((char*) &sact, 0, sizeof(struct sigaction));
+           sact.sa_handler = (SIG_RET_TYPE)hangup;
+           (void) sigaction(SIGHUP, &sact, (struct sigaction*)0);
+#ifdef SIGXCPU
+           (void) sigaction(SIGXCPU, &sact, (struct sigaction*)0);
+#endif
+       }
+#else
        (void) signal(SIGHUP, (SIG_RET_TYPE) hangup);
 #ifdef SIGXCPU
        (void) signal(SIGXCPU, (SIG_RET_TYPE) hangup);
+#endif
 #endif
 
        process_options(argc, argv);    /* command line options */
index f6c8b4bae9d37631577ba806d905a750b0cbda6e..80756df616c1ff93c57870681b22f7f8650b5f61 100644 (file)
@@ -155,19 +155,23 @@ getlock()
                    (void) printf("\nThere is already a game in progress under your name.");
                    (void) printf("  Destroy old game? [yn] ");
                    (void) fflush(stdout);
-                   c = getchar();
-                   (void) putchar(c);
-                   (void) fflush(stdout);
-                   while (getchar() != '\n') ; /* eat rest of line and newline */
+                   if ((c = getchar()) != EOF) {
+                       int tmp;
+
+                       (void) putchar(c);
+                       (void) fflush(stdout);
+                       while ((tmp = getchar()) != '\n' && tmp != EOF)
+                           ; /* eat rest of line and newline */
+                   }
                }
-               if(c == 'y' || c == 'Y')
+               if(c == 'y' || c == 'Y') {
                        if(eraseoldlocks())
                                goto gotlock;
                        else {
                                unlock_file(HLOCK);
                                error("Couldn't destroy old game.");
                        }
-               else {
+               else {
                        unlock_file(HLOCK);
                        error("%s", "");
                }
index d71159cd544f7dda947909781cbd160fcb3b0795..0c37b098827170bcf1eff974cbde55ba15ca63d3 100644 (file)
 #include "patchlevel.h"
 #endif
 
+#ifndef NO_SIGNAL
+#include <signal.h>
+#endif
+
 /* Should be defined in <X11/Intrinsic.h> but you never know */
 #ifndef XtSpecificationRelease
 #define XtSpecificationRelease 0
@@ -88,6 +92,9 @@ int click_x, click_y, click_button;   /* Click position on a map window   */
                                        /* (filled by set_button_values()). */
 int updated_inventory;
 
+#ifndef NO_SIGNAL
+static XtSignalId X11_sig_id;
+#endif
 
 /* Interface definition, for windows.c */
 struct window_procs X11_procs = {
@@ -162,7 +169,10 @@ static void FDECL(X11_hangup, (Widget, XEvent*, String*, Cardinal*));
 static int FDECL(input_event, (int));
 static void FDECL(win_visible, (Widget,XtPointer,XEvent *,Boolean *));
 static void NDECL(init_standard_windows);
-
+#if !defined(NO_SIGNAL) && defined(SAFERHANGUP)
+static void FDECL(X11_sig, (int));
+static void FDECL(X11_sig_cb, (XtPointer, XtSignalId*));
+#endif
 
 /*
  * Local variables.
@@ -604,6 +614,32 @@ X11_create_nhwindow(type)
     if (!x_inited)
        panic("create_nhwindow:  windows not initialized");
 
+#if !defined(NO_SIGNAL) && defined(SAFERHANGUP)
+    /* set up our own signal handlers on the first call.  Can't do this in
+     * X11_init_nhwindows because unixmain sets its handler after calling
+     * all the init routines. */
+    if (X11_sig_id == 0) {
+       X11_sig_id = XtAppAddSignal(app_context, X11_sig_cb, (XtPointer)0);
+#ifdef SA_RESTART
+       {
+           struct sigaction sact;
+
+           (void) memset((char*) &sact, 0, sizeof(struct sigaction));
+           sact.sa_handler = (SIG_RET_TYPE)X11_sig;
+           (void) sigaction(SIGHUP, &sact, (struct sigaction*)0);
+#ifdef SIGXCPU
+           (void) sigaction(SIGXCPU, &sact, (struct sigaction*)0);
+#endif
+       }
+#else
+       (void) signal(SIGHUP, (SIG_RET_TYPE) X11_sig);
+#ifdef SIGXCPU
+       (void) signal(SIGXCPU, (SIG_RET_TYPE) X11_sig);
+#endif
+#endif
+    }
+#endif
+
     /*
      * We have already created the standard message, map, and status
      * windows in the window init routine.  The first window of that
@@ -1064,6 +1100,36 @@ void X11_exit_nhwindows(dummy)
        X11_destroy_nhwindow(WIN_MESSAGE);
 }
 
+#if !defined(NO_SIGNAL) && defined(SAFERHANGUP)
+void
+X11_sig(sig)  /* Unix signal handler */
+int sig;
+{
+    XtNoticeSignal(X11_sig_id);
+    hangup(sig);
+}
+
+void
+X11_sig_cb(not_used, id)
+       XtPointer not_used;
+       XtSignalId* id;
+{
+    XEvent event;
+    XClientMessageEvent *mesg;
+
+    /* Set up a fake message to the event handler. */
+    mesg = (XClientMessageEvent *) &event;
+    mesg->type = ClientMessage;
+    mesg->message_type = XA_STRING;
+    mesg->format = 8;
+
+    XSendEvent(XtDisplay(window_list[WIN_MAP].w),
+              XtWindow(window_list[WIN_MAP].w),
+              False,
+              NoEventMask,
+              (XEvent*) mesg);
+}
+#endif
 
 /* delay_output ------------------------------------------------------------ */
 
index bef860bd31a864780ce1564eac89a320d296ff6b..3e23214cd3e165a078ce274c0e45f585c8449505 100644 (file)
@@ -1622,6 +1622,10 @@ x_event(exit_condition)
                    inptr = (inptr+1) % INBUF_SIZE;
                    /* pkey(retval); */
                    keep_going = FALSE;
+               } else if (program_state.done_hup) {
+                   retval = '\033';
+                   inptr = (inptr+1) % INBUF_SIZE;
+                   keep_going = FALSE;
                }
                break;
            case EXIT_ON_KEY_OR_BUTTON_PRESS:
@@ -1637,6 +1641,10 @@ x_event(exit_condition)
                        /* pkey(retval); */
                    }
                    keep_going = FALSE;
+               } else if (program_state.done_hup) {
+                   retval = '\033';
+                   inptr = (inptr+1) % INBUF_SIZE;
+                   keep_going = FALSE;
                }
                break;
            default:
index e97962958be34a9485228657fd177c21efdc015e..185090ddd6c475b317435c3b03711d5b890a495d 100644 (file)
@@ -158,7 +158,7 @@ gnome_player_selection()
        if (sel >= 0) sel = pickmap[sel];
        else if (sel == ROLE_NONE) {            /* Quit */
            clearlocks();
-           gnome_exit_nhwindows(0);
+           gtk_exit(0);
        }
        free(choices);
        free(pickmap);
@@ -212,7 +212,7 @@ gnome_player_selection()
            if (sel >= 0) sel = pickmap[sel];
            else if (sel == ROLE_NONE) { /* Quit */
                clearlocks();
-               gnome_exit_nhwindows(0);
+               gtk_exit(0);
            }
            flags.initrace = sel;
            free(choices);
@@ -267,7 +267,7 @@ gnome_player_selection()
            if (sel >= 0) sel = pickmap[sel];
            else if (sel == ROLE_NONE) { /* Quit */
                clearlocks();
-               gnome_exit_nhwindows(0);
+               gtk_exit(0);
            }
            flags.initgend = sel;
            free(choices);
@@ -320,7 +320,7 @@ gnome_player_selection()
            if (sel >= 0) sel = pickmap[sel];
            else if (sel == ROLE_NONE) { /* Quit */
                clearlocks();
-               gnome_exit_nhwindows(0);
+               gtk_exit(0);
            }
            flags.initalign = sel;
            free(choices);
@@ -350,7 +350,7 @@ void gnome_askname()
     /* Quit if they want to quit... */
     if (ret==-1)
       {
-        gnome_exit_nhwindows(0);
+       gtk_exit(0);
       }
 }
 
@@ -369,8 +369,7 @@ void gnome_get_nh_event()
 */
 void gnome_exit_nhwindows(const char *str)
 {
-       gtk_exit (0);
-       terminate(EXIT_SUCCESS);
+       /* gtk cannot do this without exiting the program, do nothing */
 }
 
 /* Prepare the window to be suspended. */
@@ -398,19 +397,17 @@ void gnome_resume_nhwindows()
 winid 
 gnome_create_nhwindow(int type)
 {
+    winid i = 0;
 
-  winid i = 0;
+    /* Return the next available winid */
 
-/* Return the next available winid
- */
-
-  for (i=0; i<MAXWINDOWS; i++)
-      if (gnome_windowlist[i].win == NULL)
-          break;
-  if (i == MAXWINDOWS)
-      g_error ("ERROR:  No windows available...\n");
-  gnome_create_nhwindow_by_id( type, i);
-  return i;
+    for (i=0; i<MAXWINDOWS; i++)
+       if (gnome_windowlist[i].win == NULL)
+           break;
+    if (i == MAXWINDOWS)
+       g_error ("ERROR:  No windows available...\n");
+    gnome_create_nhwindow_by_id( type, i);
+    return i;
 }
 
 void
@@ -910,8 +907,10 @@ int gnome_nhgetch()
 
     g_askingQuestion = 1;
     /* Process events until a key press event arrives. */
-    while ( g_numKeys == 0 ) 
+    while ( g_numKeys == 0 ) {
+       if (program_state.done_hup) return '\033';
        gtk_main_iteration();
+    }
     
     theFirst = g_list_first( g_keyBuffer);
     g_keyBuffer = g_list_remove_link(g_keyBuffer, theFirst);
@@ -944,8 +943,10 @@ int gnome_nh_poskey(int *x, int *y, int *mod)
     
     g_askingQuestion = 0;
     /* Process events until a key or map-click arrives. */
-    while ( g_numKeys == 0 && g_numClicks == 0 )
+    while ( g_numKeys == 0 && g_numClicks == 0 ) {
+       if (program_state.done_hup) return '\033';
        gtk_main_iteration();
+    }
     
     if (g_numKeys > 0) {
        int key;
index cb797b9531c01d8d6b0fea9c2c749a708fd185a7..973c137823b4920de762c96cc71822132c65e125 100644 (file)
@@ -58,12 +58,7 @@ getlin_hook_proc hook;
                (void) fflush(stdout);
                Sprintf(toplines, "%s ", query);
                Strcat(toplines, obufp);
-               if((c = Getchar()) == EOF) {
-#ifndef NEWAUTOCOMP
-                       *bufp = 0;
-#endif /* not NEWAUTOCOMP */
-                       break;
-               }
+               if((c = Getchar()) == EOF) c = '\033';
                if(c == '\033') {
                        *obufp = c;
                        obufp[1] = 0;
@@ -183,6 +178,11 @@ register const char *s;    /* chars allowed besides return */
 
     while((c = tty_nhgetch()) != '\n') {
        if(iflags.cbreak) {
+           if (c == EOF || c == '\033') {
+               ttyDisplay->dismiss_more = 1;
+               morc = '\033';
+               break;
+           }
            if ((s && index(s,c)) || c == x) {
                morc = (char) c;
                break;
index 1be3537514d92127b5ec460cd176c3493f59a526..2e1a90edb2384ac83641c83eab1caa68b02f93cf 100644 (file)
@@ -677,7 +677,7 @@ tty_askname()
                 wins[BASE_WINDOW]->cury - 1);
        ct = 0;
        while((c = tty_nhgetch()) != '\n') {
-               if(c == EOF) error("End of input\n");
+               if(c == EOF) c = '\033';
                if (c == '\033') { ct = 0; break; }  /* continue outer loop */
 #if defined(WIN32CON)
                if (c == '\003') bail("^C abort.\n");
@@ -2520,6 +2520,7 @@ tty_nhgetch()
     i = tgetch();
 #endif
     if (!i) i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */
+    else if (i == EOF) i = '\033'; /* same for EOF */
     if (ttyDisplay && ttyDisplay->toplin == 1)
        ttyDisplay->toplin = 2;
     return i;
@@ -2546,8 +2547,8 @@ tty_nh_poskey(x, y, mod)
     if (WIN_MESSAGE != WIN_ERR && wins[WIN_MESSAGE])
            wins[WIN_MESSAGE]->flags &= ~WIN_STOP;
     i = ntposkey(x, y, mod);
-    if (!i && mod && *mod == 0)
-       i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */
+    if (!i && mod && (*mod == 0 || *mod == EOF))
+       i = '\033'; /* map NUL or EOF to ESC, nethack doesn't expect either */
     if (ttyDisplay && ttyDisplay->toplin == 1)
                ttyDisplay->toplin = 2;
     return i;