? enh-unedit_editor.diff
Index: src/ChangeLog
===================================================================
RCS file: /home/nyap/.cvsroot/cvs/src/ChangeLog,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.12.1
diff -C16 -w -r1.1.1.1 -r1.1.1.1.12.1
*** src/ChangeLog	2001/03/06 16:21:21	1.1.1.1
--- src/ChangeLog	2001/03/08 19:23:47	1.1.1.1.12.1
***************
*** 1,16 ****
--- 1,22 ----
+ 2001-03-08  Noel Yap  <yap_noel@yahoo.com>
+ 
+ 	* edit.c (unedit_fileproc, unedit, editor_set, notify_do):
+ 	"cvs unedit -e <editor>" option added to allow specification of
+ 	which editor to unedit.
+ 
  2000-09-19  Larry Jones  <larry.jones@sdrc.com>
  
  	* version.c: Version 1.11.
  
  2000-09-07  Larry Jones  <larry.jones@sdrc.com>
  
  	* Makefile.in: Use @bindir@, @libdir@, @infodir@, and @mandir@
  	from autoconf.
  
  2000-08-23  Larry Jones  <larry.jones@sdrc.com>
  
  	* mkmodules.c (init): Create an empty val-tags file if it doesn't
  	already exist to avoid problems with users not having sufficient
  	permissions to create it later.
  
  2000-09-06  Jim Kingdon  <jkingdon@dhcp-net200-89.su.valinux.com>
Index: src/edit.c
===================================================================
RCS file: /home/nyap/.cvsroot/cvs/src/edit.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.12.1
diff -C16 -w -r1.1.1.1 -r1.1.1.1.12.1
*** src/edit.c	2001/03/06 16:21:21	1.1.1.1
--- src/edit.c	2001/03/08 19:23:47	1.1.1.1.12.1
***************
*** 5,36 ****
--- 5,38 ----
     the Free Software Foundation; either version 2, or (at your option)
     any later version.
  
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.  */
  
  #include "cvs.h"
  #include "getline.h"
  #include "watch.h"
  #include "edit.h"
  #include "fileattr.h"
  
  static int watch_onoff PROTO ((int, char **));
  
