Patch to poll the temporary file, while the external editor is
running, and upload whenever it's changed (e.g., the user saved
without exiting the editor).

Also checks environment variable "VISUAL" to see what the preferred editor is.

Josh
--- cadaver-0.22.5/src/cadaver.h	2007-01-23 06:42:52.000000000 -0800
+++ dev/src/cadaver.h	2007-06-13 17:00:38.000000000 -0700
@@ -87,6 +87,7 @@ struct command {
 
 extern char *proxy_hostname;
 extern int proxy_port;
+extern int child_waiting;
 
 struct session {
     ne_uri uri;
--- cadaver-0.22.5/src/cadaver.c	2007-01-23 06:42:52.000000000 -0800
+++ dev/src/cadaver.c	2007-06-13 17:09:20.000000000 -0700
@@ -107,6 +107,7 @@ static enum out_state {
     out_transfer_plain, /* doing a plain ... transfer */
     out_transfer_pretty /* doing a pretty progress bar transfer */
 } out_state;   
+int child_waiting;
 
 /* Protoypes */
 
@@ -741,6 +752,7 @@ static char **completion(const char *tex
 void output(enum output_type t, const char *fmt, ...)
 {
     va_list params;
+    if (child_waiting) return;
     if (t == o_finish) {
 	switch (out_state) {
 	case out_transfer_plain:
@@ -832,6 +844,7 @@ int main(int argc, char *argv[])
     int ret = 0;
     char *home = getenv("HOME"), *tmp;
 
+    child_waiting = 0;
     progname = argv[0];
 
 #ifdef HAVE_SETLOCALE
--- cadaver-0.22.5/src/edit.c	2006-02-14 10:26:30.000000000 -0800
+++ dev/src/edit.c	2007-06-13 17:35:08.000000000 -0700
@@ -23,6 +23,9 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
@@ -51,38 +54,161 @@
 #include "options.h"
 #include "i18n.h"
 
-static int run_editor(const char *filename)
+int upload_tempfile(const char *filename, const char *real_remote, int quiet) {
+   int fd, upload_okay = 0;
+
+   fd = open(filename, O_RDONLY | OPEN_BINARY_FLAGS);
+   if (fd < 0) {
+      output(o_finish, _("Could not re-open temporary file: %s\n"),
+            strerror(errno));
+   } else {
+      do {
+         if (!quiet)
+            output(o_transfer, _("Uploading changes to `%s'"), real_remote);
+         /* FIXME: conditional PUT using fetched Etag/modtime if !can_lock */
+         if (out_handle(ne_put(session.sess, real_remote, fd))) {
+            upload_okay = 1;
+         } else if (quiet) {
+            break; /* Terminate loop if non-interactive */
+         } else {
+            /* TODO: offer to save locally instead */
+            printf(_("Try uploading again (y/n)? "));
+            if (!yesno())
+               upload_okay = 1;
+         }
+      } while (!upload_okay);
+      close(fd);
+   }
+   return upload_okay;
+}
+
+/* Executes the editor. While the editor is running, checks the temp
+ * file for changes and uploads whenever changes are detected. */
+static int run_editor(const char *filename, const char *real_remote)
 {
     char editcmd[BUFSIZ];
     const char *editor;
     struct stat before_st, after_st;
+
+#ifdef HAVE_SIGNAL_H
+    pid_t child;
+    int loopstatus, childstatus;
+    struct timespec req, rem;
+#endif
+
     editor = get_option(opt_editor);
     if (editor == NULL) {
-	editor = getenv("EDITOR");
-	if (editor == NULL) {
-	    editor = "vi";
-	}
+      editor = getenv("EDITOR");
+      if (editor == NULL) {
+          editor = getenv("VISUAL");
+          if (editor == NULL) {
+              editor = "vi";
+          }
+       }
     }
+
     snprintf(editcmd, BUFSIZ, "%s %s", editor, filename);
     if (stat(filename, &before_st)) {
-	printf(_("Could not stat file: %s\n"), strerror(errno));
-	return -1;
+      printf(_("Could not stat file: %s\n"), strerror(errno));
+      return -1;
     }
+
+#ifdef HAVE_SIGNAL_H
+
+    /* Fork so that we can examine the temporary file, and upload it
+     * whenever it has been changed.  Thus the user can just do a "save"
+     * and the modifications are uploaded without their needing to
+     * exit the editor. */
+
+    /* The file will remain locked on the WebDAV server until they
+     * exit the editor. */
+
+    if (child = fork()) {
+
+       /* PARENT: check file for changes and do uploading */
+
+       child_waiting = 1;  /* Suppress normal output */
+       loopstatus = 1;
+       while (loopstatus == 1) {
+
+          /* Examine the file every 1/4 second */
+          req.tv_sec = 0;
+          req.tv_nsec = 250000000;
+          nanosleep(&req, &rem);
+
+          /* See how the child process is doing */
+          switch (waitpid(child, &childstatus, WNOHANG)) {
+             case -1:
+                /* There was an error... get out */
+                printf(_("Child error: %s\n"), strerror(errno));
+                loopstatus = -1;
+                break;
+             case 0:
+                /* Child is still running. See if the temporary file has changed. */
+                if (stat(filename, &after_st)) {
+                   printf(_("Error! Could not examine temporary file: %s\n"),
+                         strerror(errno));
+                   loopstatus = -1; /* Error termination */
+                }
+                if (before_st.st_mtime != after_st.st_mtime) {
+                   /* The file has been changed - upload */
+
+                   /* Record the new timestamp now, in case the user saves
+                    * again while we're uploading */
+                   if (stat(filename, &before_st)) {
+                     printf(_("Could not stat file: %s\n"), strerror(errno));
+                     loopstatus = -1; /* Error termination */
+                   }
+
+                   /* Upload the file */
+                   if (!upload_tempfile(filename, real_remote, 1)) {
+                      loopstatus = -1; /* Error termination */
+                   }
+                }
+                break;
+             default:
+                /* Child has terminated */
+                if (childstatus)
+                   printf(_("Editor process exited with status %d\n"),
+                         childstatus);
+                loopstatus = 0; /* Normal termination */
+          }
+       }
+       if (loopstatus == -1)
+          kill(child, SIGTERM);
+
+       /* Allow normal output again */
+       child_waiting = 0;
+    } else {
+
+       /* CHILD: run the editor, then terminate */
+
+       printf("Running editor: `%s'...\n", editcmd);
+       exit(system(editcmd));
+    }
+
+    /* post-fork */
+
+#else   /* HAVE_SIGNAL_H */
+
     printf("Running editor: `%s'...\n", editcmd);
     system(editcmd);
+
+#endif  /* HAVE_SIGNAL_H */
+
+    /* See if the file was modified as the user exited the editor */
     if (stat(filename, &after_st)) {
-	printf(_("Error! Could not examine temporary file: %s\n"), 
-		 strerror(errno));
-	return -1;
-    }
-    if (before_st.st_mtime == after_st.st_mtime) {
-	/* File not changed. */
-	printf(_("No changes were made.\n"));
-	return -1;
-    } else {
-	printf(_("Changes were made.\n"));
-	return 0;
-    }	
+      printf(_("Error! Could not examine temporary file: %s\n"),
+         strerror(errno));
+      return -1;
+    }
+
+    if (before_st.st_mtime != after_st.st_mtime)
+      /* Modified: upload one last time */
+      if (!upload_tempfile(filename, real_remote, 0))
+         return -1;
+
+    return 0;
 }
 
 /* Returns true if resource at URI is lockable. */
@@ -191,46 +317,20 @@ void execute_edit(const char *remote)
     if (close(fd)) {
 	output(o_finish, _("Error writing to temporary file: %s\n"), 
 	       strerror(errno));
-    } 
-    else if (!run_editor(fname)) {
-	int upload_okay = 0;
-
-	fd = open(fname, O_RDONLY | OPEN_BINARY_FLAGS);
-	if (fd < 0) {
-	    output(o_finish, 
-		   _("Could not re-open temporary file: %s\n"),
-		   strerror(errno));
-	} else {
-	    do {
-		output(o_transfer, _("Uploading changes to `%s'"), 
-		       real_remote);
-		/* FIXME: conditional PUT using fetched Etag/modtime if
-		 * !can_lock */
-		if (out_handle(ne_put(session.sess, real_remote, fd))) {
-		    upload_okay = 1;
-		} else {
-		    /* TODO: offer to save locally instead */
-		    printf(_("Try uploading again (y/n)? "));
-		    if (!yesno()) {
-			upload_okay = 1;
-		    }
-		}
-	    } while (!upload_okay);
-	    close(fd);
-	}
     }
-    
+    else run_editor(fname, real_remote);
+
     if (unlink(fname)) {
 	printf(_("Could not delete temporary file %s:\n%s\n"), fname,
 	       strerror(errno));
-    }	       
+    }
 
     /* Return 1: Checkin, 2: Checkout, 0: otherwise */
     is_checkout = is_vcr(real_remote);
     if (is_checkout==2) {
     	execute_checkin(real_remote);
     }
-    
+
     /* UNLOCK it again whether we succeed or failed in our mission */
     if (can_lock) {
 	output(o_start, "Unlocking `%s':", remote);
_______________________________________________
cadaver mailing list
[email protected]
http://mailman.webdav.org/mailman/listinfo/cadaver

Reply via email to