+ static char *unedit_editor = NULL;
+ 
  static int setting_default;
  static int turning_on;
  
  static int setting_tedit;
  static int setting_tunedit;
  static int setting_tcommit;
  
  static int onoff_fileproc PROTO ((void *callerdat, struct file_info *finfo));
  
  static int
  onoff_fileproc (callerdat, finfo)
      void *callerdat;
      struct file_info *finfo;
  {
      fileattr_set (finfo->file, "_watched", turning_on ? "" : NULL);
      return 0;
***************
*** 445,535 ****
  
      err += send_notifications (argc, argv, local);
  
      return err;
  }
  
  static int unedit_fileproc PROTO ((void *callerdat, struct file_info *finfo));
  
  static int
  unedit_fileproc (callerdat, finfo)
      void *callerdat;
      struct file_info *finfo;
  {
      FILE *fp;
      time_t now;
      char *ascnow;
-     char *basefilename;
  
      if (noexec)
  	return 0;
  
      basefilename = xmalloc (10 + sizeof CVSADM_BASE + strlen (finfo->file));
      strcpy (basefilename, CVSADM_BASE);
      strcat (basefilename, "/");
      strcat (basefilename, finfo->file);
      if (!isfile (basefilename))
      {
  	/* This file apparently was never cvs edit'd (e.g. we are uneditting
  	   a directory where only some of the files were cvs edit'd.  */
  	free (basefilename);
  	return 0;
      }
  
      if (xcmp (finfo->file, basefilename) != 0)
      {
  	printf ("%s has been modified; revert changes? ", finfo->fullname);
  	if (!yesno ())
  	{
  	    /* "no".  */
  	    free (basefilename);
  	    return 0;
  	}
      }
      rename_file (basefilename, finfo->file);
      free (basefilename);
  
      fp = open_file (CVSADM_NOTIFY, "a");
  
      (void) time (&now);
      ascnow = asctime (gmtime (&now));
      ascnow[24] = '\0';
      fprintf (fp, "U%s\t%s GMT\t%s\t%s\t\n", finfo->file,
  	     ascnow, hostname, CurDir);
  
      if (fclose (fp) < 0)
      {
  	if (finfo->update_dir[0] == '\0')
  	    error (0, errno, "cannot close %s", CVSADM_NOTIFY);
  	else
  	    error (0, errno, "cannot close %s/%s", finfo->update_dir,
  		   CVSADM_NOTIFY);
      }
  
      /* Now update the revision number in CVS/Entries from CVS/Baserev.
         The basic idea here is that we are reverting to the revision
         that the user edited.  If we wanted "cvs update" to update
         CVS/Base as we go along (so that an unedit could revert to the
         current repository revision), we would need:
  
         update (or all send_files?) (client) needs to send revision in
         new Entry-base request.  update (server/local) needs to check
         revision against repository and send new Update-base response
         (like Update-existing in that the file already exists.  While
         we are at it, might try to clean up the syntax by having the
         mode only in a "Mode" response, not in the Update-base itself).  */
      {
  	char *baserev;
  	Node *node;
  	Entnode *entdata;
  
  	baserev = base_get (finfo);
  	node = findnode_fn (finfo->entries, finfo->file);
  	/* The case where node is NULL probably should be an error or
  	   something, but I don't want to think about it too hard right
  	   now.  */
  	if (node != NULL)
  	{
  	    entdata = (Entnode *) node->data;
  	    if (baserev == NULL)
  	    {
  		/* This can only happen if the CVS/Baserev file got
--- 447,542 ----
  
      err += send_notifications (argc, argv, local);
  
      return err;
  }
  
  static int unedit_fileproc PROTO ((void *callerdat, struct file_info *finfo));
  
  static int
  unedit_fileproc (callerdat, finfo)
      void *callerdat;
      struct file_info *finfo;
  {
      FILE *fp;
      time_t now;
      char *ascnow;
  
      if (noexec)
  	return 0;
  
+     if (unedit_editor == NULL)
+     {
+         char *basefilename = NULL;
+ 
      basefilename = xmalloc (10 + sizeof CVSADM_BASE + strlen (finfo->file));
      strcpy (basefilename, CVSADM_BASE);
      strcat (basefilename, "/");
      strcat (basefilename, finfo->file);
      if (!isfile (basefilename))
      {
  	/* This file apparently was never cvs edit'd (e.g. we are uneditting
  	   a directory where only some of the files were cvs edit'd.  */
  	free (basefilename);
  	return 0;
      }
  
      if (xcmp (finfo->file, basefilename) != 0)
      {
  	printf ("%s has been modified; revert changes? ", finfo->fullname);
  	if (!yesno ())
  	{
  	    /* "no".  */
  	    free (basefilename);
  	    return 0;
  	}
      }
      rename_file (basefilename, finfo->file);
      free (basefilename);
+     }
  
      fp = open_file (CVSADM_NOTIFY, "a");
  
      (void) time (&now);
      ascnow = asctime (gmtime (&now));
      ascnow[24] = '\0';
      fprintf (fp, "U%s\t%s GMT\t%s\t%s\t\n", finfo->file,
  	     ascnow, hostname, CurDir);
  
      if (fclose (fp) < 0)
      {
  	if (finfo->update_dir[0] == '\0')
  	    error (0, errno, "cannot close %s", CVSADM_NOTIFY);
  	else
  	    error (0, errno, "cannot close %s/%s", finfo->update_dir,
  		   CVSADM_NOTIFY);
      }
  
      /* Now update the revision number in CVS/Entries from CVS/Baserev.
         The basic idea here is that we are reverting to the revision
         that the user edited.  If we wanted "cvs update" to update
         CVS/Base as we go along (so that an unedit could revert to the
         current repository revision), we would need:
  
         update (or all send_files?) (client) needs to send revision in
         new Entry-base request.  update (server/local) needs to check
         revision against repository and send new Update-base response
         (like Update-existing in that the file already exists.  While
         we are at it, might try to clean up the syntax by having the
         mode only in a "Mode" response, not in the Update-base itself).  */
+     if (unedit_editor == NULL)
      {
  	char *baserev;
  	Node *node;
  	Entnode *entdata;
  
  	baserev = base_get (finfo);
  	node = findnode_fn (finfo->entries, finfo->file);
  	/* The case where node is NULL probably should be an error or
  	   something, but I don't want to think about it too hard right
  	   now.  */
  	if (node != NULL)
  	{
  	    entdata = (Entnode *) node->data;
  	    if (baserev == NULL)
  	    {
  		/* This can only happen if the CVS/Baserev file got
***************
*** 551,606 ****
  		return 0;
  	    }
  	    Register (finfo->entries, finfo->file, baserev, entdata->timestamp,
  		      entdata->options, entdata->tag, entdata->date,
  		      entdata->conflict);
  	}
  	free (baserev);
  	base_deregister (finfo);
      }
  
      xchmod (finfo->file, 0);
      return 0;
  }
  
  static const char *const unedit_usage[] =
  {
!     "Usage: %s %s [-lR] [files...]\n",
      "-l: Local directory only, not recursive\n",
      "-R: Process directories recursively\n",
      "(Specify the --help global option for a list of other help options)\n",
      NULL
  };
  
  int
  unedit (argc, argv)
      int argc;
      char **argv;
  {
      int local = 0;
      int c;
      int err;
  
      if (argc == -1)
  	usage (unedit_usage);
  
      optind = 0;
!     while ((c = getopt (argc, argv, "+lR")) != -1)
      {
  	switch (c)
  	{
  	    case 'l':
  		local = 1;
  		break;
  	    case 'R':
  		local = 0;
  		break;
  	    case '?':
  	    default:
  		usage (unedit_usage);
  		break;
  	}
      }
      argc -= optind;
      argv += optind;
  
      /* No need to readlock since we aren't doing anything to the
--- 558,617 ----
  		return 0;
  	    }
  	    Register (finfo->entries, finfo->file, baserev, entdata->timestamp,
  		      entdata->options, entdata->tag, entdata->date,
  		      entdata->conflict);
  	}
  	free (baserev);
  	base_deregister (finfo);
      }
  
      xchmod (finfo->file, 0);
      return 0;
  }
  
  static const char *const unedit_usage[] =
  {
!     "Usage: %s %s [-lR] [-e editor] [files...]\n",
      "-l: Local directory only, not recursive\n",
      "-R: Process directories recursively\n",
+     "-e editor\tSpecify editor\n",
      "(Specify the --help global option for a list of other help options)\n",
      NULL
  };
  
  int
  unedit (argc, argv)
      int argc;
      char **argv;
  {
      int local = 0;
      int c;
      int err;
  
      if (argc == -1)
  	usage (unedit_usage);
  
      optind = 0;
!     while ((c = getopt (argc, argv, "+lRe:")) != -1)
      {
  	switch (c)
  	{
+             case 'e':
+                 unedit_editor = optarg;
+                 break;
  	    case 'l':
  		local = 1;
  		break;
  	    case 'R':
  		local = 0;
  		break;
  	    case '?':
  	    default:
  		usage (unedit_usage);
  		break;
  	}
      }
      argc -= optind;
      argv += optind;
  
      /* No need to readlock since we aren't doing anything to the
***************
*** 629,681 ****
      strcat (base, file);
      if (unlink_file (base) < 0 && ! existence_error (errno))
  	error (0, errno, "cannot remove %s", file);
      free (base);
  }
  
  
  void
  editor_set (filename, editor, val)
      char *filename;
      char *editor;
      char *val;
  {
      char *edlist;
      char *newlist;
  
      edlist = fileattr_get0 (filename, "_editors");
      newlist = fileattr_modify (edlist, editor, val, '>', ',');
      /* If the attributes is unchanged, don't rewrite the attribute file.  */
      if (!((edlist == NULL && newlist == NULL)
  	  || (edlist != NULL
  	      && newlist != NULL
  	      && strcmp (edlist, newlist) == 0)))
  	fileattr_set (filename, "_editors", newlist);
      if (edlist != NULL)
  	free (edlist);
      if (newlist != NULL)
  	free (newlist);
  }
  
  struct notify_proc_args {
      /* What kind of notification, "edit", "tedit", etc.  */
      char *type;
      /* User who is running the command which causes notification.  */
!     char *who;
      /* User to be notified.  */
      char *notifyee;
      /* File.  */
      char *file;
  };
  
  /* Pass as a static until we get around to fixing Parse_Info to pass along
     a void * where we can stash it.  */
  static struct notify_proc_args *notify_args;
  
  static int notify_proc PROTO ((char *repository, char *filter));
  
  static int
  notify_proc (repository, filter)
      char *repository;
      char *filter;
  {
      FILE *pipefp;
--- 640,699 ----
      strcat (base, file);
      if (unlink_file (base) < 0 && ! existence_error (errno))
  	error (0, errno, "cannot remove %s", file);
      free (base);
  }
  
  
  void
  editor_set (filename, editor, val)
      char *filename;
      char *editor;
      char *val;
  {
      char *edlist;
      char *newlist;
  
+     if (unedit_editor != NULL)
+     {
+         editor = unedit_editor;
+     }
+ 
      edlist = fileattr_get0 (filename, "_editors");
      newlist = fileattr_modify (edlist, editor, val, '>', ',');
      /* If the attributes is unchanged, don't rewrite the attribute file.  */
      if (!((edlist == NULL && newlist == NULL)
  	  || (edlist != NULL
  	      && newlist != NULL
  	      && strcmp (edlist, newlist) == 0)))
  	fileattr_set (filename, "_editors", newlist);
      if (edlist != NULL)
  	free (edlist);
      if (newlist != NULL)
  	free (newlist);
  }
  
  struct notify_proc_args {
      /* What kind of notification, "edit", "tedit", etc.  */
      char *type;
      /* User who is running the command which causes notification.  */
!     char *notifier;
      /* User to be notified.  */
      char *notifyee;
+     /* Editor affected */
+     char *editor;
      /* File.  */
      char *file;
  };
  
  /* Pass as a static until we get around to fixing Parse_Info to pass along
     a void * where we can stash it.  */
  static struct notify_proc_args *notify_args;
  
  static int notify_proc PROTO ((char *repository, char *filter));
  
  static int
  notify_proc (repository, filter)
      char *repository;
      char *filter;
  {
      FILE *pipefp;
***************
*** 717,749 ****
      {
  	free (prog);
  	return 1;
      }
  
      pipefp = run_popen (expanded_prog, "w");
      if (pipefp == NULL)
      {
  	error (0, errno, "cannot write entry to notify filter: %s", prog);
  	free (prog);
  	free (expanded_prog);
  	return 1;
      }
  
      fprintf (pipefp, "%s %s\n---\n", srepos, args->file);
      fprintf (pipefp, "Triggered %s watch on %s\n", args->type, repository);
!     fprintf (pipefp, "By %s\n", args->who);
  
      /* Lots more potentially useful information we could add here; see
         logfile_write for inspiration.  */
  
      free (prog);
      free (expanded_prog);
      return (pclose (pipefp));
  }
  
  /* FIXME: this function should have a way to report whether there was
     an error so that server.c can know whether to report Notified back
     to the client.  */
  void
  notify_do (type, filename, who, val, watches, repository)
      int type;
      char *filename;
--- 735,772 ----
      {
  	free (prog);
  	return 1;
      }
  
      pipefp = run_popen (expanded_prog, "w");
      if (pipefp == NULL)
      {
  	error (0, errno, "cannot write entry to notify filter: %s", prog);
  	free (prog);
  	free (expanded_prog);
  	return 1;
      }
  
      fprintf (pipefp, "%s %s\n---\n", srepos, args->file);
      fprintf (pipefp, "Triggered %s watch on %s\n", args->type, repository);
!     fprintf (pipefp, "By %s\n", args->notifier);
! 
!     if(args->editor != NULL && strcmp(args->editor, "") != 0)
!     {
!         fprintf (pipefp, "For %s\n", args->editor);
!     }
  
      /* Lots more potentially useful information we could add here; see
         logfile_write for inspiration.  */
  
      free (prog);
      free (expanded_prog);
      return (pclose (pipefp));
  }
  
  /* FIXME: this function should have a way to report whether there was
     an error so that server.c can know whether to report Notified back
     to the client.  */
  void
  notify_do (type, filename, who, val, watches, repository)
      int type;
      char *filename;
***************
*** 908,940 ****
  		if (fclose (fp) < 0)
  		    error (0, errno, "cannot close %s", usersname);
  	    }
  	    free (usersname);
  	    if (line != NULL)
  		free (line);
  
  	    if (args.notifyee == NULL)
  	    {
  		args.notifyee = xmalloc (endp - p + 1);
  		strncpy (args.notifyee, p, endp - p);
  		args.notifyee[endp - p] = '\0';
  	    }
  
  	    notify_args = &args;
  	    args.type = notif;
! 	    args.who = who;
  	    args.file = filename;
  
  	    (void) Parse_Info (CVSROOTADM_NOTIFY, repository, notify_proc, 1);
  	    free (args.notifyee);
  	}
  
  	p = nextp;
      }
      if (watchers != NULL)
  	free (watchers);
  
      switch (type)
      {
  	case 'E':
  	    if (*watches == 'E')
  	    {
--- 931,964 ----
  		if (fclose (fp) < 0)
  		    error (0, errno, "cannot close %s", usersname);
  	    }
  	    free (usersname);
  	    if (line != NULL)
  		free (line);
  
  	    if (args.notifyee == NULL)
  	    {
  		args.notifyee = xmalloc (endp - p + 1);
  		strncpy (args.notifyee, p, endp - p);
  		args.notifyee[endp - p] = '\0';
  	    }
  
  	    notify_args = &args;
  	    args.type = notif;
! 	    args.notifier = who;
!             args.editor = unedit_editor;
  	    args.file = filename;
  
  	    (void) Parse_Info (CVSROOTADM_NOTIFY, repository, notify_proc, 1);
  	    free (args.notifyee);
  	}
  
  	p = nextp;
      }
      if (watchers != NULL)
  	free (watchers);
  
      switch (type)
      {
  	case 'E':
  	    if (*watches == 'E')
  	    {
Index: src/version.c
===================================================================
RCS file: /home/nyap/.cvsroot/cvs/src/version.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.12.1
diff -C16 -w -r1.1.1.1 -r1.1.1.1.12.1
*** src/version.c	2001/03/06 16:21:21	1.1.1.1
--- src/version.c	2001/03/08 19:23:47	1.1.1.1.12.1
***************
*** 1,31 ****
  /*
   * Copyright (c) 1994 david d `zoo' zuhn
   * Copyright (c) 1994 Free Software Foundation, Inc.
   * Copyright (c) 1992, Brian Berliner and Jeff Polk
   * Copyright (c) 1989-1992, Brian Berliner
   * 
   * You may distribute under the terms of the GNU General Public License as
   * specified in the README file that comes with this  CVS source distribution.
   * 
   * version.c - the CVS version number
   */
  
  #include "cvs.h"
  
! char *version_string = "Concurrent Versions System (CVS) 1.11";
  
  #ifdef CLIENT_SUPPORT
  #ifdef SERVER_SUPPORT
  char *config_string = " (client/server)\n";
  #else
  char *config_string = " (client)\n";
  #endif
  #else
  #ifdef SERVER_SUPPORT
  char *config_string = " (server)\n";
  #else
  char *config_string = "\n";
  #endif
  #endif
  
  static const char *const version_usage[] =
--- 1,31 ----
  /*
   * Copyright (c) 1994 david d `zoo' zuhn
   * Copyright (c) 1994 Free Software Foundation, Inc.
   * Copyright (c) 1992, Brian Berliner and Jeff Polk
   * Copyright (c) 1989-1992, Brian Berliner
   *
   * You may distribute under the terms of the GNU General Public License as
   * specified in the README file that comes with this  CVS source distribution.
   *
   * version.c - the CVS version number
   */
  
  #include "cvs.h"
  
! char *version_string = "Concurrent Versions System (CVS) 1.11 (unedit editor)";
  
  #ifdef CLIENT_SUPPORT
  #ifdef SERVER_SUPPORT
  char *config_string = " (client/server)\n";
  #else
  char *config_string = " (client)\n";
  #endif
  #else
  #ifdef SERVER_SUPPORT
  char *config_string = " (server)\n";
  #else
  char *config_string = "\n";
  #endif
  #endif
  
  static const char *const version_usage[] =
***************
*** 59,75 ****
      if (client_active)
      {
  	(void) fputs ("Server: ", stdout);
  	start_server ();
  	if (supported_request ("version"))
  	    send_to_server ("version\012", 0);
  	else
  	{
  	    send_to_server ("noop\012", 0);
  	    fputs ("(unknown)\n", stdout);
  	}
  	err = get_responses_and_close ();
      }
  #endif
      return err;
  }
- 	
--- 59,74 ----
