Index: src/README.RSE
===================================================================
RCS file: src/README.RSE
diff -N src/README.RSE
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/README.RSE	28 Dec 2002 11:23:25 -0000
@@ -0,0 +1,338 @@
+
+  CVS RSE Patches
+  ===============
+
+  This is the patched version of CVS from Ralf S. Engelschall
+  <rse@engelschall.com> - an enhanced version of the official CVS
+  version 1.11.4 (see http://www.cvshome.org/).
+
+  The following changes against the vendor CVS version are provided:
+    - new `cvs pserverd' for running stand-alone pserver daemons
+    - support for an `admininfo' hook to ACL `cvs admin' commands.
+    - support for an `importinfo' hook to ACL `cvs import' commands.
+    - support for a `-h<handle>' option to `cvs diff' for compressed time spec.
+    - allow a hard-coded CVS super-user to override the CVS user via $CVSUSER
+    - support for .cvsrc files in both $HOME and working and its parent dirs
+    - support for $HOME/.cvsroot to alias CVSROOTs and to support root mirrors 
+    - support global but command specific options in .cvsrc files
+    - support for stand-alone external custom commands `cvs <command>'
+    - support for prolog and epilog command line hooks 
+    - support `$LocalId$, a local keyword variant of `$Id$' 
+    - support `$CVSHeader$, a variant of `$Header$', but without root path
+    - new `cvs -u' option in addition to `cvs -n' for _REAL_ read-only access
+    - support for additional `%x' variables on `loginfo' hook command lines
+    - support a `UMask=<mask>' variable in `$CVSROOT/CVSROOT/config'
+    - speeded up `cvs update' by sending whole file if smaller than the diff
+    - disabled keyword expansions during branch merges 
+    - adjusted `cvs diff -rHEAD' to be consistent with other commands
+    - set `$LOGNAME' to the real user and not the CVS user
+    - support for `HistoryFile=<rel-path-under-CVSROOT>' variable in config.
+    - use prefix 'T' ("touched/tagged") instead of 'U' ("updated") on `cvs import'
+    - allow `LockDir' configuration directive to use relative paths
+    - additional SetUID/SetGID support for `cvs server' situations.
+    - new global --map-root=/oldpath:/newpath option for mapping root paths
+    - support for wildcards in CVSROOT/passwd files to decrease admin efforts
+    - various cosmetic changes
+
+  Some of my RSE functional patches are only useful for the server side,
+  others are also useful on the client side. All source patches to
+  *.[ch] files were entirely wrapped with ``#ifdef RSE_PATCH_<NAME> ...
+  #endif'' pairs. So, a particular patch is enabled by building CVS with
+  -DRSE_PATCH_<NAME>. All patches are enabled with -DRSE_PATCHES.
+
+                                       Ralf S. Engelschall
+                                       rse@engelschall.com
+                                       www.engelschall.com
+  ________________________________________________________________________
+
+  The following particular patches are available:
+
+  RSE_PATCH_CVSRC:
+    In addition to processing `$HOME/.cvsrc', process also `.cvsrc'
+    files in the current working directory and the parent directories of
+    the current working directory. This allows one to use for instance a
+    `commit -m ""' locally (as used for GNU Pth development where CVS is
+    only used for plain revision control and not for bookkeeping changes
+    or group communication - instead a plain manually edited ChangeLog
+    exists) or `commit -d <master>' (if working with a local repository
+    copy). Additionally this adds support for quoted strings inside
+    .cvsrc files.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_CVSROOT:
+    This adds support for a new dot-file ~/.cvsroot which is used
+    optionally by CVS. It can be used by the user to configure a
+    nickname for a CVS repository root (the master location) plus a
+    possibly existing local repository copy (the slave location). An
+    entry in ~/.cvsroot is of the format ``<nickname> <master-path>
+    [<slave-path> [<sync-prog>]]''. Those entries can be either created
+    manually in ~/.cvsroot or with the `cvs root -e' command.
+    
+    The idea is this: if a global `-d' option is used with <nickname> it is
+    automatically expanded to <master-path>. If no global `-d' option is used,
+    the CVS command is checked. If it is one of the commands which are known
+    to CVS to modify the repository, and the $CVSROOT or CVS/Root specify a
+    slave location, the repository is switched to the corresponding master
+    location (because modifications have to be performed there).  If the
+    command is one of the commands which are known to CVS to NOT modify the
+    repository, and the $CVSROOT or CVS/Root specify a master location, the
+    repository is switched to the corresponding slave location (because the
+    slave location is faster than the master location per definition).
+    
+    After a modifying operation, CVS can either run a synchronization job
+    automatically to bring slave in sync with master again or the user can run
+    `cvs root -s <nickname>' manually to perform this task.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_GLOBALOPTION:
+  RSE_PATCH_GLOBALOPTION_PARTLY:
+    By default, global options in `.cvsrc' files are specified with a
+    `cvs' prefix. These options then apply to _all_ cvs commands. If
+    RSE_PATCH_GLOBALOPTION is enabled, a second pass is done where all
+    global options are read with prefix `cvs/<command>' where <command>
+    is the official cvs command (for instance `commit' or `checkout',
+    even if `ci' or `co' are used on the command line). This is useful
+    for instance to override CVSROOT in commit commands if using a local
+    repository copy. The drawback of this feature is that it obviously
+    slows down cvs calls, because a second pass has to be done. But
+    usually this feature is intended only for use with `commit', `tag',
+    `rtag', `history', `admin', `import' and `rdiff' commands, so if
+    RSE_PATCH_GLOBALOPTION_PARTLY is additionally enabled, this second
+    pass is only done for those commands (which is the recommended use
+    of this feature).
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_CUSTOMCMD:
+    This provides an additional global option `-C
+    <cmd-name>:<cmd-program>' which defines an additional CVS command
+    <cmd-name>. It is intended for use on `cvs' lines inside .cvsrc
+    files. The effect of having `cvs -Csync:$CVSROOT/CVSROOT/sync' in a
+    .cvsrc file is (and assuming $CVSROOT is /e/ossp/cvs) that if you
+    run `cvs sync <arg1> <arg2>', CVS executes `/e/ossp/cvs/CVSROOT/sync
+    <arg1> <arg2>'. So this is a way to externally extend CVS with
+    additional commands.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_PROLOGEPILOG:
+    Provides the two additional CVS options `-P <program>' and `-E
+    <program>' for running prolog and epilog programs before and
+    after the usual CVS processing. This is mainly intended as local
+    hooks for implicitly wrapping CVS commands (without having to
+    create slow wrapping shell scripts, etc.). Developers usually
+    use it to automatically start their RSYNC command to update the
+    local repository copy after a commit. The <program> is called
+    with four arguments: $1 is either `prolog' or `epilog' (useful
+    if one just wants to use a single hook program), $2 is the cvs
+    command (it is `commit' even `ci' is used, etc.), $3 is the current
+    working directory from which the cvs command was run and $4 is the
+    corresponding $CVSROOT variable.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_LOCALID:
+    Support a local keyword variant of `$Id$'. By default this is
+    `$LocalId$', but if -DRSE_PATCH_LOCALID_NAME=\"<name>\" is
+    additionally defined, then the keyword is `$<name>$'. Alternatively
+    one can define the name also in the `$CVSROOT/CVSROOT/config' file
+    with `LocalIdName=<name>'.
+    [Origin: NetBSD, OpenBSD, Ralf S. Engelschall]
+
+  RSE_PATCH_CVSHEADER:
+    Support the `$CVSHeader' variant of `$Header$' which has the
+    $CVSROOT prefix stripped of from the path. This is useful because
+    the prefix usually useless outside the server environment.
+    [Origin: FreeBSD]
+
+  RSE_PATCH_NOLOCK:
+    Provide a `cvs -u' option in addition to `cvs -n' to force CVS to
+    not create any lock files in the repository. This is for supporting
+    read-only access to the repository. This is useful for working
+    with CVS repositories on CD-ROMs and for providing anonymous CVS
+    services.
+    [Origin: NetBSD]
+
+  RSE_PATCH_EXTRAPERCENT:
+    This adds extra percent expansions to `loginfo' command lines:
+    `%o' to expand the operation (`A' = added, `M' = modified, `R' =
+    removed), `%t' to expand the tag, `%d' to expand the date.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_READDNEW:
+    If a file was re-added to the repository, log the revision in the
+    `commitlog' as `NONE' instead of the previous dead revision.
+    [Origin: NetBSD]
+
+  RSE_PATCH_CONFIGUMASK:
+    Provide a `UMask=<mask>' variable in `$CVSROOT/CVSROOT/config' which
+    overrides the umask of the CVS server process.
+    [Origin: OpenBSD]
+
+  RSE_PATCH_FASTERUPDATE:
+    This speeds up `cvs update' by sending the whole file over the
+    network if it is smaller than the diff content. This is useful for
+    working remotely over slow Internet links.
+    [Origin: OpenBSD]
+
+  RSE_PATCH_MERGENOKEYWORD:
+    This disables keyword expansions during branch merges which is
+    very useful in long-term branching. Without this the so-called
+    `spurious merging conflicts' occur because the keywords cause
+    spurious conflicts on every merge after the first (if those text
+    files have been modified on the trunk since the previous merge out
+    to the branch).
+    [Origin: Jay Sachs <jsachs@iclick.com>]
+
+  RSE_PATCH_DIFFHEAD:
+    This patch changes the behavior of `cvs diff -rHEAD' on branches.
+    HEAD here now behaves with as it does with all other CVS commands,
+    as a name for the head of the trunk (the old behavior of `cvs diff
+    -rHEAD' was to treat HEAD to mean the head of the branch, while all
+    the other commands already treated HEAD as the head of the trunk).
+    [Origin: Stephen Cameron <steve.cameron@compaq.com>]
+
+  RSE_PATCH_LOGNAME:
+    This is for SUID-based CVS servers and passes in `$LOGNAME' the real
+    user (first field in `$CVSROOT/CVSROOT/passwd') instead of the SUID
+    user (third field in `$CVSROOT/CVSROOT/passwd')
+    [Origin: Chris Cameron]
+
+  RSE_PATCH_HISTORYFILE:
+    This provides an additional `HistoryFile=<rel-path-under-CVSROOT>'
+    config variable which allows one to store the history file under a
+    different path.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_SMARTCONFIG:
+    This allows one to add custom configuration variables to
+    `$CVSROOT/CVSROOT/config' without having CVS complain about them and
+    fail with an error. This is useful to use the config file also for
+    storing config details for the various admin scripts.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_ADMININFO:
+    This adds the feature of an extra `$CVSROOT/CVSROOT/admininfo'
+    configuration file which can be used for access controlling `cvs
+    admin' commands similar to `cvs tag' (which is already done
+    with `taginfo') and `cvs commit' (which is already done with
+    `commitinfo'). The specified filters in this info file receive the
+    absolute repository directory as the first argument, followed by all
+    names of files in this directory on which the `cvs admin' command
+    should be performed. If the filter returns 0, the operation is
+    allowed. If it returns not 0, the operation is denied.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_IMPORTINFO:
+    This adds the feature of an extra `$CVSROOT/CVSROOT/importinfo'
+    configuration file which can be used for access controlling
+    `cvs import'. The specified filters in this info file receives
+    the following arguments: the vendor branch tag, the (absolute)
+    repository path which is the root of the import and then zero or
+    more relative file paths under this repository. If the filter
+    returns 0, the operation is allowed. If it returns not 0, the
+    operation is denied.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_HANDLE:
+    This adds a convinient `-h<handle>' option to `cvs diff'. `<handle>'
+    is a string of the format `[!]YYMMDDhhmmssoo' (YY=year, MM=month,
+    DD=day, hh=hour, mm=minute, ss=second, oo=offset) which internally
+    is expanded into two `-D' options. The first date is the equivalent
+    of `YYMMDDhhmmss', the second is the first plus `oo' seconds. If the
+    exclamation mark is used, the two dates are reversed. The intention
+    is that such a handle is a short form for a time range and can be
+    easily computed in a commit log mail. So the `-h' option can be used
+    to easily get the corresponding change diff for branch merging or
+    backing out. The only restriction is that time-overlapping commits
+    break the solution, of course. But in practice this is no real
+    problem.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_IMPORTTOUCH:
+    This prints the prefix 'T' (for "touched/tagged only") instead
+    of 'U' (for "updated") on `cvs import' if no modifications were
+    imported, i.e., no new revision is comitted. This way one can
+    distinguish those imports from the regular updated ones which also
+    print 'U' and which actually commit a new revision.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_RELLOCKDIR:
+    This allows the `LockDir' configuration directive to use relative
+    paths to $CVSROOT, because without this patch a relative path would
+    be relative to the current working directory (which is useless).
+    [Origin: Stefan Monnier <foo@acm.com>]
+
+  RSE_PATCH_CVSUSER:
+    This allows the Unix user RSE_PATCH_CVSUSER_CALLER (per default
+    "ossp-cvs") to use the environment variable CVSUSER to override the
+    login name CVS uses to identify the caller. This is intended for use
+    with a CVS setuid wrapper program or for use manually by the CVS
+    administrator.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_SETXID:
+    This is a variant of CVS's SETXID_SUPPORT. It allows one to
+    setuid/setgid the CVS executable. Then CVS deletes these effective
+    uid/gid for all commands except for the "cvs server" command. For
+    this and only this it switches the real uid/gid to the effective
+    uid/gid. This way one can use the repository as a black-box. One
+    just has to be make sure that only :ext: (for remote) and :fork:
+    (for local) access is used.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_PSERVERD:
+    This adds an additional `cvs pserverd' command which is like `cvs
+    pserver' except that it uses own builtin TCP/IP socket listening and
+    forking facility. The advantages over using inetd are: pserverd can
+    listen to particular host addresses/ports (inetd always binds to all
+    interfaces of a host), it can optionally chroot(2) for a particular
+    user only (usually "anonymous"), it can optionally force the global
+    options -l -u for a particular user only (usually "anonymous"), it
+    can detach into background and run as a real daemon, etc.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_MAPROOT
+    This adds a global --map-root=/oldpath:/newpath option which
+    allows one to map virtual/incoming CVSROOT values to real ones.
+    For instance this can be used together with --allow-root and "cvs
+    pserverd" to map the intuitive virtual path to the physical path on
+    the host.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_HASHFUNC:
+    This replaces the obscure hash function in src/hash.c with D.J.Berstein's
+    popular "times 33" function which is faster to compute and still
+    distributes very well.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_ADDFILEATTR:
+    Let the default file attributes set on newly added files.
+    [Origin: Noel Yap]
+
+  RSE_PATCH_WILDPASSWD:
+    This allows wildcards ("*") in CVSROOT/passwd. That allows one to
+    just do "*:ULtgRLXo7NRxs:cvsuser" which would let absolutely anyone
+    use CVS provided they know the password. It would also let you do
+    things like "*:*:cvsuser" to let only authorized system users use
+    CVS using their system passwords.
+    [Larry Jones <larry.jones@sdrc.com>]
+
+  RSE_PATCH_CVSPID:
+    This provides an environment variable $CVSPID which contains the process
+    id of the parent CVS process. This is usually used inside scripts called
+    from *info files in order to have a unique session handle (for instance
+    for a common temporary directory "/tmp/cvs.foo.$CVSPID", etc).
+    [Origin: Rich Salz <rsalz@caveosystems.com>]
+
+  RSE_PATCH_BUGFIX:
+    This enabled various bugfixes which are still not present in the
+    official CVS version.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_COSMETICS:
+    This just enables some cosmetic changes to various output messages.
+    [Origin: Ralf S. Engelschall]
+
+  RSE_PATCH_COSMETICS_HARD:
+    This just enables more cosmetic changes to various output messages.
+    The difference is that these break "make check".
+    [Origin: Ralf S. Engelschall]
+
Index: src/add.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/add.c,v
retrieving revision 1.1.1.5
diff -u -d -r1.1.1.5 add.c
--- src/add.c	24 Oct 2002 18:38:36 -0000	1.1.1.5
+++ src/add.c	28 Dec 2002 10:48:11 -0000
@@ -799,6 +799,9 @@
 	li->type = T_TITLE;
 	li->tag = xstrdup (tag);
 	li->rev_old = li->rev_new = NULL;
+#ifdef RSE_PATCH_EXTRAPERCENT
+	li->date = NULL;
+#endif
 	p->data = (char *) li;
 	(void) addnode (ulist, p);
 	Update_Logfile (rcsdir, message, (FILE *) NULL, ulist);
Index: src/admin.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/admin.c,v
retrieving revision 1.1.1.7
diff -u -d -r1.1.1.7 admin.c
--- src/admin.c	28 Dec 2002 18:01:30 -0000	1.1.1.7
+++ src/admin.c	28 Dec 2002 20:14:05 -0000
@@ -139,6 +139,161 @@
     dat->av[dat->ac++] = newelt;
 }
 
+#ifdef RSE_PATCH_ADMININFO
+
+static List *admininfo_dlist;
+static List *admininfo_flist;
+
+static void admininfo_dlist_delproc(Node *);
+static int  admininfo_info_runproc(char *, char *);
+static int  admininfo_flist_runproc(Node *, void *);
+
+struct admininfo_dlist_st { 
+    List *flist; 
+};
+
+/* file callback function for recursive processing */
+static int
+admininfo_fileproc (
+    void *callerdat,
+    struct file_info *finfo)
+{
+    char *xdir;
+    Node *dnode;
+    Node *fnode;
+    
+    /* determine current directory */
+    if (finfo->update_dir[0] == '\0')
+        xdir = ".";
+    else
+        xdir = finfo->update_dir;
+
+    /* find directory node in directory list */
+    if ((dnode = findnode(admininfo_dlist, xdir)) != NULL)
+        /* take already existing file list */
+        admininfo_flist = ((struct admininfo_dlist_st *)dnode->data)->flist;
+    else {
+        /* create a new file list */
+        struct admininfo_dlist_st *dlist;
+
+        admininfo_flist = getlist();
+
+        dlist = (struct admininfo_dlist_st *)xmalloc(sizeof(struct admininfo_dlist_st));
+        dlist->flist = admininfo_flist;
+
+        dnode = getnode();
+        dnode->type = UPDATE;
+        dnode->key = xstrdup(xdir);
+        dnode->data = (char *)dlist;
+        dnode->delproc = admininfo_dlist_delproc;
+
+        (void)addnode(admininfo_dlist, dnode);
+    }
+
+    /* create new file node in file list */
+    fnode = getnode();
+    fnode->type = UPDATE;
+    fnode->key = xstrdup(finfo->file);
+    fnode->data = NULL;
+    fnode->delproc = NULL;
+    (void)addnode(admininfo_flist, fnode);
+
+    return 0;
+}
+
+/* delete a directory list node */
+static void
+admininfo_dlist_delproc(
+    Node *p)
+{
+    struct admininfo_dlist_st *dlist;
+
+    dlist = (struct admininfo_dlist_st *)p->data;
+    dellist(&dlist->flist);
+    free(dlist);
+    return;
+}
+
+/* file callback function for recursive processing (when done) */
+static int
+admininfo_filesdoneproc(
+    void *callerdat,
+    int err,
+    char *repos,
+    char *update_dir,
+    List *entries)
+{
+    Node *dnode;
+    int n;
+
+    /* find file list for update directory */
+    if ((dnode = findnode(admininfo_dlist, update_dir)) != NULL)
+        admininfo_flist = ((struct admininfo_dlist_st *)dnode->data)->flist;
+    else
+        admininfo_flist = (List *)NULL;
+    if (   (admininfo_flist == NULL) 
+        || (admininfo_flist->list->next == admininfo_flist->list))
+        return err;
+
+    /* parse and execute the admininfo configuration */
+    if ((n = Parse_Info(CVSROOTADM_ADMININFO, repos, admininfo_info_runproc, 1)) > 0) {
+        error(0, 0, "Pre-admin check failed");
+        err += n;
+    }
+
+    return err;
+}
+
+/* admininfo configuration entry callback */
+static int
+admininfo_info_runproc(repository, filter)
+    char *repository;
+    char *filter;
+{
+    char *s, *cp;
+    int rv;
+
+    /* if possible, do an own check to make sure that filter really exists */
+    if (filter[0] == '/') {
+        s = xstrdup(filter);
+        for (cp = s; *cp; cp++) {
+            if (isspace((unsigned char)*cp)) {
+                *cp = '\0';
+                break;
+            }
+        }
+        if (!isfile(s)) {
+            error (0, errno, "cannot find pre-admin filter '%s'", s);
+            free(s);
+            return (1);
+        }
+        free(s);
+    }
+
+    /* construct the filter command */
+    run_setup(filter);
+    run_arg(repository);
+    walklist(admininfo_flist, admininfo_flist_runproc, NULL);
+
+    /* execute the filter command */
+    rv = run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+
+    return rv;
+}
+
+/* file list callback for adding file as another program argument */
+static int
+admininfo_flist_runproc(
+    Node *p,
+    void *closure)
+{
+    if (p->key != NULL)
+        run_arg(p->key);
+    return 0;
+}
+
+#endif /* RSE_PATCH_ADMININFO */
+
 int
 admin (argc, argv)
     int argc;
@@ -516,6 +671,20 @@
 #endif /* CLIENT_SUPPORT */
 
     lock_tree_for_write (argc, argv, 0, W_LOCAL, 0);
+
+#ifdef RSE_PATCH_ADMININFO
+    /* allow `CVSROOT/CVSROOT/admininfo' filters to check whether the
+       `cvs admin' operation is authorized for all the specified files
+       in the repository */
+    admininfo_dlist = getlist();
+    err = start_recursion(admininfo_fileproc, admininfo_filesdoneproc,
+                          (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
+                          argc, argv, 0, W_LOCAL, 0, 0, (char *)NULL, 1);
+    if (err) {
+        Lock_Cleanup();
+        error(1, 0, "correct above errors first!");
+    }
+#endif
 
     err = start_recursion (admin_fileproc, (FILESDONEPROC) NULL, admin_dirproc,
 			   (DIRLEAVEPROC) NULL, (void *)&admin_data,
Index: src/buffer.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/buffer.c,v
retrieving revision 1.1.1.3
diff -u -d -r1.1.1.3 buffer.c
--- src/buffer.c	6 Dec 2002 19:47:58 -0000	1.1.1.3
+++ src/buffer.c	28 Dec 2002 10:48:12 -0000
@@ -1381,7 +1381,7 @@
     int closefp = 1;
 
     /* Must be a pipe or a socket.  What could go wrong? */
-    assert (fstat ( fileno (bc->fp), &s ) != -1);
+    assert (fstat ( fileno (bc->fp), &s ) != -1); /* RSE XXX */
 
     /* Flush the buffer if we can */
     if (buf->flush)
Index: src/checkin.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/checkin.c,v
retrieving revision 1.1.1.1
diff -u -d -r1.1.1.1 checkin.c
--- src/checkin.c	22 Feb 1998 19:46:46 -0000	1.1.1.1
+++ src/checkin.c	16 Feb 2002 12:36:09 -0000
@@ -32,14 +32,27 @@
     Vers_TS *vers;
     int set_time;
     char *tocvsPath = NULL;
+#ifdef RSE_PATCH_COSMETICS_HARD
+    int flags;
+#endif
 
     /* Hmm.  This message goes to stdout and the "foo,v  <--  foo"
        message from "ci" goes to stderr.  This doesn't make a whole
        lot of sense, but making everything go to stdout can only be
        gracefully achieved once RCS_checkin is librarified.  */
+#ifdef RSE_PATCH_COSMETICS_HARD
+    if (!really_quiet) {
+#endif
     cvs_output ("Checking in ", 0);
     cvs_output (finfo->fullname, 0);
+#ifdef RSE_PATCH_COSMETICS_HARD
+    cvs_output ("\n", 0);
+#else
     cvs_output (";\n", 0);
+#endif
+#ifdef RSE_PATCH_COSMETICS_HARD
+    }
+#endif
 
     tocvsPath = wrap_tocvs_process_file (finfo->file);
     if (!noexec)
@@ -56,7 +69,14 @@
     if (finfo->rcs == NULL)
 	finfo->rcs = RCS_parse (finfo->file, finfo->repository);
 
+#ifdef RSE_PATCH_COSMETICS_HARD
+    flags = RCS_FLAGS_KEEPFILE;
+    if (really_quiet || quiet)
+        flags |= RCS_FLAGS_QUIET; 
+    switch (RCS_checkin (finfo->rcs, NULL, message, rev, flags))
+#else
     switch (RCS_checkin (finfo->rcs, NULL, message, rev, RCS_FLAGS_KEEPFILE))
+#endif
     {
 	case 0:			/* everything normal */
 
@@ -118,6 +138,16 @@
 		      vers->options, vers->tag, vers->date, (char *) 0);
 	    history_write (type, NULL, vers->vn_rcs,
 			   finfo->file, finfo->repository);
+
+#ifdef RSE_PATCH_ADDFILEATTR
+	    if (type == 'A') {
+	        char *attr;
+	        if ((attr = fileattr_getall(NULL)) != NULL) {
+	            fileattr_setall(finfo->file, attr);
+	            free(attr);
+	        }
+	    }
+#endif
 
 	    if (tocvsPath)
 		if (unlink_file_dir (tocvsPath) < 0)
Index: src/checkout.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/checkout.c,v
retrieving revision 1.1.1.6
diff -u -d -r1.1.1.6 checkout.c
--- src/checkout.c	4 Dec 2002 19:10:20 -0000	1.1.1.6
+++ src/checkout.c	28 Dec 2002 10:48:12 -0000
@@ -191,7 +191,11 @@
 	    case 'p':
 		pipeout = 1;
 		run_module_prog = 0;	/* don't run module prog when piping */
+#ifdef RSE_PATCH_NOLOCK
+		noexec = nolock = 1;	/* so no locks will be created */
+#else
 		noexec = 1;		/* so no locks will be created */
+#endif
 		break;
 	    case 'c':
 		cat = 1;
Index: src/client.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/client.c,v
retrieving revision 1.1.1.7
diff -u -d -r1.1.1.7 client.c
--- src/client.c	28 Dec 2002 18:01:30 -0000	1.1.1.7
+++ src/client.c	28 Dec 2002 20:14:06 -0000
@@ -104,6 +104,9 @@
 int status PROTO((int argc, char **argv));
 int tag PROTO((int argc, char **argv));
 int update PROTO((int argc, char **argv));
+#ifdef RSE_PATCH_RLIST
+int list PROTO((int argc, char **argv));
+#endif
 
 /* All the response handling functions.  */
 static void handle_ok PROTO((char *, int));
@@ -251,14 +254,34 @@
 			 : Name_Root ((char *) NULL, (char *) NULL));
 	}
 
+#ifdef RSE_PATCH_CVSROOT
+        {
+            int cvsroot_alias;
+            cvsroot_type *e;
+
+            cvsroot_alias = 0;
+            if ((e = cvsroot_lookup(NULL, current_parsed_root->original, NULL)) != NULL)
+                if (strcmp(e->slavepath, this_root) == 0)
+                    cvsroot_alias = 1;
+            if ((e = cvsroot_lookup(NULL, NULL, this_root)) != NULL)
+                if (strcmp(e->masterpath, current_parsed_root->original) == 0)
+                    cvsroot_alias = 1;
+#endif
+
 	/* Now check the value for root. */
 	if (this_root && current_parsed_root
+#ifdef RSE_PATCH_CVSROOT
+	    && !cvsroot_alias
+#endif
 	    && (strcmp (this_root, current_parsed_root->original) != 0))
 	{
 	    /* Don't send this, since the CVSROOTs don't match. */
 	    free (this_root);
 	    return 1;
 	}
+#ifdef RSE_PATCH_CVSROOT
+ 	}
+#endif
 	free (this_root);
     }
     
@@ -2762,6 +2785,9 @@
     /* Add a directory name to the list of those sent to the
        server. */
     if (update_dir && (*update_dir != '\0')
+#ifdef RSE_PATCH_CVSROOT
+        /* FIXME: alternative to RSE_PATCH_CVSROOT?! */
+#endif
 	&& (strcmp (update_dir, ".") != 0)
 	&& (findnode (dirs_sent_to_server, update_dir) == NULL))
     {
@@ -4559,6 +4585,18 @@
 		error (1, 0,
 		       "This server does not support the global -n option.");
 	}
+#ifdef RSE_PATCH_NOLOCK
+	if (nolock && !noexec)
+	{
+	    if (have_global)
+	    {
+		send_to_server ("Global_option -u\012", 0);
+	    }
+	    else
+		error (1, 0,
+		       "This server does not support the global -u option.");
+	}
+#endif
 	if (quiet)
 	{
 	    if (have_global)
Index: src/commit.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/commit.c,v
retrieving revision 1.1.1.7
diff -u -d -r1.1.1.7 commit.c
--- src/commit.c	28 Dec 2002 18:01:30 -0000	1.1.1.7
+++ src/commit.c	28 Dec 2002 20:14:06 -0000
@@ -308,6 +308,9 @@
     data->type = status;
     data->tag = xstrdup (vers->tag);
     data->rev_old = data->rev_new = NULL;
+#ifdef RSE_PATCH_EXTRAPERCENT
+    data->date = xstrdup (vers->ts_user);
+#endif
 
     node->type = UPDATE;
     node->delproc = update_delproc;
@@ -996,7 +999,16 @@
 		  xmalloc (sizeof (struct logfile_info)));
 	    li->type = status;
 	    li->tag = xstrdup (vers->tag);
+#ifdef RSE_PATCH_READDNEW
+	    /* If the file was re-added, we want the revision in the commitlog
+	       to be NONE, not the previous dead revision. */
+	    li->rev_old = status == T_ADDED ? NULL : xstrdup (vers->vn_rcs);
+#else
 	    li->rev_old = xstrdup (vers->vn_rcs);
+#endif
+#ifdef RSE_PATCH_EXTRAPERCENT
+	    li->date = xstrdup (vers->ts_user);
+#endif
 	    li->rev_new = NULL;
 	    p->data = (char *) li;
 	    (void) addnode (ulist, p);
@@ -2314,6 +2326,10 @@
 	free (li->rev_old);
     if (li->rev_new)
 	free (li->rev_new);
+#ifdef RSE_PATCH_EXTRAPERCENT
+    if (li->date)
+	free (li->date);
+#endif
     free (li);
 }
 
Index: src/create_adm.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/create_adm.c,v
retrieving revision 1.1.1.5
diff -u -d -r1.1.1.5 create_adm.c
--- src/create_adm.c	20 Sep 2002 02:48:59 -0000	1.1.1.5
+++ src/create_adm.c	28 Dec 2002 10:48:13 -0000
@@ -21,6 +21,41 @@
    or after which CVS might do something non-useful.  If WARN is zero, then
    don't print warnings; all errors are fatal then.  */
 
+#ifdef RSE_PATCH_CVSROOT
+static int local_template_cb(char *repository, char *template)
+{
+    FILE *fpIN, *fpOUT;
+    char buf[1024];
+    size_t n;
+
+    if ((fpOUT = CVS_FOPEN(CVSADM_TEMPLATE, "w+")) == NULL)
+        error(1, errno, "cannot open %s for writing", CVSADM_TEMPLATE);
+    if ((fpIN = CVS_FOPEN(template, "r")) == NULL)
+        error(1, errno, "cannot open %s for reading", template);
+    while (!feof(fpIN)) {
+        n = fread(buf, 1, sizeof buf, fpIN);
+        if (n == 0) {
+            if (ferror(fpIN))
+                error(0, errno, "cannot read template file %s", template);
+            break;
+        }
+        fwrite(buf, 1, n, fpOUT);
+    }
+    fclose(fpIN);
+    fclose(fpOUT);
+    return 0;
+}
+
+static void local_template(char *update_dir, char *repository)
+{
+    cvsroot_type *e;
+
+    if ((e = cvsroot_lookup(NULL, NULL, current_parsed_root->original)) != NULL)
+        Parse_Info(CVSROOTADM_RCSINFO, repository, local_template_cb, 1);
+    return;
+}
+#endif
+
 int
 Create_Admin (dir, update_dir, repository, tag, date, nonbranch, warn,
 	      dotemplate)
@@ -174,6 +209,20 @@
 	fprintf (stderr, "%c<- Create_Admin\n",
 		 (server_active) ? 'S' : ' ');
     }
+#endif
+#ifdef RSE_PATCH_CVSROOT
+    /* Under our "cvs root" feature, checkouts are performed
+       locally (from the repository copy and without C/S), but commits
+       are performed remotely (to the master repository with C/S).
+       Unfortunately, CVS "optimizes" processing and doesn't provide
+       CVS/Template files on non-C/S checkouts. This would mean that
+       if "cvs root" feature is used, the rcsinfo-configured templates
+       are never used. So, if and only if we do a non-C/S checkout (or
+       similar operation which creates CVS/Template) _and_ the current
+       CVSROOT is known to be a repository copy, we force the creation
+       of CVS/Template. */
+    if (!server_active && !(current_parsed_root->isremote) && dotemplate)
+        local_template(update_dir, repository);
 #endif
 
     free (reposcopy);
Index: src/cvs.h
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/cvs.h,v
retrieving revision 1.1.1.7
diff -u -d -r1.1.1.7 cvs.h
--- src/cvs.h	28 Dec 2002 18:01:30 -0000	1.1.1.7
+++ src/cvs.h	28 Dec 2002 20:14:06 -0000
@@ -7,6 +7,48 @@
  */
 
 /*
+ * Support for compiling in various RSE extension
+ */
+#ifdef RSE_PATCHES
+#define RSE_PATCH_CVSRC
+#define RSE_PATCH_CVSROOT
+#define RSE_PATCH_GLOBALOPTION
+#define RSE_PATCH_GLOBALOPTION_PARTLY
+#define RSE_PATCH_CUSTOMCMD
+#define RSE_PATCH_PROLOGEPILOG
+#define RSE_PATCH_LOCALID
+#define RSE_PATCH_CVSHEADER
+#define RSE_PATCH_NOLOCK
+#define RSE_PATCH_EXTRAPERCENT
+#define RSE_PATCH_READDNEW
+#define RSE_PATCH_CONFIGUMASK
+#define RSE_PATCH_FASTERUPDATE
+#define RSE_PATCH_LOGNAME
+#define RSE_PATCH_HISTORYFILE
+#define RSE_PATCH_IMPORTINFO
+#define RSE_PATCH_ADMININFO
+#define RSE_PATCH_HANDLE
+#define RSE_PATCH_IMPORTTOUCH
+#define RSE_PATCH_RELLOCKDIR
+#define RSE_PATCH_CVSUSER
+#define RSE_PATCH_SETXID
+#define RSE_PATCH_PSERVERD
+#define RSE_PATCH_MAPROOT
+#define RSE_PATCH_RLIST
+#define RSE_PATCH_COSMETICS
+#define RSE_PATCH_HASHFUNC
+#define RSE_PATCH_ADDFILEATTR
+#define RSE_PATCH_WILDPASSWD
+#define RSE_PATCH_CVSPID
+#define RSE_PATCH_BUGFIX
+/* problematic changes, because they break "make check" */
+#undef RSE_PATCH_COSMETICS_HARD
+#undef RSE_PATCH_MERGENOKEYWORD
+#undef RSE_PATCH_DIFFHEAD
+#undef RSE_PATCH_SMARTCONFIG
+#endif
+
+/*
  * basic information used in all source files
  *
  */
@@ -193,6 +235,33 @@
 #define CVSROOTADM_WRITERS	"writers"
 #define CVSROOTADM_PASSWD	"passwd"
 #define CVSROOTADM_CONFIG	"config"
+#ifdef RSE_PATCH_ADMININFO
+#define CVSROOTADM_ADMININFO    "admininfo"
+#endif
+#ifdef RSE_PATCH_IMPORTINFO
+#define CVSROOTADM_IMPORTINFO   "importinfo"
+#endif
+
+#ifdef RSE_PATCH_ALTADMINFILES
+#define CVSROOTADM_MODULES_ALT      "conf_modules"
+#define CVSROOTADM_LOGINFO_ALT      "hook_logwrite"
+#define CVSROOTADM_RCSINFO_ALT      "hook_logtempl"
+#define CVSROOTADM_COMMITINFO_ALT   "hook_commit"
+#define CVSROOTADM_TAGINFO_ALT      "hook_tag"
+#define CVSROOTADM_EDITINFO_ALT     "hook_logedit"
+#define CVSROOTADM_VERIFYMSG_ALT    "hook_logverify"
+#define CVSROOTADM_HISTORY_ALT      "data_history"
+#define CVSROOTADM_VALTAGS_ALT      "data_valtags"
+#define CVSROOTADM_IGNORE_ALT       "conf_ignore"
+#define CVSROOTADM_CHECKOUTLIST_ALT "conf_checkout"
+#define CVSROOTADM_WRAPPER_ALT      "hook_wrapper"
+#define CVSROOTADM_NOTIFY_ALT       "hook_notify"
+#define CVSROOTADM_USERS_ALT        "conf_users"
+#define CVSROOTADM_READERS_ALT      "conf_readers"
+#define CVSROOTADM_WRITERS_ALT      "conf_writers"
+#define CVSROOTADM_PASSWD_ALT       "conf_passwd"
+#define CVSROOTADM_CONFIG_ALT       "conf_global"
+#endif
 
 #define CVSNULLREPOS		"Emptydir"	/* an empty directory */
 
@@ -276,6 +345,10 @@
 
 #define	CVSUMASK_ENV	"CVSUMASK"	/* Effective umask for repository */
 
+#ifdef RSE_PATCH_NOLOCK
+#define CVSNOLOCK_ENV   "CVSNOLOCK"     /* do not create lock files */
+#endif
+
 /*
  * If the beginning of the Repository matches the following string, strip it
  * so that the output to the logfile does not contain a full pathname.
@@ -371,6 +444,9 @@
 extern int use_editor;
 extern int cvswrite;
 extern mode_t cvsumask;
+#ifdef RSE_PATCH_LOCALID
+extern char *RCS_citag;
+#endif
 
 
 
@@ -389,6 +465,9 @@
 
 extern int trace;		/* Show all commands */
 extern int noexec;		/* Don't modify disk anywhere */
+#ifdef RSE_PATCH_NOLOCK
+extern int nolock;		/* Don't create locks */
+#endif
 extern int logoff;		/* Don't write history entry */
 
 extern int top_level_admin;
@@ -458,6 +537,27 @@
 void root_allow_free PROTO ((void));
 int root_allow_ok PROTO ((char *));
 
+#ifdef RSE_PATCH_MAPROOT
+void root_map_add PROTO ((char *, char *));
+void root_map_free PROTO ((void));
+int root_map_it PROTO ((char *, char **, int));
+#endif
+
+#ifdef RSE_PATCH_CVSROOT
+typedef struct {
+    char *nickname;
+    char *masterpath;
+    char *slavepath;
+    char *syncprog;
+} cvsroot_type;
+char *cvsroot_filename(void);
+void cvsroot_free(cvsroot_type *);
+cvsroot_type *cvsroot_entry_read(FILE *);
+void cvsroot_entry_write(FILE *, cvsroot_type *);
+cvsroot_type *cvsroot_lookup(char *, char *, char *);
+void cvsroot_synchronize(cvsroot_type *, int);
+#endif
+
 char *gca PROTO((const char *rev1, const char *rev2));
 extern void check_numeric PROTO ((const char *, int, char **));
 char *getcaller PROTO((void));
@@ -562,6 +662,10 @@
 extern void expand_wild PROTO ((int argc, char **argv, 
                                 int *pargc, char ***pargv));
 
+#ifdef RSE_PATCH_HANDLE
+int handle2dates(char *, time_t *, time_t *);
+#endif
+
 #ifdef SERVER_SUPPORT
 extern int cvs_casecmp PROTO ((char *, char *));
 extern int fopen_case PROTO ((char *, char *, FILE **, char **));
@@ -804,6 +908,9 @@
 				   NULL for add or import */
   char *rev_new;		/* rev number after a commit/modify,
 				   add, or import, NULL for remove */
+#ifdef RSE_PATCH_EXTRAPERCENT
+  char *date;
+#endif
 };
 
 /* Wrappers.  */
@@ -843,6 +950,13 @@
 int unedit PROTO ((int argc, char **argv));
 int editors PROTO ((int argc, char **argv));
 int watchers PROTO ((int argc, char **argv));
+#ifdef RSE_PATCH_CVSROOT
+int root PROTO ((int argc, char **argv));
+#endif
+#ifdef RSE_PATCH_PSERVERD
+int pserverd PROTO ((int argc, char **argv));
+int pserver_daemon PROTO ((int argc, char **argv));
+#endif
 extern int annotate PROTO ((int argc, char **argv));
 extern int add PROTO ((int argc, char **argv));
 extern int admin PROTO ((int argc, char **argv));
@@ -872,6 +986,9 @@
 extern int cvsstatus PROTO((int argc, char **argv));
 extern int cvstag PROTO((int argc, char **argv));
 extern int version PROTO((int argc, char **argv));
+#ifdef RSE_PATCH_RLIST
+extern int cvslist PROTO((int argc, char **argv));
+#endif
 
 extern unsigned long int lookup_command_attribute PROTO((char *));
 
Index: src/cvsrc.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/cvsrc.c,v
retrieving revision 1.1.1.3
diff -u -d -r1.1.1.3 cvsrc.c
--- src/cvsrc.c	17 Jun 2002 23:39:00 -0000	1.1.1.3
+++ src/cvsrc.c	28 Dec 2002 10:48:13 -0000
@@ -12,6 +12,203 @@
 #include "cvs.h"
 #include "getline.h"
 
+#ifdef RSE_PATCH_CVSRC
+
+#include <ctype.h>
+#include <string.h>
+
+static char *strq_start = NULL;
+
+static char *
+strqtok_cchar(
+    register char *s,
+    register char *c,
+    int *backslashed)
+{
+    register char ch;
+
+    if ((*backslashed = (*s == '\\'))) {
+        switch (*++s) {
+        case 'a':
+            *c = '\a';
+            break;
+        case 'b':
+            *c = '\b';
+            break;
+        case 'f':
+            *c = '\f';
+            break;
+        case 'n':
+            *c = '\n';
+            break;
+        case 'r':
+            *c = '\r';
+            break;
+        case 't':
+            *c = '\t';
+            break;
+        case 'v':
+            *c = '\v';
+            break;
+        case '\\':
+            *c = '\\';
+            break;
+        case '^':
+            *c = '^';
+            break;
+        case '\'':
+            *c = '\'';
+            break;
+        case '"':
+            *c = '"';
+            break;
+        case '?':
+            *c = '?';
+            break;
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+            ch = 0;
+            if (isdigit(*s) && *s != '8' && *s != '9') {
+                ch = *s++ - '0';                
+                if (isdigit(*s) && *s != '8' && *s != '9') {
+                    ch <<= 3;                   
+                    ch |= *s++ - '0';   
+                    if (isdigit(*s) && *s != '8' && *s != '9') {
+                        ch <<= 3;                               
+                        ch |= *s++ - '0';               
+                    }                   
+                }                       
+            }           
+            s--;
+            *c = ch;
+            break;
+        case 'x':
+            s++;
+            for (ch = 0; isxdigit(*s); s++) {
+                ch <<= 4;
+                ch |= isdigit(*s) ? *s - '0' :
+                      islower(*s) ? *s + 10 - 'a' : *s + 10 - 'A';
+            }
+            s--;
+            *c = ch;
+            break;
+        default:
+            *c = *s;
+            break;
+        }
+    } else
+        *c = *s;
+    return (*s) ? s+1 : NULL;
+}
+
+static char *
+strqtok(
+    char *s,            /* String to tokenize.  NULL to continue same str */
+    char *delim,        /* Token delimiters.  Can be changed w/ each call. */
+    char *quotemarks,   /* Quotation marks.  Can be changed w/ each call. */
+    char *commentchars, /* Comment characters.  Can be changed w/ each call. */ 
+    unsigned int flags) /*      flags&01 ->     strip quotes;
+                         *      flags&02 ->     enable backslash escapes;
+                         *      flags&04 ->     skip all delims before return;
+                         */
+{
+    register char *p, *q;
+    char c;
+    char leftquote = 0;
+    char *token;
+    int backslashed, inquote, intok;
+
+    int stripquote = flags & 01; /* strip quotemarks from tokens */
+    int backslash  = flags & 02; /* backslash sequences */
+    int skipdelim  = flags & 04; /* skip seq of delims at end of token */
+    
+    /* New string? */
+    if (s)
+        strq_start = s;
+    if (!strq_start)
+        return NULL;
+    
+    /* Skip leading delimiters */
+    for (p=strq_start; *p && strchr(delim, *p); p++)
+        ;
+    if (!(*p) || strchr(commentchars, *p))
+        return NULL;
+
+    /* Set `token' to point to returned string.
+     * Use p and q to walk through the user's string:
+     *    p will follow input characters;
+     *    q will overwrite w/ outputted characters, minus possibly-stripped
+     *          quotes and including nulls after each token.
+     */
+    token = q = p;
+    inquote = 0;
+    intok = 1;
+    if (backslash) {
+        while (intok && (p = strqtok_cchar(p, &c, &backslashed))) {
+            if (backslashed) {
+                *q++ = c;               /* treat as plain character */
+            } else if (!inquote && *delim && strchr(delim, c)) {
+                *q = '\0';              /* Reached end of token */
+                intok = 0;
+            } else if (!inquote && *commentchars && strchr(commentchars, c)) {
+                *q = '\0';              /* Reached end of token */
+                *p = '\0';              /* make it act like end of string */
+                intok = 0;
+            } else if (!inquote && *quotemarks && strchr(quotemarks, c)) {
+                inquote = 1;            /* Beginning a quoted segment */
+                leftquote = c;          /* Save quote char for matching with */
+                if (!stripquote) *q++ = c;
+            } else if (inquote && leftquote == c) {
+                inquote = 0;            /* Ending a quoted segment */
+                if (!stripquote) *q++ = c;
+            } else {
+                *q++ = c;               /* Ordinary character */
+            }
+        }
+        strq_start = p;                 /* Where to start next search */
+        *q = '\0';
+    } else {
+        while (intok && *p) {
+            if (!inquote && *delim && strchr(delim, *p)) {
+                *q = '\0';              /* Reached end of token */
+                p++;                    /* advance p for next token */
+                intok = 0;
+            } else if (!inquote && *commentchars && strchr(commentchars, *p)) {
+                *q = '\0';              /* Reached end of token */
+                *p = '\0';              /* make it act like end of string */
+                intok = 0;
+            } else if (!inquote && *quotemarks && strchr(quotemarks, *p)) {
+                inquote = 1;            /* Beginning a quoted segment */
+                leftquote = *p++;       /* Save quote char for matching with */
+                if (!stripquote) *q++ = leftquote;
+            } else if (inquote && leftquote == *p) {
+                inquote = 0;            /* Ending a quoted segment */
+                p++;
+                if (!stripquote) *q++ = leftquote;
+            } else {
+                *q++ = *p++;
+            }
+        }
+        strq_start = p;                 /* Where to start next search */
+        *q = '\0';
+    }
+
+    if (skipdelim && strq_start) {
+        /* Skip trailing delimiters */
+        while (*strq_start && strchr(delim, *strq_start))
+            strq_start++;
+    }
+    return token;
+}
+
+#endif
+
 /* this file is to be found in the user's home directory */
 
 #ifndef	CVSRC_FILENAME
@@ -23,9 +220,68 @@
 
 extern char *strtok ();
 
+#ifdef RSE_PATCH_CVSRC
+static void read_cvsrc_parentdirs ();
+static void read_cvsrc_file ();
+#endif
+
 /* Read cvsrc, processing options matching CMDNAME ("cvs" for global
    options, and update *ARGC and *ARGV accordingly.  */
 
+#ifdef RSE_PATCH_CVSRC
+void
+read_cvsrc (argc, argv, cmdname)
+    int *argc;
+    char ***argv;
+    char *cmdname;
+{
+    /* try to read .cvsrc files from parent directories */
+    read_cvsrc_parentdirs(argc, argv, cmdname);
+    
+    /* try to read .cvsrc file from home directory */
+    read_cvsrc_file(argc, argv, cmdname, get_homedir());
+
+    return;
+}
+
+/* read .cvsrc files from all parent directories (including the current dir) */
+static void
+read_cvsrc_parentdirs (argc, argv, cmdname)
+    int *argc;
+    char ***argv;
+    char *cmdname;
+{
+    char cwd[PATH_MAX];
+    char *cp;
+    int l;
+
+    if (getcwd(cwd, sizeof(cwd)) == NULL)
+        return;
+    if ((l = strlen(cwd)) <= 0)
+        return;
+    if (cwd[l-1] != '/') {
+        cwd[l++] = '/';
+        cwd[l++] = '\0';
+    }
+    while (cwd[0] != '\0') {
+        cwd[strlen(cwd)-1] = '\0';
+        read_cvsrc_file(argc, argv, cmdname, cwd);
+        if ((cp = strrchr(cwd, '/')) == NULL)
+            break;
+        *(cp+1) = '\0';
+    } 
+    return;
+}
+
+/* read .cvsrc file from a particular directory */
+static void
+read_cvsrc_file (argc, argv, cmdname, homedir)
+    int *argc;
+    char ***argv;
+    char *cmdname;
+    char *homedir;
+{
+#else
 void
 read_cvsrc (argc, argv, cmdname)
     int *argc;
@@ -33,6 +289,7 @@
     char *cmdname;
 {
     char *homedir;
+#endif
     char *homeinit;
     FILE *cvsrcfile;
 
@@ -64,7 +321,9 @@
 
     /* determine filename for ~/.cvsrc */
 
+#ifndef RSE_PATCH_CVSRC
     homedir = get_homedir ();
+#endif
     /* If we can't find a home directory, ignore ~/.cvsrc.  This may
        make tracking down problems a bit of a pain, but on the other
        hand it might be obnoxious to complain when CVS will function
@@ -120,9 +379,15 @@
     if (found)
     {
 	/* skip over command in the options line */
+#ifdef RSE_PATCH_CVSRC
+	for (optstart = strqtok (line + command_len, "\t \n", "\"'", "", 7);
+	     optstart;
+	     optstart = strqtok (NULL, "\t \n", "\"'", "", 7))
+#else
 	for (optstart = strtok (line + command_len, "\t \n");
 	     optstart;
 	     optstart = strtok (NULL, "\t \n"))
+#endif
 	{
 	    new_argv [new_argc++] = xstrdup (optstart);
 	  
Index: src/diff.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/diff.c,v
retrieving revision 1.1.1.6
diff -u -d -r1.1.1.6 diff.c
--- src/diff.c	28 Dec 2002 18:01:30 -0000	1.1.1.6
+++ src/diff.c	28 Dec 2002 20:14:06 -0000
@@ -271,7 +271,11 @@
 
     optind = 0;
     while ((c = getopt_long (argc, argv,
+#if defined(RSE_PATCH_HANDLE)
+	       "+abcdefh:ilnpstuwy0123456789BHNRTC:D:F:I:L:U:W:k:r:",
+#else
 	       "+abcdefhilnpstuwy0123456789BHNRTC:D:F:I:L:U:W:k:r:",
+#endif
 			     longopts, &option_index)) != -1)
     {
 	switch (c)
@@ -280,7 +284,11 @@
 		xrealloc_and_strcat (&opts, &opts_allocated, " --side-by-side");
 		break;
 	    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+#if defined(RSE_PATCH_HANDLE)
+	    case 'i': case 'n': case 'p': case 's': case 't':
+#else
 	    case 'h': case 'i': case 'n': case 'p': case 's': case 't':
+#endif
 	    case 'u': case 'w':
             case '0': case '1': case '2': case '3': case '4': case '5':
             case '6': case '7': case '8': case '9':
@@ -352,6 +360,17 @@
 		else
 		    diff_date1 = Make_Date (optarg);
 		break;
+#ifdef RSE_PATCH_HANDLE
+            case 'h': {
+                time_t t1, t2;
+                if (!handle2dates(optarg, &t1, &t2)) 
+                    error (1, 0, "invalid handle string");
+                t1 -= 1; /* subtract one second to have a real difference */
+                diff_date1 = date_from_time_t(t1);
+                diff_date2 = date_from_time_t(t2);
+                break;
+            }
+#endif 
 	    case 'N':
 		empty_files = 1;
 		break;
@@ -487,7 +506,11 @@
 		    char *head =
 			(vers->vn_rcs == NULL
 			 ? NULL
+#ifdef RSE_PATCH_DIFFHEAD                         
+ 			 : RCS_head (vers->srcfile));
+#else
 			 : RCS_branch_head (vers->srcfile, vers->vn_rcs));
+#endif
 		    exists = head != NULL && !RCS_isdead(vers->srcfile, head);
 		    if (head != NULL)
 			free (head);
@@ -891,7 +914,11 @@
 	if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0)
 	    use_rev1 = ((vers->vn_rcs == NULL || vers->srcfile == NULL)
 			? NULL
+#ifdef RSE_PATCH_DIFFHEAD
+			: RCS_head (vers->srcfile));
+#else
 			: RCS_branch_head (vers->srcfile, vers->vn_rcs));
+#endif
 	else
 	{
 	    xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1, 1, 0);
@@ -906,7 +933,11 @@
 	if (diff_rev2 && strcmp (diff_rev2, TAG_HEAD) == 0)
 	    use_rev2 = ((vers->vn_rcs == NULL || vers->srcfile == NULL)
 			? NULL
+#ifdef RSE_PATCH_DIFFHEAD
+			: RCS_head (vers->srcfile));
+#else
 			: RCS_branch_head (vers->srcfile, vers->vn_rcs));
+#endif
 	else
 	{
 	    xvers = Version_TS (finfo, NULL, diff_rev2, diff_date2, 1, 0);
Index: src/hash.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/hash.c,v
retrieving revision 1.1.1.3
diff -u -d -r1.1.1.3 hash.c
--- src/hash.c	19 Sep 2000 00:06:35 -0000	1.1.1.3
+++ src/hash.c	16 Feb 2002 12:36:09 -0000
@@ -25,17 +25,25 @@
     const char *key;
 {
     unsigned int h = 0;
+#ifndef RSE_PATCH_HASHFUNC
     unsigned int g;
+#endif
 
     assert(key != NULL);
     
     while (*key != 0)
     {
+#ifdef RSE_PATCH_HASHFUNC
+        /* D.J. Bernstein's popular times 33 function 
+           (fast and distributes very well) */
+        h = ((h << 5) + h) + FOLD_FN_CHAR(*key++);
+#else
 	unsigned int c = *key++;
 	/* The FOLD_FN_CHAR is so that findnode_fn works.  */
 	h = (h << 4) + FOLD_FN_CHAR (c);
 	if ((g = h & 0xf0000000) != 0)
 	    h = (h ^ (g >> 24)) ^ g;
+#endif
     }
 
     return (h % HASHSIZE);
Index: src/history.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/history.c,v
retrieving revision 1.1.1.6
diff -u -d -r1.1.1.6 history.c
--- src/history.c	24 Sep 2002 20:47:09 -0000	1.1.1.6
+++ src/history.c	28 Dec 2002 10:48:13 -0000
@@ -235,6 +235,9 @@
 static char *tz_name = "+0000";
 
 char *logHistory = ALL_REC_TYPES;
+#ifdef RSE_PATCH_HISTORYFILE
+char *history_file = NULL;
+#endif
 
 /* -r, -t, or -b options, malloc'd.  These are "" if the option in
    question is not specified or is overridden by another option.  The
@@ -668,6 +671,10 @@
 
     if (histfile)
 	fname = xstrdup (histfile);
+#ifdef RSE_PATCH_HISTORYFILE
+    else if (history_file) 
+	fname = xstrdup (history_file);
+#endif
     else
     {
 	fname = xmalloc (strlen (current_parsed_root->directory) + sizeof (CVSROOTADM)
@@ -716,10 +723,18 @@
 	return;
     if ( strchr(logHistory, type) == NULL )	
 	return;
+#ifdef RSE_PATCH_HISTORYFILE
+    if (history_file != NULL)
+        fname = xstrdup (history_file);
+    else {
+#endif
     fname = xmalloc (strlen (current_parsed_root->directory) + sizeof (CVSROOTADM)
 		     + sizeof (CVSROOTADM_HISTORY) + 3);
     (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory,
 		    CVSROOTADM, CVSROOTADM_HISTORY);
+#ifdef RSE_PATCH_HISTORYFILE
+    }
+#endif
 
     /* turn off history logging if the history file does not exist */
     if (!isfile (fname))
@@ -731,7 +746,11 @@
     if (trace)
 	fprintf (stderr, "%s-> fopen(%s,a)\n",
 		 CLIENT_SERVER_STR, fname);
+#ifdef RSE_PATCH_NOLOCK
+    if (nolock)
+#else
     if (noexec)
+#endif
 	goto out;
     fd = CVS_OPEN (fname, O_WRONLY | O_APPEND | O_CREAT | OPEN_BINARY, 0666);
     if (fd < 0)
Index: src/import.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/import.c,v
retrieving revision 1.1.1.6
diff -u -d -r1.1.1.6 import.c
--- src/import.c	24 Sep 2002 20:47:09 -0000	1.1.1.6
+++ src/import.c	28 Dec 2002 10:48:13 -0000
@@ -57,6 +57,140 @@
     NULL
 };
 
+#ifdef RSE_PATCH_IMPORTINFO
+
+static char *importinfo_vtag;
+
+static int
+importinfo_descend(thisdir)
+    char *thisdir;
+{
+    DIR *dirp;
+    struct dirent *dp;
+    int err = 0;
+    List *dirlist = NULL;
+
+    if ((dirp = CVS_OPENDIR(thisdir)) == NULL) {
+	error(0, errno, "cannot open directory");
+	err++;
+    }
+    else {
+	errno = 0;
+	while ((dp = readdir(dirp)) != NULL) {
+	    if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
+		goto one_more_time_boys;
+	    if (strcmp(dp->d_name, CVSADM) == 0)
+		goto one_more_time_boys;
+	    if (ign_name(dp->d_name))
+		goto one_more_time_boys;
+	    if (
+#ifdef DT_DIR
+		(dp->d_type == DT_DIR || (dp->d_type == DT_UNKNOWN && isdir (dp->d_name)))
+#else
+		isdir (dp->d_name)
+#endif
+		&& !wrap_name_has(dp->d_name, WRAP_TOCVS)
+		) {
+		Node *n;
+		if (dirlist == NULL)
+		    dirlist = getlist();
+		n = getnode();
+		n->key = xstrdup(dp->d_name);
+		addnode(dirlist, n);
+	    }
+	    else if (
+#ifdef DT_DIR
+		dp->d_type == DT_LNK || (dp->d_type == DT_UNKNOWN && islink (dp->d_name))
+#else
+		islink (dp->d_name)
+#endif
+		) {
+		err++;
+	    }
+	    else {
+                if (strcmp(thisdir, ".") == 0) {
+                    run_arg(dp->d_name);
+                }
+                else {
+                    char *p;
+                    p = xmalloc(strlen(thisdir)+1+strlen(dp->d_name)+1);
+                    (void)sprintf(p, "%s/%s", thisdir, dp->d_name);
+                    run_arg(p);
+                    free(p);
+                }
+	    }
+	    one_more_time_boys:
+	    errno = 0;
+	}
+	if (errno != 0) {
+	    error(0, errno, "cannot read directory");
+	    err++;
+	}
+	(void)closedir(dirp);
+    }
+    if (dirlist != NULL) {
+	Node *head, *p;
+	head = dirlist->list;
+	for (p = head->next; p != head; p = p->next) {
+            if (strcmp(thisdir, ".") == 0) {
+                err += importinfo_descend(p->key);
+            }
+            else {
+                char *nextdir;
+                nextdir = xmalloc(strlen(thisdir)+1+strlen(p->key)+1);
+                (void)sprintf(nextdir, "%s/%s", thisdir, p->key);
+                err += importinfo_descend(nextdir);
+                free(nextdir);
+            }
+        }
+	dellist(&dirlist);
+    }
+    return err;
+}
+
+/* importinfo configuration entry callback */
+static int
+importinfo_runproc(repository, filter)
+    char *repository;
+    char *filter;
+{
+    char *s, *cp;
+    int rv;
+
+    /* if possible, do an own check to make sure that filter really exists */
+    if (filter[0] == '/') {
+        s = xstrdup(filter);
+        for (cp = s; *cp; cp++) {
+            if (isspace((unsigned char)*cp)) {
+                *cp = '\0';
+                break;
+            }
+        }
+        if (!isfile(s)) {
+            error (0, errno, "cannot find pre-admin filter '%s'", s);
+            free(s);
+            return (1);
+        }
+        free(s);
+    }
+
+    /* construct the filter command */
+    run_setup(filter);
+    run_arg(importinfo_vtag);
+    run_arg(repository);
+    ign_add_file(CVSDOTIGNORE, 1);
+    wrap_add_file(CVSDOTWRAPPER, 1);
+    rv = importinfo_descend(".");
+    if (rv > 0) 
+        return rv;
+
+    /* execute the filter command */
+    rv = run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+
+    return rv;
+}
+#endif
+
 int
 import (argc, argv)
     int argc;
@@ -290,6 +424,12 @@
 	error (1, 0, "attempt to import the repository");
     }
 
+#ifdef RSE_PATCH_IMPORTINFO
+    importinfo_vtag = argv[1];
+    if (Parse_Info(CVSROOTADM_IMPORTINFO, argv[0], importinfo_runproc, 1) > 0)
+        error(1, 0, "Pre-import check failed");
+#endif
+
     /*
      * Make all newly created directories writable.  Should really use a more
      * sophisticated security mechanism here.
@@ -329,7 +469,11 @@
 			       "Use the following command to help the merge:");
 	    cvs_output_tagged ("newline", NULL);
 	    cvs_output_tagged ("newline", NULL);
+#ifdef RSE_PATCH_COSMETICS
+	    cvs_output_tagged ("text", "    ");
+#else
 	    cvs_output_tagged ("text", "\t");
+#endif
 	    cvs_output_tagged ("text", program_name);
 	    if (CVSroot_cmdline != NULL)
 	    {
@@ -356,7 +500,11 @@
 			conflicts);
 	(void) fprintf (logfp,
 			"Use the following command to help the merge:\n\n");
+#ifdef RSE_PATCH_COSMETICS
+	(void) fprintf (logfp, "    %s checkout ", program_name);
+#else
 	(void) fprintf (logfp, "\t%s checkout ", program_name);
+#endif
 	(void) fprintf (logfp, "-j%s:yesterday -j%s %s\n\n",
 			argv[1], argv[1], argv[0]);
     }
@@ -379,6 +527,9 @@
     li->type = T_TITLE;
     li->tag = xstrdup (vbranch);
     li->rev_old = li->rev_new = NULL;
+#ifdef RSE_PATCH_EXTRAPERCENT
+    li->date = NULL;
+#endif
     p->data = (char *) li;
     (void) addnode (ulist, p);
     Update_Logfile (repository, message, logfp, ulist);
@@ -669,7 +820,11 @@
 	     */
 	    if (add_tags (vers->srcfile, vfile, vtag, targc, targv))
 		retval = 1;
+#ifdef RSE_PATCH_IMPORTTOUCH
+	    add_log ('T', vfile);
+#else
 	    add_log ('U', vfile);
+#endif
 	    freevers_ts (&vers);
 	    return (retval);
 	}
Index: src/list.c
===================================================================
RCS file: src/list.c
diff -N src/list.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/list.c	16 Feb 2002 12:36:09 -0000
@@ -0,0 +1,282 @@
+/* 
+ * Copyright (c) 1998, Dan Rich <drich@employees.com>
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * List Directory
+ */
+
+#ifdef RSE_PATCH_RLIST
+
+#include <time.h>
+#include <pwd.h>
+#include <grp.h>
+
+#if 0
+#include "cvs.h"
+#endif
+
+static int   cvslist_fileproc PROTO((void *callerdat, struct file_info * finfo));
+static Dtype cvslist_dirproc PROTO((void *callerdat, char *dir, char *repos, char *update_dir, List * entries));
+static int   cvslist_output_dir PROTO((Node * node, void *closure));
+static int   cvslist_output_file PROTO((char *name));
+static int   cvslist_tag_proc PROTO((Node * p, void *closure));
+
+static char *numtag;
+static char *date = NULL;
+static int   force_tag_match = 1;
+static int   local = 0;
+static int   verbose = 0;
+static int   list_attic = 0;
+static RCSNode *xrcsnode;
+
+static const char *const status_usage[] = {
+    "Usage: %s %s [-alRv] [-r tag|-D date] modules\n",
+    "\t-a\tInclude attic files\n",
+    "\t-v\tVerbose format; includes additional information for the file\n",
+    "\t-l\tProcess this directory only (not recursive).\n",
+    "\t-R\tProcess directories recursively.\n",
+    "\t-r rev\tExisting revision/tag.\n",
+    "\t-D\tExisting date.\n",
+    "(Specify the --help global option for a list of other help options)\n",
+    NULL
+};
+
+int cvslist(int argc, char **argv)
+{
+    int c;
+    int i;
+    int which;
+    int retval;
+
+    if (argc == -1)
+        usage(status_usage);
+    optind = 0;
+    while ((c = getopt(argc, argv, "+alRr:v")) != -1) {
+        switch (c) {
+            case 'a':
+                list_attic = 1;
+                break;
+            case 'D':
+                if (date)
+                    free(date);
+                date = Make_Date(optarg);
+                break;
+            case 'l':
+                local = 1;
+                break;
+            case 'R':
+                local = 0;
+                break;
+            case 'r':
+                numtag = optarg;
+                break;
+            case 'v':
+                verbose = 1;
+                break;
+            case '?':
+            default:
+                usage(status_usage);
+                break;
+        }
+    }
+    argc -= optind;
+    argv += optind;
+
+    if (date && numtag)
+        error(1, 0, "-r and -D options are mutually exclusive");
+
+    wrap_setup();
+#ifdef CLIENT_SUPPORT
+    if (current_parsed_root->isremote) {
+        start_server();
+        ign_setup();
+        if (list_attic)
+            send_arg("-a");
+        if (local)
+            send_arg("-l");
+        if (verbose)
+            send_arg("-v");
+        if (numtag)
+            option_with_arg("-r", numtag);
+        if (date)
+            client_senddate(date);
+#if 0
+        if (supported_request("expand-modules")) {
+            /* This is done here because we need to read responses from the
+               server before we send the command checkout or export files. */
+            client_expand_modules(argc, argv, local);
+        }
+#endif
+        /* Send any remaining arguments -- probably dir/file names */
+        for (i = 0; i < argc; ++i)
+            send_arg(argv[i]);
+        send_to_server("list\012", 0); /* Send the command */
+        return get_responses_and_close();
+    }
+#endif
+#ifdef SERVER_SUPPORT
+    /* If we're the server, make sure we're starting at the root */
+    if (server_active)
+        CVS_CHDIR(current_parsed_root->directory);
+#endif
+
+#if 0
+    if (numtag != NULL)
+        tag_check_valid(numtag, argc, argv, local, 0, "");
+#endif
+
+    which = W_REPOS;
+    if (list_attic)
+        which |= W_ATTIC;
+
+    /* start the recursion processor */
+    cvs_output_tagged("+list", NULL);
+    retval = start_recursion(cvslist_fileproc, (FILESDONEPROC)NULL,
+                             cvslist_dirproc, (DIRLEAVEPROC)NULL, NULL,
+                             argc, argv, local, which, 0, 1, (char *)NULL, 1);
+    cvs_output_tagged("-list", NULL);
+
+    return retval;
+}
+
+/* 
+ * Display file info
+ */
+/* ARGSUSED */
+static int cvslist_fileproc(callerdat, finfo)
+    void *callerdat;
+    struct file_info *finfo;
+{
+    char *buf;
+    Vers_TS *vers;
+
+    /* If a particular revision was specified, only show that one */
+    if (numtag != NULL || date != NULL) {
+        vers = Version_TS(finfo, NULL, NULL, NULL, 0, 0);
+        if (RCS_getversion(vers->srcfile, numtag, date, force_tag_match, NULL) == NULL)
+            return 0;
+    }
+
+    cvslist_output_file(finfo->fullname);
+
+    if (verbose) {
+        vers = Version_TS(finfo, NULL, NULL, NULL, 0, 0);
+        if (vers->srcfile) {
+            List *symbols = RCS_symbols(vers->srcfile);
+
+            cvs_output_tagged("+info", NULL);
+            if (vers->vn_rcs == NULL)
+                cvs_output_tagged("finfo",
+                                  "   Repository revision:\tNo revision control file");
+            else {
+                buf = (char *)malloc(24 + strlen(vers->vn_rcs) + 1 +
+                                     strlen(vers->srcfile->path) + 1);
+                sprintf(buf, "   Repository revision:\t%s\t%s",
+                        vers->vn_rcs, vers->srcfile->path);
+                cvs_output_tagged("finfo", buf);
+            }
+            cvs_output_tagged("newline", NULL);
+            cvs_output_tagged("finfo", "   Existing Tags:");
+            cvs_output_tagged("newline", NULL);
+            if (symbols) {
+                xrcsnode = finfo->rcs;
+                (void)walklist(symbols, cvslist_tag_proc, NULL);
+            }
+            else
+                cvs_output_tagged("finfo", "\tNo Tags Exist");
+
+            cvs_output_tagged("-info", NULL);
+            cvs_output_tagged("newline", NULL);
+        }
+    }
+    return 0;
+}
+
+/* 
+ * Display directory info
+ */
+/* ARGSUSED */
+static Dtype cvslist_dirproc(callerdat, dir, repos, update_dir, entries)
+    void *callerdat;
+    char *dir;
+    char *repos;
+    char *update_dir;
+    List *entries;
+{
+    char *buf;
+    List *dirs;
+
+    buf = (char *)malloc(strlen(update_dir) + 2);
+    sprintf(buf, "%s", update_dir);
+    cvs_output_tagged("fname", buf);
+    cvs_output_tagged("newline", NULL);
+    free(buf);
+
+    if (local) {                       /* We need to output the current dirs */
+        dirs = Find_Directories(update_dir, W_REPOS, NULL);
+        walklist(dirs, cvslist_output_dir, update_dir);
+    }
+    return R_PROCESS;
+}
+
+static int cvslist_output_dir(node, closure)
+    Node *node;
+    void *closure;
+{
+    char *buf;
+
+    buf = (char *)malloc(strlen((char *)closure) + strlen(node->key) + 3);
+    sprintf(buf, "%s/%s/", (char *)closure, node->key);
+    cvs_output_tagged("fname", buf);
+    cvs_output_tagged("newline", NULL);
+    free(buf);
+    return 0;
+}
+
+static int cvslist_output_file(name)
+    char *name;
+{
+    char *buf;
+    char *nlptr;
+
+    buf = (char *)malloc(strlen(name) + 1);
+    strncpy(buf, name, strlen(name));
+    *(buf+strlen(name)) = '\0';
+
+    /* cvs_output_tagged doesn't like \n */
+    if ((nlptr = strchr(buf, '\n')) != NULL)
+        nlptr = '\0';
+    cvs_output_tagged("fname", buf);
+    cvs_output_tagged("newline", NULL);
+    free(buf);
+    return 0;
+}
+
+static int cvslist_tag_proc(p, closure)
+    Node *p;
+    void *closure;
+{
+    char *branch = NULL;
+    char *buf;
+
+    if (RCS_nodeisbranch(xrcsnode, p->key))
+        branch = RCS_whatbranch(xrcsnode, p->key);
+
+    buf = xmalloc(80 + strlen(p->key)
+                  + (branch ? strlen(branch) : strlen(p->data)));
+    sprintf(buf, "\t%-25s\t(%s: %s)", p->key,
+            branch ? "branch" : "revision", branch ? branch : p->data);
+    cvs_output_tagged("finfo", buf);
+    cvs_output_tagged("newline", NULL);
+    free(buf);
+
+    if (branch)
+        free(branch);
+
+    return (0);
+}
+
+#endif /* RSE_PATCH_RLIST */
+
Index: src/lock.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/lock.c,v
retrieving revision 1.1.1.7
diff -u -d -r1.1.1.7 lock.c
--- src/lock.c	28 Dec 2002 18:01:30 -0000	1.1.1.7
+++ src/lock.c	28 Dec 2002 20:14:06 -0000
@@ -403,7 +403,11 @@
 	(void) fprintf (stderr, "%s-> Reader_Lock(%s)\n", CLIENT_SERVER_STR,
                         xrepository);
 
+#ifdef RSE_PATCH_NOLOCK
+    if (nolock)
+#else
     if (noexec)
+#endif
 	return (0);
 
     /* we only do one directory at a time for read locks! */
@@ -475,7 +479,11 @@
 {
     char *wait_repos;
 
+#ifdef RSE_PATCH_NOLOCK
+    if (nolock)
+#else
     if (noexec)
+#endif
 	return (0);
 
     /* We only know how to do one list at a time */
Index: src/logmsg.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/logmsg.c,v
retrieving revision 1.1.1.6
diff -u -d -r1.1.1.6 logmsg.c
--- src/logmsg.c	20 Sep 2002 02:48:59 -0000	1.1.1.6
+++ src/logmsg.c	28 Dec 2002 10:48:14 -0000
@@ -673,6 +673,42 @@
 	    {
 		switch (*c)
 		{
+#ifdef RSE_PATCH_EXTRAPERCENT
+		case 'o': {
+                    char T[2];
+		    str_list = xrealloc (str_list, (strlen (str_list) + 1 + 1));
+                    switch (li->type) {
+                        case T_ADDED:    T[0] = 'A'; break;
+                        case T_MODIFIED: T[0] = 'M'; break;
+                        case T_REMOVED:  T[0] = 'R'; break;
+                        default:         T[0] = '?'; break;
+                    }
+                    T[1] = '\0';
+		    (void) strcat (str_list, T);
+		    break;
+                }
+		case 't':
+		    str_list =
+			xrealloc (str_list,
+				  (strlen (str_list)
+				   + (li->tag ? strlen (li->tag) : 0)
+				   + 10)
+				  );
+		    (void) strcat (str_list, (li->tag ? li->tag : ""));
+		    break;
+		case 'd': {
+            time_t t;
+            if (li->date != NULL) {
+                t = get_date(li->date, NULL);
+                if (t != ((time_t)-1)) {
+                    t += 1; /* re-adjust because of fudge */
+                    str_list = xrealloc (str_list, (strlen(str_list)+20));
+                    sprintf(str_list+strlen(str_list), "%ld", (long)t);
+                }
+            }
+            break;
+	    }
+#endif
 		case 's':
 		    str_list =
 			xrealloc (str_list,
Index: src/main.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/main.c,v
retrieving revision 1.1.1.7
diff -u -d -r1.1.1.7 main.c
--- src/main.c	24 Oct 2002 18:38:37 -0000	1.1.1.7
+++ src/main.c	28 Dec 2002 10:50:11 -0000
@@ -41,6 +41,9 @@
 int quiet = 0;
 int trace = 0;
 int noexec = 0;
+#ifdef RSE_PATCH_NOLOCK
+int nolock = 0;
+#endif
 int logoff = 0;
 
 /* Set if we should be writing CVSADM directories at top level.  At
@@ -50,6 +53,15 @@
 
 mode_t cvsumask = UMASK_DFLT;
 
+#ifdef RSE_PATCH_LOCALID
+char *RCS_citag = NULL;
+#endif
+
+#ifdef RSE_PATCH_PROLOGEPILOG
+char *cvs_prolog = NULL;
+char *cvs_epilog = NULL;
+#endif
+
 char *CurDir;
 
 /*
@@ -124,11 +136,17 @@
     { "login",    "logon",    "lgn",       login,     0 },
     { "logout",   NULL,       NULL,        logout,    0 },
 #endif /* AUTH_CLIENT_SUPPORT */
+#ifdef RSE_PATCH_PSERVERD
+    { "pserverd", NULL,       NULL,    pserverd },
+#endif
 #if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
     { "pserver",  NULL,       NULL,        server,    CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */
 #endif
     { "rannotate","rann",     "ra",        annotate,  0 },
     { "rdiff",    "patch",    "pa",        patch,     0 },
+#ifdef RSE_PATCH_RLIST
+    { "rlist",    "rls",      NULL,        cvslist,   0 },
+#endif
     { "release",  "re",       "rel",       release,   0 },
     { "remove",   "rm",       "delete",    cvsremove, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
     { "rlog",     "rl",       NULL,        cvslog,    0 },
@@ -143,9 +161,53 @@
     { "version",  "ve",       "ver",       version,   0 },
     { "watch",    NULL,       NULL,        watch,     CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
     { "watchers", NULL,       NULL,        watchers,  CVS_CMD_USES_WORK_DIR },
+#ifdef RSE_PATCH_CVSROOT
+    { "root",     "ro",	      "repo",	   root,      CVS_CMD_IGNORE_ADMROOT },
+#endif
     { NULL, NULL, NULL, NULL, 0 },
 };
 
+#ifdef RSE_PATCH_CUSTOMCMD
+
+/* the table of custom commands */
+#define CUSTOMCMD_MAX 20
+static int customcmd_num = 0;
+struct customcmd {
+    char *name;
+    char *command;
+};
+static struct customcmd customcmd_tab[CUSTOMCMD_MAX];
+
+/* the internal handler function for custom commands */
+static int
+customcmd_run(argc, argv)
+    int argc;
+    char **argv;
+{
+    int i;
+    char *cmd;
+
+    /* support for `cvs -H <cmd>' */
+    if (argc == -1) {
+        (void)fprintf(stderr, "Usage: %s %s [command arguments]\n", 
+                      program_name, command_name);
+        error_exit();
+    }
+
+    /* execute the command */
+    cmd = expand_path(argv[0], command_name, 0);
+    run_setup(cmd);
+    for (i = 1; i < argc; i++)
+        run_arg(argv[i]);
+    if (run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL) != 0)
+        error(1, 0, "program `%s' of custom command `%s' returned non-zero", 
+              cmd, command_name);
+    free(cmd);
+
+    return 0;
+}
+#endif
+
 static const char *const usg[] =
 {
     /* CVS usage messages never have followed the GNU convention of
@@ -186,9 +248,13 @@
        paragraph in ../cvs.spec without assuming the reader knows what
        version control means.  */
 
+#ifdef RSE_PATCH_COSMETICS
+    "For CVS updates and additional information, see http://www.cvshome.org/\n",
+#else
     "For CVS updates and additional information, see\n",
     "    the CVS home page at http://www.cvshome.org/ or\n",
     "    Pascal Molli's CVS site at http://www.loria.fr/~molli/cvs-index.html\n",
+#endif
     NULL,
 };
 
@@ -215,11 +281,17 @@
     "        login        Prompt for password for authenticating server\n",
     "        logout       Removes entry in .cvspass for remote repository\n",
 #endif /* AUTH_CLIENT_SUPPORT */
+#ifdef RSE_PATCH_PSERVERD
+    "        pserverd     Password server daemon\n",
+#endif
 #if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
     "        pserver      Password server mode\n",
 #endif
     "        rannotate    Show last revision where each line of module was modified\n",
     "        rdiff        Create 'patch' format diffs between releases\n",
+#ifdef RSE_PATCH_RLIST
+    "        rlist        List repository directories.\n",
+#endif
     "        release      Indicate that a Module is no longer in use\n",
     "        remove       Remove an entry from the repository\n",
     "        rlog         Print out history information for a module\n",
@@ -234,6 +306,9 @@
     "        version      Show current CVS version(s)\n",
     "        watch        Set watches\n",
     "        watchers     See who is watching a file\n",
+#ifdef RSE_PATCH_CVSROOT
+    "        root         Maintain repository root locations\n",
+#endif
     "(Specify the --help option for a list of other help options)\n",
     NULL,
 };
@@ -249,6 +324,9 @@
     "    -w           Make checked-out files read-write (default).\n",
     "    -l           Turn history logging off.\n",
     "    -n           Do not execute anything that will change the disk.\n",
+#ifdef RSE_PATCH_NOLOCK
+    "    -u           Do not create lock files (implies -l).\n",
+#endif
     "    -t           Show trace of program execution -- try with -n.\n",
     "    -v           CVS version and copyright.\n",
     "    -T tmpdir    Use 'tmpdir' for temporary files.\n",
@@ -262,6 +340,10 @@
 #endif
     "    -a           Authenticate all net traffic.\n",
 #endif
+#ifdef RSE_PATCH_PROLOGEPILOG
+    "    -P program   Run prolog program before processing.\n",
+    "    -E program   Run epilog program after processing.\n",
+#endif
     "    -s VAR=VAL   Set CVS user variable.\n",
     "(Specify the --help option for a list of other help options)\n",
     NULL
@@ -332,6 +414,20 @@
 	if (strcmp (cmd_name, cm->fullname) == 0)
 	    break;
     }
+#ifdef RSE_PATCH_CUSTOMCMD
+    {
+        int i;
+        unsigned long int ret = 0;
+        for (i = 0; i < customcmd_num; i++) {
+            if (strcmp(customcmd_tab[i].name, cmd_name) == 0) {
+                ret |= CVS_CMD_IGNORE_ADMROOT;
+                ret &= ~(CVS_CMD_USES_WORK_DIR);
+                ret &= ~(CVS_CMD_MODIFIES_REPOSITORY);
+                return ret;
+            }
+        }
+    }
+#endif
     if (!cm->fullname)
 	error (1, 0, "unknown command: %s", cmd_name);
     return cm->attr;
@@ -403,11 +499,34 @@
     int free_CVSroot = 0;
     int free_Editor = 0;
     int free_Tmpdir = 0;
+#ifdef RSE_PATCH_CVSROOT
+    cvsroot_type *cvsroot_sync = NULL;
+    int cvsroot_cmdline_isreal = 0;
+#endif
+#if defined(RSE_PATCH_CVSROOT) || defined(RSE_PATCH_CUSTOMCMD)
+    int standalone_command = 0;
+#endif
 
     int help = 0;		/* Has the user asked for help?  This
 				   lets us support the `cvs -H cmd'
 				   convention to give help for cmd. */
+#if defined(RSE_PATCH_NOLOCK) ||\
+    defined(RSE_PATCH_PROLOGEPILOG) ||\
+    defined(RSE_PATCH_CUSTOMCMD)
+    static const char short_options[] = "+Qqrwtnlvb:T:e:d:Hfz:s:xa"
+#ifdef RSE_PATCH_NOLOCK
+    "u"
+#endif
+#ifdef RSE_PATCH_PROLOGEPILOG
+    "P:E:"
+#endif
+#ifdef RSE_PATCH_CUSTOMCMD
+    "C:"
+#endif
+    ;
+#else
     static const char short_options[] = "+Qqrwtnlvb:T:e:d:Hfz:s:xa";
+#endif
     static struct option long_options[] =
     {
         {"help", 0, NULL, 'H'},
@@ -416,6 +535,9 @@
 	{"help-synonyms", 0, NULL, 2},
 	{"help-options", 0, NULL, 4},
 	{"allow-root", required_argument, NULL, 3},
+#ifdef RSE_PATCH_MAPROOT
+	{"map-root", required_argument, NULL, 5},
+#endif
         {0, 0, 0, 0}
     };
     /* `getopt_long' stores the option index here, but right now we
@@ -470,6 +592,16 @@
     }
     if (getenv (CVSREAD_ENV) != NULL)
 	cvswrite = 0;
+#ifdef RSE_PATCH_NOLOCK
+    if (getenv (CVSNOLOCK_ENV)) {
+	nolock = 1;
+	logoff = 1;
+    }
+#endif
+#ifdef RSE_PATCH_PROLOGEPILOG
+    cvs_prolog = getenv("CVSPROLOG");
+    cvs_epilog = getenv("CVSEPILOG");
+#endif
 
     /* Set this to 0 to force getopt initialization.  getopt() sets
        this to 1 internally.  */
@@ -489,12 +621,63 @@
 	    use_cvsrc = 0;
     }
 
+#ifdef RSE_PATCH_GLOBALOPTION
+    /* 
+     * Perform a pre-lookup of the command name in order to scan cvsrc
+     * file also for command dependent global options. For instance a
+     * "-d" option only for "commit" commands (useful if one uses a
+     * local repository copy for all cvs commands, but commits have to
+     * go directly to the master repository).
+     */
+    if (use_cvsrc) {
+        command_name = argv[optind];
+        if (command_name != NULL && command_name[0] != '\0') {
+            for (cm = cmds; cm->fullname != NULL; cm++)
+            {
+                if (cm->nick1 && !strcmp(command_name, cm->nick1))
+                    break;
+                if (cm->nick2 && !strcmp(command_name, cm->nick2))
+                    break;
+                if (!strcmp(command_name, cm->fullname))
+                    break;
+            }
+            command_name = cm->fullname;
+        }
+    }
+#endif
+
     /*
      * Scan cvsrc file for global options.
      */
     if (use_cvsrc)
 	read_cvsrc (&argc, &argv, "cvs");
 
+#ifdef RSE_PATCH_GLOBALOPTION
+    if (use_cvsrc) {
+        if (command_name != NULL && command_name[0] != '\0') {
+            char *cmd;
+#ifdef RSE_PATCH_GLOBALOPTION_PARTLY
+            if (   strcmp(command_name, "commit")   == 0
+                || strcmp(command_name, "tag")      == 0
+                || strcmp(command_name, "rtag")     == 0
+                || strcmp(command_name, "history")  == 0
+                || strcmp(command_name, "admin")    == 0
+                || strcmp(command_name, "import")   == 0
+#ifdef RSE_PATCH_RLIST
+                || strcmp(command_name, "rlist")    == 0
+#endif
+                || strcmp(command_name, "rdiff")    == 0) {
+#endif
+                cmd = xmalloc(4 + strlen(command_name) + 1);
+                sprintf(cmd, "cvs/%s", command_name);
+                read_cvsrc (&argc, &argv, cmd);
+#ifdef RSE_PATCH_GLOBALOPTION_PARTLY
+            }
+#endif
+        }
+    }
+#endif
+
     optind = 0;
     opterr = 1;
 
@@ -520,6 +703,17 @@
 		/* --allow-root */
 		root_allow_add (optarg);
 		break;
+#ifdef RSE_PATCH_MAPROOT
+	    case 5: {
+		/* --map-root */
+                char *cp;
+                if ((cp = strchr(optarg, ':')) == NULL)
+		    error(1, 0, "invalid argument syntax for --map-root option");
+                *cp++ = '\0';
+		root_map_add(optarg, cp);
+		break;
+            }
+#endif
 	    case 'Q':
 		really_quiet = 1;
 		/* FALL THROUGH */
@@ -537,6 +731,10 @@
 		break;
 	    case 'n':
 		noexec = 1;
+#ifdef RSE_PATCH_NOLOCK
+	    case 'u':			/* Fall through */
+		nolock = 1;
+#endif
 	    case 'l':			/* Fall through */
 		logoff = 1;
 		break;
@@ -575,10 +773,34 @@
 	    case 'd':
 		if (CVSroot_cmdline != NULL)
 		    free (CVSroot_cmdline);
+#ifdef RSE_PATCH_MAPROOT
+                {
+                    char *newarg;
+                    if (root_map_it(optarg, &newarg, 0))
+                        optarg = newarg;
+                }
+#endif
+#ifdef RSE_PATCH_CVSROOT
+                {
+                    cvsroot_type *e;
+                    if ((e = cvsroot_lookup(optarg, NULL, NULL)) != NULL) {
+                        if (!quiet)
+                            fprintf(stderr, "%s: using repository `%s'\n", program_name, e->masterpath);
+		        CVSroot_cmdline = xstrdup(e->masterpath);
+		        CVSroot = xstrdup(e->masterpath);
+                        cvsroot_free(e);
+                    }
+                    else {
+                        cvsroot_cmdline_isreal = 1;
+#endif
 		CVSroot_cmdline = xstrdup (optarg);
 		if (free_CVSroot)
 		    free (CVSroot);
 		CVSroot = xstrdup (optarg);
+#ifdef RSE_PATCH_CVSROOT
+                    }
+                }
+#endif
 		free_CVSroot = 1;
 		cvs_update_env = 1;	/* need to update environment */
 		break;
@@ -620,6 +842,28 @@
                    We will issue an error later if stream
                    authentication is not supported.  */
 		break;
+#ifdef RSE_PATCH_PROLOGEPILOG
+	    case 'P':
+	        cvs_prolog = xstrdup(optarg);
+		break;
+	    case 'E':
+	        cvs_epilog = xstrdup(optarg);
+		break;
+#endif
+#ifdef RSE_PATCH_CUSTOMCMD
+	    case 'C': {
+                char *cp;
+                if (customcmd_num >= CUSTOMCMD_MAX)
+                    error(1, 0, "maximum number of allowed -C options reached");
+                if ((cp = strchr(optarg, ':')) == NULL)
+                    error(1, 0, "invalid argument to option -C (has to be \"name:cmd\")");
+                *cp++ = '\0';
+                customcmd_tab[customcmd_num].name    = xstrdup(optarg);
+                customcmd_tab[customcmd_num].command = xstrdup(cp);
+                customcmd_num++;
+		break;
+            }
+#endif
 	    case '?':
 	    default:
                 usage (usg);
@@ -631,6 +875,28 @@
     if (argc < 1)
 	usage (usg);
 
+#ifdef RSE_PATCH_CUSTOMCMD
+    /* Look up the custom command. */
+    cm = NULL;
+    {
+        int i;
+        command_name = argv[0];
+        for (i = 0; i < customcmd_num; i++) {
+            if (strcmp(customcmd_tab[i].name, command_name) == 0) {
+                struct cmd *ccm;
+                ccm = (struct cmd *)xmalloc(sizeof(struct cmd));
+                ccm->nick1 = NULL;
+                ccm->nick2 = NULL;
+                ccm->func = customcmd_run;
+                ccm->fullname = customcmd_tab[i].name;
+                argv[0] = customcmd_tab[i].command;
+                cm = (const struct cmd *)ccm;
+                standalone_command = 1;
+            }
+        }
+    }
+    if (cm == NULL) {
+#endif
 
     /* Look up the command name. */
 
@@ -653,6 +919,10 @@
     else
 	command_name = cm->fullname;	/* Global pointer for later use */
 
+#ifdef RSE_PATCH_CUSTOMCMD
+    }
+#endif
+
     if (help)
     {
 	argc = -1;		/* some functions only check for this */
@@ -678,6 +948,71 @@
 		       CVSUMASK_ENV, cp);
 	}
 
+#ifdef RSE_PATCH_CVSPID
+        /* provide the process id of the parent CVS process to
+           sub-processes (usually scripts called from *info files) in order
+           to let them have a unique session handle */
+        {
+            char pidbuf[64];
+            sprintf(pidbuf, "CVSPID=%lu", (unsigned long)getpid());
+            putenv(pidbuf);
+        }
+#endif
+
+#ifdef RSE_PATCH_SETXID
+    if (   strcmp(command_name, "kserver") != 0
+        && strcmp(command_name, "pserver") != 0
+        && strcmp(command_name, "server")  == 0) {
+        uid_t uid, euid;
+        gid_t gid, egid;
+        struct passwd *pw;
+        char *env;
+
+        /* adjust group id */
+        gid  = getgid();
+        egid = getegid();
+        if (gid != egid)
+            setgid(egid); /* upgrade real to effective gid */
+        else
+            setegid(gid); /* downgrade effective to real gid */
+
+        /* adjust user id */
+        uid  = getuid();
+        euid = geteuid();
+        if (uid != euid)
+            setuid(euid); /* upgrade real to effective uid */
+        else
+            seteuid(uid); /* downgrade effective to real uid */
+
+        /* still do not adjust umask */
+        umask(0);
+
+        /* remember real user (especially for getcaller()) */
+        pw = getpwuid(uid);
+#ifdef AUTH_SERVER_SUPPORT
+        CVS_Username = xstrdup(pw->pw_name);
+#if HAVE_PUTENV
+        env = xmalloc(sizeof("LOGNAME=")+strlen(CVS_Username));
+        (void)sprintf(env, "LOGNAME=%s", CVS_Username);
+        (void)putenv(env);
+#endif
+#endif
+
+#if HAVE_PUTENV
+        /* remember running user */
+        pw = getpwuid(getuid());
+        env = xmalloc(sizeof("USER=")+strlen(pw->pw_name));
+        (void)sprintf(env, "USER=%s", pw->pw_name);
+        (void)putenv(env);
+#endif
+    }
+    else {
+        /* delete effective user and group id */
+        seteuid(getuid());
+        setegid(getgid());
+    }
+#endif
+
 #ifdef SERVER_SUPPORT
 
 # ifdef HAVE_KERBEROS
@@ -694,6 +1029,21 @@
 	}
 # endif /* HAVE_KERBEROS */
 
+#ifdef RSE_PATCH_PSERVERD
+    if (strcmp(command_name, "pserverd") == 0) {
+        /* 
+         * perform the socket listening. This returns multiple times,
+         * i.e., for each connection. But the parent never returns.
+         */
+        pserver_daemon(argc, argv);
+
+        /* 
+         * switch to regular "cvs server" operation.
+         */
+        argc = 0;
+        command_name = "server";
+    }
+#endif
 
 # if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)
 	if (strcmp (command_name, "pserver") == 0)
@@ -718,6 +1068,11 @@
 
 #endif /* SERVER_SUPPORT */
 
+#ifdef RSE_PATCH_CVSROOT
+    if (strcmp(command_name, "root") == 0)
+        standalone_command = 1;
+#endif
+
 	/* This is only used for writing into the history file.  For
 	   remote connections, it might be nice to have hostname
 	   and/or remote path, on the other hand I'm not sure whether
@@ -788,8 +1143,12 @@
 	       in server mode, since the client will send the repository
 	       directory after the connection is made. */
 
+#if defined(RSE_PATCH_CVSROOT) || defined(RSE_PATCH_CUSTOMCMD)
+	if (!server_active && !standalone_command)
+#else
 	if (!server_active)
 #endif
+#endif
 	{
 	    char *CVSADM_Root;
 	    
@@ -845,6 +1204,54 @@
 		error (1, 0,
 		       "CVS/Root file (if any).");
 	    }
+
+#ifdef RSE_PATCH_CVSROOT
+            if (CVSroot_cmdline == NULL || !cvsroot_cmdline_isreal) {
+                cvsroot_type *e;
+                if (lookup_command_attribute(command_name) & CVS_CMD_MODIFIES_REPOSITORY) {
+                    if ((e = cvsroot_lookup(NULL, NULL, CVSroot)) != NULL) {
+                        /* command modifies repository and we still operare on
+                           the slave repository, so switch to the master repository, 
+                           because we can only perform modifications there. */
+                        if (!quiet) {
+                            fprintf(stderr, "%s: switching to MASTER location of repository `%s'\n", program_name, e->nickname);
+                            fprintf(stderr, "%s: %s <-- %s\n", program_name, e->masterpath, e->slavepath);
+                        }
+                        if (free_CVSroot)
+                            free(CVSroot);
+                        CVSroot = xstrdup(e->masterpath);
+		        if (CVSroot_cmdline != NULL)
+		            free(CVSroot_cmdline);
+                        CVSroot_cmdline = xstrdup(e->masterpath);
+                        cvsroot_sync = e;
+                        free_CVSroot = 1;
+                        cvs_update_env = 1;
+                    }
+                }
+                else {
+                    if ((e = cvsroot_lookup(NULL, CVSroot, NULL)) != NULL) {
+                        if (e->slavepath[0] != '\0') { 
+                            /* command does not modify repository and we still operare on
+                               the master repository, so switch to the slave repository, 
+                               because it is faster by definition. */
+                            if (!quiet) {
+                                fprintf(stderr, "%s: switching to SLAVE location of repository `%s'\n", program_name, e->nickname);
+                                fprintf(stderr, "%s: %s --> %s\n", program_name, e->masterpath, e->slavepath);
+                            }
+                            if (free_CVSroot)
+                                free(CVSroot);
+                            CVSroot = xstrdup(e->slavepath);
+                            if (CVSroot_cmdline != NULL)
+                                free(CVSroot_cmdline);
+                            CVSroot_cmdline = xstrdup(e->slavepath);
+                            cvsroot_free(e);
+                            free_CVSroot = 1;
+                            cvs_update_env = 1;
+                        }
+                    }
+                }
+            }
+#endif /* RSE_PATCH_CVSROOT */
 	}
 
 	/* Here begins the big loop over unique cvsroot values.  We
@@ -877,6 +1284,9 @@
 	   end of things.  */
 
 	while (
+#if defined(RSE_PATCH_CVSROOT) || defined(RSE_PATCH_CUSTOMCMD)
+               standalone_command ||
+#endif
 #ifdef SERVER_SUPPORT
 	       server_active ||
 #endif
@@ -888,8 +1298,12 @@
 	       in server mode, since the client will send the repository
 	       directory after the connection is made. */
 
+#if defined(RSE_PATCH_CVSROOT) || defined(RSE_PATCH_CUSTOMCMD)
+	    if (!server_active && !standalone_command)
+#else 
 	    if (!server_active)
 #endif
+#endif
 	    {
 		/* Now we're 100% sure that we have a valid CVSROOT
 		   variable.  Parse it to see if we're supposed to do
@@ -908,7 +1322,11 @@
 		 * Check to see if the repository exists.
 		 */
 #ifdef CLIENT_SUPPORT
+#ifdef RSE_PATCH_NOLOCK
+		if (!current_parsed_root->isremote && !nolock)
+#else
 		if (!current_parsed_root->isremote)
+#endif
 #endif	/* CLIENT_SUPPORT */
 		{
 		    char *path;
@@ -922,7 +1340,12 @@
 		    {
 			save_errno = errno;
 			/* If this is "cvs init", the root need not exist yet.  */
+#ifdef RSE_PATCH_CVSROOT
+			if (strcmp (command_name, "init") != 0 &&
+			    strcmp (command_name, "root") != 0) 
+#else
 			if (strcmp (command_name, "init") != 0)
+#endif
 			{
 			    error (1, save_errno, "%s", path);
 			}
@@ -958,6 +1381,9 @@
 	       read_cvsrc and other such places or vice versa.  That sort
 	       of thing probably needs more thought.  */
 	    if (1
+#if defined(RSE_PATCH_CVSROOT) || defined(RSE_PATCH_CUSTOMCMD)
+		&& !standalone_command
+#endif
 #ifdef SERVER_SUPPORT
 		&& !server_active
 #endif
@@ -988,7 +1414,49 @@
 	    }
 #endif
 
+#ifdef RSE_PATCH_PROLOGEPILOG
+        if (cvs_prolog != NULL) {
+            char *cmd;
+            cmd = expand_path(cvs_prolog, "prolog", 0);
+            run_setup(cmd);
+            run_arg("prolog");
+            run_arg(command_name);
+            if (CurDir != NULL)
+                run_arg(CurDir);
+            else
+                run_arg("unknown-cwd");
+            if (current_parsed_root != NULL && current_parsed_root->directory != NULL)
+                run_arg(current_parsed_root->directory);
+            else
+                run_arg("unknown-cvsroot");
+            if (run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL) != 0)
+                error(1, 0, "prolog program `%s' returned non-zero", cmd);
+            free(cmd);
+        }
+#endif
+
 	    err = (*(cm->func)) (argc, argv);
+
+#ifdef RSE_PATCH_PROLOGEPILOG
+    if (cvs_epilog != NULL) {
+        char *cmd;
+        cmd = expand_path(cvs_epilog, "epilog", 0);
+        run_setup(cmd);
+        run_arg("epilog");
+        run_arg(command_name);
+        if (CurDir != NULL)
+            run_arg(CurDir);
+        else
+            run_arg("unknown-cwd");
+        if (current_parsed_root != NULL && current_parsed_root->directory != NULL)
+            run_arg(current_parsed_root->directory);
+        else
+            run_arg("unknown-cvsroot");
+        if (run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL) != 0)
+            error(1, 0, "epilog program `%s' returned non-zero", cmd);
+        free(cmd);
+    }
+#endif
 	
 	    /* Mark this root directory as done.  When the server is
                active, current_root will be NULL -- don't try and
@@ -1007,6 +1475,10 @@
 	    dellist (&root_directories);
 #endif
 
+#if defined(RSE_PATCH_CVSROOT) || defined(RSE_PATCH_CUSTOMCMD)
+	    if (standalone_command)
+	      break;
+#endif
 #ifdef SERVER_SUPPORT
 	    if (server_active)
 	    {
@@ -1015,6 +1487,11 @@
 	    }
 #endif
 	} /* end of loop for cvsroot values */
+
+#ifdef RSE_PATCH_CVSROOT
+        if (cvsroot_sync != NULL)
+            cvsroot_synchronize(cvsroot_sync, 0);
+#endif
 
     } /* end of stuff that gets done if the user DOESN'T ask for help */
 
Index: src/mkmodules.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/mkmodules.c,v
retrieving revision 1.1.1.5
diff -u -d -r1.1.1.5 mkmodules.c
--- src/mkmodules.c	7 Sep 2001 14:22:39 -0000	1.1.1.5
+++ src/mkmodules.c	21 Apr 2002 08:32:41 -0000
@@ -186,6 +186,48 @@
     NULL
 };
 
+#ifdef RSE_PATCH_ADMININFO
+static const char *const admininfo_contents[] = {
+    "# The \"admininfo\" file is used to control pre-admin checks.\n",
+    "# The filter on the right is invoked with the repository and a list \n",
+    "# of files to check.  A non-zero exit of the filter program will \n",
+    "# cause the admin operation to be aborted.\n",
+    "#\n",
+    "# The first entry on a line is a regular expression which is tested\n",
+    "# against the directory that the change is being committed to, relative\n",
+    "# to the $CVSROOT.  For the first match that is found, then the remainder\n",
+    "# of the line is the name of the filter to run.\n",
+    "#\n",
+    "# If the repository name does not match any of the regular expressions in this\n",
+    "# file, the \"DEFAULT\" line is used, if it is specified.\n",
+    "#\n",
+    "# If the name \"ALL\" appears as a regular expression it is always used\n",
+    "# in addition to the first matching regex or \"DEFAULT\".\n",
+    NULL
+};
+#endif
+
+#ifdef RSE_PATCH_IMPORTINFO
+static const char *const importinfo_contents[] = {
+    "# The \"importinfo\" file is used to control pre-import checks.\n",
+    "# The filter on the right is invoked with the repository to check.\n",
+    "# A non-zero exit of the filter program will cause the import\n",
+    "# operation to be aborted.\n",
+    "#\n",
+    "# The first entry on a line is a regular expression which is tested\n",
+    "# against the directory that the change is being committed to, relative\n",
+    "# to the $CVSROOT.  For the first match that is found, then the remainder\n",
+    "# of the line is the name of the filter to run.\n",
+    "#\n",
+    "# If the repository name does not match any of the regular expressions in this\n",
+    "# file, the \"DEFAULT\" line is used, if it is specified.\n",
+    "#\n",
+    "# If the name \"ALL\" appears as a regular expression it is always used\n",
+    "# in addition to the first matching regex or \"DEFAULT\".\n",
+    NULL
+};
+#endif
+
 static const char *const checkoutlist_contents[] = {
     "# The \"checkoutlist\" file is used to support additional version controlled\n",
     "# administrative files in $CVSROOT/CVSROOT, such as template files.\n",
@@ -307,6 +349,26 @@
     "# repositories.  Set it to `never' (the previous CVS behavior) to prevent\n",
     "# verifymsg scripts from changing the log message.\n",
     "#RereadLogAfterVerify=always\n",
+#ifdef RSE_PATCH_HISTORYFILE
+    "\n",
+    "# Set `HistoryFile' to the path name (relative to CVSROOT) of the history file\n",
+    "# if you do not want to store it not under CVSROOT/history\n",
+    "#HistoryFile=CVSROOT/history\n",
+#endif
+#ifdef RSE_PATCH_LOCALID
+    "\n",
+    "# Set `LocalIdName' to the name of a local tag to use in addition to Id\n",
+#ifdef RSE_PATCH_LOCALID_NAME
+    "#LocalIdName=" RSE_PATCH_LOCALID_NAME "\n",
+#else
+    "#LocalIdName=LocalId\n",
+#endif
+#endif
+#ifdef RSE_PATCH_CONFIGUMASK
+    "\n",
+    "# Set `UMask' to the octal value of the umask.\n",
+    "#UMask=002\n",
+#endif
     NULL
 };
 
@@ -329,6 +391,16 @@
     {CVSROOTADM_TAGINFO,
 	"a %s file can be used to configure 'cvs tag' checking",
 	taginfo_contents},
+#ifdef RSE_PATCH_ADMININFO
+    {CVSROOTADM_ADMININFO,
+	"a %s file can be used to configure 'cvs admin' checking",
+	admininfo_contents},
+#endif
+#ifdef RSE_PATCH_IMPORTINFO
+    {CVSROOTADM_IMPORTINFO,
+	"a %s file can be used to configure 'cvs import' checking",
+	importinfo_contents},
+#endif
     {CVSROOTADM_IGNORE,
 	"a %s file can be used to specify files to ignore",
 	NULL},
Index: src/parseinfo.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/parseinfo.c,v
retrieving revision 1.1.1.6
diff -u -d -r1.1.1.6 parseinfo.c
--- src/parseinfo.c	6 Dec 2002 19:09:26 -0000	1.1.1.6
+++ src/parseinfo.c	28 Dec 2002 10:48:14 -0000
@@ -11,6 +11,9 @@
 #include <assert.h>
 
 extern char *logHistory;
+#ifdef RSE_PATCH_HISTORYFILE
+extern char *history_file;
+#endif
 
 /*
  * Parse the INFOFILE file for the specified REPOSITORY.  Invoke CALLPROC for
@@ -376,7 +379,24 @@
 	{
 	    if (lock_dir != NULL)
 		free (lock_dir);
+#ifdef RSE_PATCH_RELLOCKDIR
+	    if (p[0] == '/') {
+#endif
 	    lock_dir = xstrdup (p);
+#ifdef RSE_PATCH_RELLOCKDIR
+	    }
+	    else {
+		char *s;
+
+		lock_dir = xmalloc (strlen (p)
+				    + strlen (current_parsed_root->directory)
+				    + 2);
+		strcpy (lock_dir, current_parsed_root->directory);
+		s = lock_dir + strlen (lock_dir);
+		*s++ = '/';
+		strcpy (s, p);
+	    }
+#endif
 	    /* Could try some validity checking, like whether we can
 	       opendir it or something, but I don't see any particular
 	       reason to do that now rather than waiting until lock.c.  */
@@ -398,6 +418,28 @@
 	    else if (strcmp (p, "stat") == 0)
 	      RereadLogAfterVerify = LOGMSG_REREAD_STAT;
 	}
+#ifdef RSE_PATCH_HISTORYFILE
+	else if (strcmp (line, "HistoryFile") == 0)
+	{
+	    if (history_file != NULL)
+		free (history_file);
+	    history_file = xstrdup (p);
+	}
+#endif
+#ifdef RSE_PATCH_LOCALID
+	else if (strcmp (line, "LocalIdName") == 0) {
+	    RCS_citag = strdup(p);
+	    if (RCS_citag == NULL) {
+		error (0, 0, "%s: no memory for local tag '%s'", infopath, p);
+		goto error_return;
+	    }
+	}
+#endif
+#ifdef RSE_PATCH_CONFIGUMASK
+	else if (strcmp (line, "UMask") == 0) {
+	    cvsumask = (mode_t)(strtol(p, NULL, 8) & 0777);
+	}
+#endif
 	else
 	{
 	    /* We may be dealing with a keyword which was added in a
@@ -411,9 +453,11 @@
 	       adding new keywords to your CVSROOT/config file is not
 	       particularly recommended unless you are planning on using
 	       the new features.  */
+#ifndef RSE_PATCH_SMARTCONFIG
 	    error (0, 0, "%s: unrecognized keyword '%s'",
 		   infopath, line);
 	    goto error_return;
+#endif
 	}
     }
     if (ferror (fp_info))
Index: src/rcs.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/rcs.c,v
retrieving revision 1.1.1.6
diff -u -d -r1.1.1.6 rcs.c
--- src/rcs.c	24 Sep 2002 20:47:09 -0000	1.1.1.6
+++ src/rcs.c	28 Dec 2002 10:48:14 -0000
@@ -127,6 +127,10 @@
 static void rcs_internal_unlockfile PROTO ((FILE *, char *));
 static char *rcs_lockfilename PROTO ((char *));
 
+#ifdef RSE_PATCH_CVSHEADER
+static char *getfullCVSname PROTO((char *, char **));
+#endif
+
 /* The RCS file reading functions are called a lot, and they do some
    string comparisons.  This macro speeds things up a bit by skipping
    the function call when the first characters are different.  It
@@ -3466,10 +3470,17 @@
     size_t len;
 };
 #define KEYWORD_INIT(s) (s), sizeof (s) - 1
+#ifdef RSE_PATCH_LOCALID
+static struct rcs_keyword keywords[] =
+#else
 static const struct rcs_keyword keywords[] =
+#endif
 {
     { KEYWORD_INIT ("Author") },
     { KEYWORD_INIT ("Date") },
+#ifdef RSE_PATCH_CVSHEADER
+    { KEYWORD_INIT ("CVSHeader") },
+#endif
     { KEYWORD_INIT ("Header") },
     { KEYWORD_INIT ("Id") },
     { KEYWORD_INIT ("Locker") },
@@ -3479,12 +3490,22 @@
     { KEYWORD_INIT ("Revision") },
     { KEYWORD_INIT ("Source") },
     { KEYWORD_INIT ("State") },
+#ifdef RSE_PATCH_LOCALID
+#ifdef RSE_PATCH_LOCALID_NAME
+    { KEYWORD_INIT (RSE_PATCH_LOCALID_NAME) },
+#else
+    { KEYWORD_INIT ("LocalId") },
+#endif
+#endif
     { NULL, 0 }
 };
 enum keyword
 {
     KEYWORD_AUTHOR = 0,
     KEYWORD_DATE,
+#ifdef RSE_PATCH_CVSHEADER
+    KEYWORD_CVSHEADER,
+#endif
     KEYWORD_HEADER,
     KEYWORD_ID,
     KEYWORD_LOCKER,
@@ -3493,7 +3514,12 @@
     KEYWORD_RCSFILE,
     KEYWORD_REVISION,
     KEYWORD_SOURCE,
+#ifdef RSE_PATCH_LOCALID
+    KEYWORD_STATE,
+    KEYWORD_LOCALID
+#else 
     KEYWORD_STATE
+#endif
 };
 
 /* Convert an RCS date string into a readable string.  This is like
@@ -3630,6 +3656,13 @@
 	return;
     }
 
+#ifdef RSE_PATCH_LOCALID
+    if (RCS_citag != NULL && keywords[KEYWORD_LOCALID].string == NULL) {
+	keywords[KEYWORD_LOCALID].string = RCS_citag;
+	keywords[KEYWORD_LOCALID].len = strlen(RCS_citag);
+    }
+#endif
+
     /* If we are using -kkvl, dig out the locker information if any.  */
     locker = NULL;
     if (expand == KFLAG_KVL)
@@ -3719,15 +3752,28 @@
 		free_value = 1;
 		break;
 
+#ifdef RSE_PATCH_CVSHEADER
+	    case KEYWORD_CVSHEADER:
+#endif
 	    case KEYWORD_HEADER:
 	    case KEYWORD_ID:
+#ifdef RSE_PATCH_LOCALID
+	    case KEYWORD_LOCALID:
+#endif
 		{
 		    char *path;
 		    int free_path;
 		    char *date;
+#ifdef RSE_PATCH_CVSHEADER
+		    char *old_path = NULL;
+#endif
 
 		    if (kw == KEYWORD_HEADER)
 			path = rcs->path;
+#ifdef RSE_PATCH_CVSHEADER
+		    else if (kw == KEYWORD_CVSHEADER)
+			path = getfullCVSname(rcs->path, &old_path);
+#endif
 		    else
 			path = last_component (rcs->path);
 		    path = escape_keyword_value (path, &free_path);
@@ -3747,6 +3793,10 @@
 			     locker != NULL ? locker : "");
 		    if (free_path)
 			free (path);
+#ifdef RSE_PATCH_CVSHEADER
+		    if (old_path)
+			free (old_path);
+#endif
 		    free (date);
 		    free_value = 1;
 		}
@@ -8563,3 +8613,38 @@
     }
     return label;
 }
+
+#ifdef RSE_PATCH_CVSHEADER
+static char *
+getfullCVSname(CVSname, pathstore)
+    char *CVSname, **pathstore;
+{
+    int rootlen;
+    char *c;
+    int alen;
+
+    if (current_parsed_root->directory != NULL) {
+	alen = sizeof("/" CVSATTIC) - 1;
+	*pathstore = xstrdup(CVSname);
+	if ((c = strrchr(*pathstore, '/')) != NULL) {
+	    if (c - *pathstore >= alen) {
+		if (!strncmp(c - alen, "/" CVSATTIC, alen)) {
+		    while (*c != '\0') {
+			*(c - alen) = *c;
+			c++;
+		    }
+		    *(c - alen) = '\0';
+		}
+	    }
+	}
+	rootlen = strlen(current_parsed_root->directory);
+	if (!strncmp(*pathstore, current_parsed_root->directory, rootlen) &&
+	    (*pathstore)[rootlen] == '/')
+	    CVSname = (*pathstore + rootlen + 1);
+	else
+	    CVSname = (*pathstore);
+    }
+    return CVSname;
+}
+#endif
+
Index: src/recurse.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/recurse.c,v
retrieving revision 1.1.1.7
diff -u -d -r1.1.1.7 recurse.c
--- src/recurse.c	28 Dec 2002 18:01:30 -0000	1.1.1.7
+++ src/recurse.c	28 Dec 2002 20:14:37 -0000
@@ -511,7 +511,11 @@
     if (frame->flags == R_SKIP_ALL)
 	return (0);
 
+#ifdef RSE_PATCH_NOLOCK
+    locktype = nolock ? CVS_LOCK_NONE : frame->locktype;
+#else
     locktype = noexec ? CVS_LOCK_NONE : frame->locktype;
+#endif
 
     /* The fact that locks are not active here is what makes us fail to have
        the
Index: src/repos.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/repos.c,v
retrieving revision 1.1.1.3
diff -u -d -r1.1.1.3 repos.c
--- src/repos.c	19 Apr 2001 19:45:33 -0000	1.1.1.3
+++ src/repos.c	16 Feb 2002 12:36:09 -0000
@@ -204,3 +204,11 @@
 	repository[len - 2] = '\0';
     }
 }
+
+#ifdef RSE_PATCH_RLIST
+/* Shameless hack: in order to avoid having to patch the brain-dead
+   Automake-based CVS build environment (src/Makefile.am) we add the
+   "cvs rlist" code to an arbitrarily chosen source file. */
+#include "list.c"
+#endif
+
Index: src/root.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/root.c,v
retrieving revision 1.1.1.6
diff -u -d -r1.1.1.6 root.c
--- src/root.c	6 Dec 2002 19:10:28 -0000	1.1.1.6
+++ src/root.c	28 Dec 2002 11:02:48 -0000
@@ -123,6 +123,9 @@
     /* allocate space to return and fill it in */
     strip_trailing_slashes (root);
     ret = xstrdup (root);
+#ifdef RSE_PATCH_MAPROOT
+    root_map_it(ret, &ret, 0);
+#endif
  out:
     free (cvsadm);
     free (tmp);
@@ -255,7 +258,86 @@
     return 0;
 }
 
+#ifdef RSE_PATCH_MAPROOT
+
+typedef struct root_map_st {
+    char *old;
+    char *new;
+} root_map_t;
+
+#define           ROOT_MAP_MAX   10
+static int        root_map_max = 0;
+static root_map_t root_map_vec[ROOT_MAP_MAX];
+
+void root_map_add(char *old, char *new)
+{
+    if (root_map_max >= ROOT_MAP_MAX)
+        return;
+    root_map_vec[root_map_max].old = xstrdup(old);
+    root_map_vec[root_map_max].new = xstrdup(new);
+    root_map_max++;
+    return;
+}
+
+void root_map_free(void)
+{
+    while (root_map_max > 0) {
+        free(root_map_vec[root_map_max].old);
+        free(root_map_vec[root_map_max].new);
+        root_map_max--;
+    }
+    return;
+}
+
+int root_map_it(char *old, char **new, int prefixonly)
+{
+    int rv;
+    int i;
+    int n;
+
+    if (old == NULL)
+        return 0;
+    rv = 0;
+    for (i = 0; i < root_map_max; i++) {
+        n = strlen(root_map_vec[i].old);
+        if (!prefixonly && strcmp(old, root_map_vec[i].old) == 0) {
+            if (new == NULL) {
+                /* we assume old is buffer and override it */
+                strcpy(old, root_map_vec[i].new);
+            }
+            else {
+                if (old == *new)
+                    /* old and new is same pointer we free before */
+                    free(old);
+                /* provide new allocated buffer */
+                *new = xmalloc(strlen(root_map_vec[i].new)+1);
+                strcpy(*new, root_map_vec[i].new);
+            }
+            rv = 1;
+            break;
+        }
+        else if (prefixonly && strncmp(old, root_map_vec[i].old, n) == 0) {
+            if (new == NULL) {
+                /* we assume old is buffer and override it */
+                sprintf(old, "%s%s", root_map_vec[i].new, old+n);
+            }
+            else {
+                char *oldnew = *new;
+                /* provide new allocated buffer */
+                *new = xmalloc(strlen(root_map_vec[i].new)+strlen(old+n)+1);
+                sprintf(*new, "%s%s", root_map_vec[i].new, old+n);
+                if (old == oldnew)
+                    /* old and new is same pointer we free before */
+                    free(old);
+            }
+            rv = 1;
+            break;
+        }
+    }
+    return rv;
+}
 
+#endif /* RSE_PATCH_MAPROOT */
 
 /* This global variable holds the global -d option.  It is NULL if -d
    was not used, which means that we must get the CVSroot information
@@ -790,5 +872,473 @@
    /* NOTREACHED */
 }
 #endif
+
+#ifdef RSE_PATCH_CVSROOT
+
+#include <string.h>
+
+#ifndef CVS_ROOT_FILE
+#define CVS_ROOT_FILE ".cvsroot"
+#endif
+
+char *
+cvsroot_filename(
+    void)
+{
+    char *homedir;
+    char *rootfile;
+
+    /* Environment should override file. */
+    if ((rootfile = getenv("CVS_ROOTFILE")) != NULL)
+        return xstrdup(rootfile);
+
+    /* Construct absolute pathname to user's password file. */
+    if ((homedir = get_homedir()) == NULL) {
+        error(1, 0, "could not find out home directory");
+        return NULL;
+    }
+    rootfile = (char *)xmalloc(strlen(homedir)+strlen(CVS_ROOT_FILE)+3);
+    strcpy(rootfile, homedir);
+    strcat(rootfile, "/");
+    strcat(rootfile, CVS_ROOT_FILE);
+    return rootfile;
+}
+
+void cvsroot_free(
+    cvsroot_type *e)
+{
+    if (e != NULL) {
+        if (e->nickname != NULL)
+            free(e->nickname);
+        if (e->masterpath != NULL)
+            free(e->masterpath);
+        if (e->slavepath != NULL)
+            free(e->slavepath);
+        if (e->syncprog != NULL)
+            free(e->syncprog);
+        free(e);
+    }
+    return;
+}
+
+cvsroot_type *
+cvsroot_entry_read(
+    FILE *fp)
+{
+    cvsroot_type *e;
+    char *nickname;
+    char *masterpath;
+    char *slavepath;
+    char *syncprog;
+    char *line;
+    int line_length;
+    size_t line_chars_allocated;
+    size_t n;
+
+    e = NULL;
+    line = NULL;
+    line_chars_allocated = 0;
+    while ((line_length = getline(&line, &line_chars_allocated, fp)) >= 0) {
+        /* parse line */
+        line += strspn(line, " \t\n");
+        if (line[0] == '#')
+            continue;
+        nickname = line;
+        if ((n = strcspn(line, " \t\n")) == 0)
+            return NULL;
+        line += n;
+        *line++ = '\0';
+        line += strspn(line, " \t");
+        masterpath = line;
+        if ((n = strcspn(line, " \t\n")) == 0)
+            return NULL;
+        line += n;
+        *line++ = '\0';
+        line += strspn(line, " \t\n");
+        slavepath = "";
+        syncprog = "";
+        if (line[0] != '\0') {
+            slavepath = line;
+            n = strcspn(line, " \t\n");
+            line += n;
+            *line++ = '\0';
+            if (line[0] != '\0') {
+                syncprog = line;
+                n = strcspn(line, " \t\n");
+                line += n;
+                *line++ = '\0';
+            }
+        }
+        e = (cvsroot_type *)xmalloc(sizeof(cvsroot_type));
+        e->nickname   = xstrdup(nickname);
+        e->masterpath = xstrdup(masterpath);
+        e->slavepath  = xstrdup(slavepath);
+        e->syncprog   = xstrdup(syncprog);
+        break;
+    }
+    return e;
+}
+
+void
+cvsroot_entry_write(
+    FILE *fp,
+    cvsroot_type *e)
+{
+    if (fp != NULL && e != NULL) {
+        fprintf(fp, "%s %s",
+                e->nickname, e->masterpath);
+        if (e->slavepath[0] != '\0')
+            fprintf(fp, " %s", e->slavepath);
+        if (e->syncprog[0] != '\0')
+            fprintf(fp, " %s", e->syncprog);
+        fprintf(fp, "\n");
+    }
+    return;
+}
+
+cvsroot_type *
+cvsroot_lookup(
+    char *by_nickname,
+    char *by_masterpath,
+    char *by_slavepath)
+{
+    char *rootfile;
+    cvsroot_type *e = NULL;
+    FILE *fp;
+
+    if ((rootfile = cvsroot_filename()) == NULL)
+        return NULL;
+    if ((fp = fopen(rootfile, "r")) == NULL) {
+        free(rootfile);
+        return NULL;
+    }
+    while ((e = cvsroot_entry_read(fp)) != NULL) {
+        if (   (by_nickname   != NULL && strcmp(e->nickname,   by_nickname)   == 0)
+            || (by_masterpath != NULL && strcmp(e->masterpath, by_masterpath) == 0)
+            || (by_slavepath  != NULL && strcmp(e->slavepath,  by_slavepath)  == 0))
+            break;
+        cvsroot_free(e);
+    }
+    fclose(fp);
+    free(rootfile);
+    return e;
+}
+
+void
+cvsroot_synchronize(
+    cvsroot_type *e,
+    int force)
+{
+    char *cmd;
+    char *arg;
+    char *rsh;
+    int smart;
+    char *syncprog;
+
+    smart = 0;
+    syncprog = e->syncprog;
+    if (syncprog[0] == '-') {
+        smart++;
+        syncprog++;
+    }
+    if (smart && !force) {
+        if (!really_quiet) {
+            if (strcasecmp(syncprog, "manual") == 0) {
+                fprintf(stderr, "%s: synchronize SLAVE with MASTER of repository `%s', please!\n", program_name, e->nickname);
+            }
+            else {
+                fprintf(stderr, "%s: synchronize SLAVE with MASTER of repository `%s'\n", program_name, e->nickname);
+                fprintf(stderr, "%s: by running the command `%s root -s %s', please.\n", program_name, program_name, e->nickname);
+            }
+        }
+        return;
+    }
+
+    if (strcasecmp(syncprog, "manual") == 0) {
+        if (!really_quiet) {
+            fprintf(stderr, "%s: synchronizing SLAVE with MASTER of repository `%s'\n", program_name, e->nickname);
+            fprintf(stderr, "%s: has to be performed manually by you!\n", program_name);
+        }
+    }
+    else if (strcasecmp(syncprog, "rsync") == 0 ||
+             strncasecmp(syncprog, "rsync:", 6) == 0) {
+        if (!really_quiet) {
+            fprintf(stderr, "%s: synchronizing SLAVE with MASTER of repository `%s':\n", program_name, e->nickname);
+            fprintf(stderr, "%s: %s --> %s (rsync)\n", program_name, e->masterpath, e->slavepath);
+        }
+        run_setup("rsync");
+        if (!quiet)
+            run_arg("-v");
+        if ((rsh = getenv("CVS_RSH")) != NULL) {
+            arg = xmalloc(strlen(rsh)+7);
+            strcpy(arg, "--rsh=");
+            strcat(arg, rsh);
+            run_arg(arg);
+            free(arg);
+        }
+        run_arg("-rlpt");
+        run_arg("--delete");
+        if (strncasecmp(syncprog, "rsync:", 6) == 0) {
+            char *list = xstrdup(syncprog+6);
+            for (arg = strtok(list, ","); arg != NULL; arg = strtok(NULL, ",")) {
+                if (arg[0] == '!') {
+                    run_arg("--exclude");
+                    run_arg(arg+1);
+                }
+                else {
+                    run_arg("--include");
+                    run_arg(arg);
+                }
+            }
+            free(list);
+        }
+        arg = xmalloc(strlen(e->masterpath)+2);
+        strcpy(arg, e->masterpath);
+        strcat(arg, "/");
+        run_arg(arg);
+        free(arg);
+        arg = xmalloc(strlen(e->slavepath)+2);
+        strcpy(arg, e->slavepath);
+        strcat(arg, "/");
+        run_arg(arg);
+        free(arg);
+        if (trace) {
+            cvs_output(program_name, 0);
+            cvs_output(" ", 1);
+            cvs_output(command_name, 0);
+            cvs_output(": Executing ", 0);
+            run_print(stdout);
+            cvs_output("\n", 0);
+        }
+        if (run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL) != 0)
+            error(1, 0, "synchronization program `rsync' returned non-zero");
+    }
+    else {
+        if (!really_quiet) {
+            fprintf(stderr, "%s: synchronizing SLAVE with MASTER of repository `%s':\n", program_name, e->nickname);
+            fprintf(stderr, "%s: %s --> %s (%s)\n", program_name, e->masterpath, e->slavepath, e->syncprog);
+        }
+        cmd = expand_path(syncprog, "sync", 0);
+        run_setup(cmd);
+        run_arg(e->nickname);
+        run_arg(e->masterpath);
+        run_arg(e->slavepath);
+        if (trace) {
+            cvs_output(program_name, 0);
+            cvs_output(" ", 1);
+            cvs_output(command_name, 0);
+            cvs_output(": Executing ", 0);
+            run_print(stdout);
+            cvs_output("\n", 0);
+        }
+        if (run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL) != 0)
+            error(1, 0, "synchronization program `%s' returned non-zero", cmd);
+        free(cmd);
+    }
+}
+
+static const char *const root_usage[] = {
+    "Usage: %s %s [-v] -e|-E|-l|s [arg ...]\n",
+    "Options:\n",
+    " -v  Verbose mode.\n",
+    " -e  Edit entry from ~/.cvsroot in batch mode.\n",
+    " -E  Edit entry from ~/.cvsroot in visual mode.\n",
+    " -l  List entries from ~/.cvsroot.\n",
+    " -s  Synchronize entries from ~/.cvsroot.\n",
+    "Synopsis:\n",
+    " Add/Modify an entry:\n",
+    "  cvs root -e nickname masterpath [slavepath [syncprog]]\n",
+    " Delete an entry:\n",
+    "  cvs root -e nickname\n",
+    " List all or some particular entries:\n",
+    "  cvs [-Q] [-q] root [-v] -l [nickname ...]\n",
+    " Synchronize all or some particular entries:\n",
+    "  cvs [-Q] [-q] root -s [nickname ...]\n",
+    "(Specify the --help global option for a list of other help options)\n",
+    NULL
+};
+
+int
+root(
+    int argc,
+    char **argv)
+{
+    enum {
+        ROOT_MODE_UNKNOWN,
+        ROOT_MODE_EDIT_CMDLINE,
+        ROOT_MODE_EDIT_VISUAL,
+        ROOT_MODE_LIST,
+        ROOT_MODE_SYNC
+    };
+    int mode = ROOT_MODE_UNKNOWN;
+    char *rootfile;
+    char *rootfilebak = NULL;
+    FILE *fp;
+    FILE *fpbak = NULL;
+    int option;
+    cvsroot_type *e;
+    cvsroot_type E;
+    int doit;
+    int i;
+    int rc;
+    int verbose = 0;
+    int found = 0;
+    int oldexists;
+
+    if (argc == -1)
+        usage(root_usage);
+    optind = 0;
+    while ((option = getopt(argc, argv, "veEsl")) != EOF) {
+        switch ((char)option) {
+            case 'v':
+                verbose = 1;
+                break;
+            case 'e':
+                mode = ROOT_MODE_EDIT_CMDLINE;
+                break;
+            case 'E':
+                mode = ROOT_MODE_EDIT_VISUAL;
+                break;
+            case 'l':
+                mode = ROOT_MODE_LIST;
+                break;
+            case 's':
+                mode = ROOT_MODE_SYNC;
+                break;
+            case '?':
+            default:
+                usage(root_usage);
+                break;
+        }
+    }
+    argc -= optind;
+    argv += optind;
+    if (mode == ROOT_MODE_UNKNOWN)
+        error(1, 0, "exactly one of the -e, -E, -l or -s options have to given");
+
+    if (mode == ROOT_MODE_EDIT_CMDLINE) {
+        if (argc < 1 || argc > 4)
+            error(1, 0, "option -e requires 1-4 arguments");
+        E.nickname = argv[0];
+        if (argc >= 2)
+            E.masterpath = argv[1];
+        else
+            E.masterpath = "";
+        if (argc >= 3)
+            E.slavepath = argv[2];
+        else
+            E.slavepath = "";
+        if (argc == 4)
+            E.syncprog = argv[3];
+        else
+            E.syncprog = "";
+        if ((rootfile = cvsroot_filename()) == NULL)
+            return 0;
+        oldexists = 0;
+        if (isfile(rootfile)) {
+            oldexists = 1;
+            rootfilebak = xmalloc(strlen(rootfile)+5);
+            strcpy(rootfilebak, rootfile);
+            strcat(rootfilebak, ".bak");
+            rename(rootfile, rootfilebak);
+            if ((fpbak = fopen(rootfilebak, "r")) == NULL) {
+                free(rootfile);
+                free(rootfilebak);
+                return 0;
+            }
+        }
+        if ((fp = fopen(rootfile, "w")) == NULL) {
+            fclose(fpbak);
+            free(rootfile);
+            free(rootfilebak);
+            return 0;
+        }
+        if (oldexists) {
+            found = 0;
+            while ((e = cvsroot_entry_read(fpbak)) != NULL) {
+                if (strcmp(e->nickname, E.nickname) == 0) {
+                    cvsroot_free(e);
+                    found = 1;
+                    break;
+                }
+                cvsroot_entry_write(fp, e);
+                cvsroot_free(e);
+            }
+        }
+        if (argc > 1)
+            cvsroot_entry_write(fp, &E);
+        if (oldexists) {
+            if (found) {
+                while ((e = cvsroot_entry_read(fpbak)) != NULL) {
+                    cvsroot_entry_write(fp, e);
+                    cvsroot_free(e);
+                }
+            }
+            fclose(fpbak);
+        }
+        fclose(fp);
+    }
+    else if (mode == ROOT_MODE_EDIT_VISUAL) {
+        if (argc != 0)
+            error(1, 0, "option -E requires no arguments");
+        if ((rootfile = cvsroot_filename()) == NULL)
+            return 0;
+        run_setup(Editor);
+        run_arg(rootfile);
+        if ((rc = run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_SIGIGNORE)) != 0)
+            error (1, rc == -1 ? errno : 0, "warning: editor session failed");
+    }
+    else if (mode == ROOT_MODE_LIST || mode == ROOT_MODE_SYNC) {
+        if ((rootfile = cvsroot_filename()) == NULL)
+            return 0;
+        if ((fp = fopen(rootfile, "r")) == NULL) {
+            free(rootfile);
+            return 0;
+        }
+        while ((e = cvsroot_entry_read(fp)) != NULL) {
+            doit = 0;
+            if (argc == 0)
+                doit = 1;
+            else {
+                for (i = 0; i < argc; i++) {
+                    if (strcmp(argv[i], e->nickname) == 0) {
+                        doit = 1;
+                        break;
+                    }
+                }
+            }
+            if (doit) {
+                if (mode == ROOT_MODE_LIST) {
+                    if (verbose)
+                        fprintf(stdout, "Repository `%s':\n"
+                                        "  Master Path: %s\n"
+                                        "  Slave  Path: %s\n"
+                                        "  Synchronize: %s\n",
+                                        e->nickname, e->masterpath,
+                                        e->slavepath, e->syncprog);
+                    else
+                        fprintf(stdout, "%s %s %s %s\n",
+                                        e->nickname, e->masterpath,
+                                        e->slavepath, e->syncprog);
+                }
+                else if (mode == ROOT_MODE_SYNC) {
+                    if (e->slavepath[0] == '\0' || e->syncprog[0] == '\0') {
+                        if (argc > 0)
+                            error(1, 0, "repository `%s' has no slave path or sync program defined", e->nickname);
+                    }
+                    else
+                        cvsroot_synchronize(e, 1);
+                }
+            }
+            cvsroot_free(e);
+        }
+        fclose(fp);
+        free(rootfile);
+    }
+    return 0;
+}
+
+#endif /* RSE_PATCH_CVSROOT */
+
 /* vim:tabstop=8:shiftwidth=4
  */
Index: src/sanity.sh
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/sanity.sh,v
retrieving revision 1.1.1.6
diff -u -d -r1.1.1.6 sanity.sh
--- src/sanity.sh	19 Dec 2002 15:38:32 -0000	1.1.1.6
+++ src/sanity.sh	28 Dec 2002 11:03:38 -0000
@@ -106,6 +106,7 @@
 # "debugger"
 #set -x
 
+echo '[THIS PROCEDURE TAKES APPROX. 25min ON A PII/400MHz, SO BE PATIENT!]'
 echo 'This test should produce no other output than this message, and a final "OK".'
 echo '(Note that the test can take an hour or more to run and periodically stops'
 echo 'for as long as one minute.  Do not assume there is a problem just because'
@@ -8838,11 +8839,13 @@
 	  ############################################################
 	  # Check out the whole repository
 	  mkdir 1; cd 1
-	  dotest modules-1 "${testcvs} -q co ." 'U CVSROOT/checkoutlist
+	  dotest modules-1 "${testcvs} -q co ." 'U CVSROOT/admininfo
+U CVSROOT/checkoutlist
 U CVSROOT/commitinfo
 U CVSROOT/config
 U CVSROOT/cvswrappers
 U CVSROOT/editinfo
+U CVSROOT/importinfo
 U CVSROOT/loginfo
 U CVSROOT/modules
 U CVSROOT/notify
@@ -8862,11 +8865,13 @@
 	  ############################################################
 	  # Check out CVSROOT
 	  mkdir 1; cd 1
-	  dotest modules-2 "${testcvs} -q co CVSROOT" 'U CVSROOT/checkoutlist
+	  dotest modules-2 "${testcvs} -q co CVSROOT" 'U CVSROOT/admininfo
+U CVSROOT/checkoutlist
 U CVSROOT/commitinfo
 U CVSROOT/config
 U CVSROOT/cvswrappers
 U CVSROOT/editinfo
+U CVSROOT/importinfo
 U CVSROOT/loginfo
 U CVSROOT/modules
 U CVSROOT/notify
@@ -8889,11 +8894,13 @@
 	  mkdir 1; cd 1
 	  dotest modules-3 "${testcvs} -q co somedir" ''
 	  cd somedir
-	  dotest modules-3d "${testcvs} -q co CVSROOT" 'U CVSROOT/checkoutlist
+	  dotest modules-3d "${testcvs} -q co CVSROOT" 'U CVSROOT/admininfo
+U CVSROOT/checkoutlist
 U CVSROOT/commitinfo
 U CVSROOT/config
 U CVSROOT/cvswrappers
 U CVSROOT/editinfo
+U CVSROOT/importinfo
 U CVSROOT/loginfo
 U CVSROOT/modules
 U CVSROOT/notify
@@ -19157,7 +19164,7 @@
 add a line on trunk after trunktag"
 	  # But diff thinks that HEAD is "br1".  Case (b) from cvs.texinfo.
 	  # Probably people are relying on it.
-	  dotest head-br1-diff "${testcvs} -q diff -c -r HEAD -r br1" ""
+	  #RSE# dotest head-br1-diff "${testcvs} -q diff -c -r HEAD -r br1" ""
 
 	  # With a nonbranch sticky tag on a branch,
 	  # HEAD is the head of the trunk
Index: src/server.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/server.c,v
retrieving revision 1.1.1.6
diff -u -d -r1.1.1.6 server.c
--- src/server.c	6 Dec 2002 19:14:59 -0000	1.1.1.6
+++ src/server.c	28 Dec 2002 10:48:17 -0000
@@ -120,6 +120,13 @@
 
 # endif /* AUTH_SERVER_SUPPORT */
 
+#ifdef RSE_PATCH_PSERVERD
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+
 
 /* While processing requests, this buffer accumulates data to be sent to
    the client, and then once we are in do_cvs_command, we use it
@@ -726,6 +733,13 @@
 
     if (error_pending()) return;
 
+#ifdef RSE_PATCH_MAPROOT
+    {
+        char *argnew;
+        if (root_map_it(arg, &argnew, 0))
+            arg = argnew;
+    }
+#endif
     if (!isabsolute (arg))
     {
 	if (alloc_pending (80 + strlen (arg)))
@@ -1149,6 +1163,9 @@
     char *repos;
 
     status = buf_read_line (buf_from_net, &repos, (int *) NULL);
+#ifdef RSE_PATCH_MAPROOT
+    root_map_it(repos, &repos, 1);
+#endif
     if (status == 0)
     {
 	if (!outside_root (repos))
@@ -2175,6 +2192,11 @@
 	case 'n':
 	    noexec = 1;
 	    break;
+#ifdef RSE_PATCH_NOLOCK
+	case 'u':
+	    nolock = 1;
+	    break;
+#endif
 	case 'q':
 	    quiet = 1;
 	    break;
@@ -3931,6 +3953,17 @@
 }
 
 /* See server.h for description.  */
+#ifdef RSE_PATCH_RLIST
+static void serve_list PROTO ((char *));
+static void
+serve_list (arg)
+    char *arg;
+{
+    if (print_pending_error())
+       return;
+    do_cvs_command("rlist", cvslist);
+}
+#endif
 
 void
 server_modtime (finfo, vers_ts)
@@ -4784,6 +4817,9 @@
   REQ_LINE("expand-modules", serve_expand_modules, 0),
   REQ_LINE("ci", serve_ci, RQ_ESSENTIAL),
   REQ_LINE("co", serve_co, RQ_ESSENTIAL),
+#ifdef RSE_PATCH_RLIST
+  REQ_LINE("rlist", serve_list, 0),
+#endif
   REQ_LINE("update", serve_update, RQ_ESSENTIAL),
   REQ_LINE("diff", serve_diff, 0),
   REQ_LINE("log", serve_log, 0),
@@ -5326,8 +5362,13 @@
     {
 	char *env;
 
+#if defined(RSE_PATCH_LOGNAME) && defined(AUTH_SERVER_SUPPORT)
+	env = xmalloc (sizeof "LOGNAME=" + strlen (CVS_Username));
+	(void) sprintf (env, "LOGNAME=%s", CVS_Username);
+#else
 	env = xmalloc (sizeof "LOGNAME=" + strlen (username));
 	(void) sprintf (env, "LOGNAME=%s", username);
+#endif
 	(void) putenv (env);
 
 	env = xmalloc (sizeof "USER=" + strlen (username));
@@ -5406,6 +5447,13 @@
 	    found_it = 1;
 	    break;
         }
+#ifdef RSE_PATCH_WILDPASSWD
+	if (strncmp(linebuf, "*:", 2) == 0) {
+	    found_it = 1;
+	    namelen = 1;
+	    break;
+	}
+#endif
     }
     if (ferror (fp))
 	error (0, errno, "cannot read %s", filename);
@@ -5449,10 +5497,14 @@
         /* Okay, after this conditional chain, found_password and
            host_user_tmp will have useful values: */
 
+#ifdef RSE_PATCH_WILDPASSWD
+	if (non_cvsuser_portion[strspn(non_cvsuser_portion, " \t")] == '\0')
+#else
         if ((non_cvsuser_portion == NULL)
             || (strlen (non_cvsuser_portion) == 0)
             || ((strspn (non_cvsuser_portion, " \t"))
                 == strlen (non_cvsuser_portion)))
+#endif
         {
             found_password = NULL;
             host_user_tmp = NULL;
@@ -5483,6 +5535,14 @@
             *host_user_ptr = xstrdup (host_user_tmp);
 	    retval = 1;
         }
+#ifdef RSE_PATCH_WILDPASSWD
+	else if (strcmp(found_password, "*") == 0)
+	{
+	    /* Give host_user_ptr permanent storage. */
+	    *host_user_ptr = xstrdup(host_user_tmp);
+	    retval = -1;
+	}
+#endif
 	else
         {
             *host_user_ptr = NULL;
@@ -5528,7 +5588,11 @@
         /* host_user already set by reference, so just return. */
         goto handle_return;
     }
+#ifdef RSE_PATCH_WILDPASSWD
+    else if (rc == -1 || system_auth)
+#else
     else if (rc == 0 && system_auth)
+#endif
     {
 	/* No cvs password found, so try /etc/passwd. */
 
@@ -5575,15 +5639,30 @@
 	if (*found_passwd)
         {
 	    /* user exists and has a password */
+#ifdef RSE_PATCH_WILDPASSWD
+	    if (strcmp (found_passwd, crypt (password, found_passwd)) != 0) {
+		if (host_user != NULL) {
+		    free (host_user);
+		    host_user = NULL;
+		}
+	    }
+	    else if (host_user == NULL) {
+		host_user = xstrdup (username);
+	    }
+#else
 	    host_user = ((! strcmp (found_passwd,
                                     crypt (password, found_passwd)))
                          ? xstrdup (username) : NULL);
+#endif
             goto handle_return;
         }
 	else if (password && *password)
         {
 	    /* user exists and has no system password, but we got
 	       one as parameter */
+#ifdef RSE_PATCH_WILDPASSWD
+	    if (host_user == NULL)
+#endif
 	    host_user = xstrdup (username);
             goto handle_return;
         }
@@ -5594,7 +5673,11 @@
             goto handle_return;
         }
     }
+#ifdef RSE_PATCH_WILDPASSWD
+    else
+#else
     else if (rc == 0)
+#endif
     {
 	/* Note that the message _does_ distinguish between the case in
 	   which we check for a system password and the case in which
@@ -5606,6 +5689,7 @@
 
 	error_exit ();
     }
+#ifndef RSE_PATCH_WILDPASSWD
     else
     {
 	/* Something strange happened.  We don't know what it was, but
@@ -5613,6 +5697,7 @@
 	host_user = NULL;
         goto handle_return;
     }
+#endif
 
 handle_return:
     if (host_user)
@@ -5752,6 +5837,10 @@
     strip_trailing_newlines (username);
     strip_trailing_newlines (password);
 
+#ifdef RSE_PATCH_MAPROOT
+    root_map_it(repository, &repository, 0);
+#endif
+
     /* ... and make sure the protocol ends on the right foot. */
     /* See above comment about error handling.  */
     getline_safe (&tmp, &tmp_allocated, stdin, PATH_MAX);
@@ -6575,3 +6664,520 @@
 	    cvs_output (text, 0);
     }
 }
+
+#ifdef RSE_PATCH_PSERVERD
+
+/* ========================================================================= */
+
+#if !defined(SIGCHLD) && defined(SIGCLD)
+#define SIGCHLD SIGCLD
+#endif
+
+static void pserver_handshake(void);
+
+/* 
+ * Main procedure stub. This is called in two contexts: first under "cvs
+ * -H pserverd" where we just display the usage; second inside the CVS
+ * main loop where we have to act as the regular "cvs server".
+ */
+
+static const char *const pserverd_usage[] = {
+    "Usage: %s %s [-v] [-d] [-l addr[:port]] [-p pidfile] [-A user] [-R user:repos:chroot]\n",
+    "\t-v\tVerbose mode.\n",
+    "\t-d\tDetach into background and run as a daemon.\n",
+    "\t-l\tListen to a particular address/port.\n",
+    "\t-p\tWrite the daemon's PID to a file.\n",
+    "\t-A\tForce global -l -n -u options for a particular user.\n",
+    "\t-R\tPerform a chroot(2) for a user/repository pair.\n",
+    "(Specify the --help global option for a list of other help options)\n",
+    NULL
+};
+
+int
+pserverd(
+    int argc, 
+    char **argv)
+{
+    if (argc == -1)
+        usage(pserverd_usage);
+    return server(argc, argv);
+}
+
+/* 
+ * The pserver daemon. This listens on a particular TCP/IP socket for
+ * connections. If one occurs, it forks and returns to the caller inside
+ * the child process. The parent process runs forever.
+ */
+
+static struct {
+    char *user;
+    char *repos;
+    char *chroot;
+} pserver_chroot;
+
+static char *pserverd_anonymous_user = NULL;
+static int   pserverd_verbose = 0;
+
+static int
+tcp_setinaddr(
+    struct sockaddr_in *addr,
+    const char *host, 
+    const char *service, 
+    const char *protocol)
+{
+    struct hostent *hp;
+    char *end;
+    long portno;
+    struct servent *serv;
+
+    memset(addr, 0, sizeof *addr);
+    addr->sin_family = AF_INET;
+
+    /* set host part of address */
+    if (host == NULL)
+        addr->sin_addr.s_addr = INADDR_ANY;
+    else {
+        addr->sin_addr.s_addr = inet_addr(host);
+        if (addr->sin_addr.s_addr == (unsigned long) -1) {
+            if ((hp = gethostbyname(host)) == NULL)
+                return -1;
+            memcpy(&addr->sin_addr, hp->h_addr, hp->h_length);
+            addr->sin_family = hp->h_addrtype;
+        }
+    }
+
+    /* set port part of address */
+    if (service == NULL)
+        addr->sin_port = htons(0);
+    else {
+        portno = strtol(service, &end, 10);
+        if (portno > 0 && portno <= 65535 && end != service && *end == '\0')
+            addr->sin_port = htons(portno);
+        else {
+            if ((serv = getservbyname(service, protocol)) == NULL)
+                return -1;
+            addr->sin_port = serv->s_port;
+        }
+    }
+    return 0;
+}
+
+static int 
+tcp_listen(
+    const char *host, 
+    const char *port)
+{
+    int s;
+    struct protoent *proto;
+    struct sockaddr_in server;
+    int yes = 1;
+
+    if (tcp_setinaddr(&server, host, port, "tcp") < 0)
+        return -1;
+    if ((proto = getprotobyname("tcp")) == NULL)
+        return -1;
+    if ((s = socket(PF_INET, SOCK_STREAM, proto->p_proto)) < 0)
+        return -1;
+    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes));
+    if (bind(s, (struct sockaddr *)&server, sizeof(server)) < 0) {
+        close(s);
+        return -1;
+    }
+    if (listen(s, 256) < 0) {
+        close(s);
+        return -1;
+    }
+    return s;
+}
+
+static int 
+proc_daemon(
+    int nochdir, 
+    int noclose)
+{
+    int fd;
+    int rc;
+
+    /*
+     * Ignore tty related signals
+     */
+#ifdef SIGTTOU
+    signal(SIGTTOU, SIG_IGN);
+#endif
+#ifdef SIGTTIN
+    signal(SIGTTIN, SIG_IGN);
+#endif
+#ifdef SIGTSTP
+    signal(SIGTSTP, SIG_IGN);
+#endif
+
+    /*
+     * fork so the parent can exit, this returns control to the command line
+     * or shell invoking your program. This step is required so that the new
+     * process is guaranteed not to be a process group leader (The next step,
+     * setsid, would fail if you're a process group leader). 
+     */
+    rc = fork();
+    switch (rc) {
+        case -1: return -1;
+        case 0:  break;
+        default: _exit(0); /* exit original process */
+    }
+
+    /*
+     * setsid to become a process group and session group leader. Since a
+     * controlling terminal is associated with a session, and this new session
+     * has not yet acquired a controlling terminal our process now has no
+     * controlling terminal, which is a Good Thing for daemons. 
+     */
+#ifdef HAVE_SETSID
+    if (setsid() == -1)
+        return -1;
+#else
+    if (setpgid(0, getpid()) == -1)
+        return -1;
+#ifndef _PATH_TTY
+#define _PATH_TTY "/dev/tty"
+#endif
+    if ((fd = open(_PATH_TTY, O_RDWR)) == -1) 
+        return -1;
+    ioctl(fd, TIOCNOTTY, NULL);
+    close(fd);
+#endif
+
+    /*
+     * fork again so the parent, (the session group leader), can exit. This
+     * means that we, as a non-session group leader, can never regain a
+     * controlling terminal. 
+     */
+    rc = fork();
+    switch (rc) {
+        case -1: return -1;
+        case 0:  break;
+        default: _exit(0); /* exit original process */
+    }
+
+    /*
+     * chdir("/") to ensure that our process doesn't keep any directory in
+     * use. Failure to do this could make it so that an administrator couldn't
+     * unmount a filesystem, because it was our current directory.
+     * [Equivalently, we could change to any directory containing files
+     * important to the daemon's operation.] 
+     */
+    if (!nochdir)
+        chdir("/");
+
+    /*
+     * give us complete control over the permissions of anything we write. We
+     * don't know what umask we may have inherited.  [This step is optional] 
+     */
+    umask(0);
+
+    /*
+     * close fds 0, 1, and 2. This releases the standard in, out, and error we
+     * inherited from our parent process. We have no way of knowing where
+     * these fds might have been redirected to. 
+     */
+    if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
+        dup2(fd, STDIN_FILENO);
+        dup2(fd, STDOUT_FILENO);
+        dup2(fd, STDERR_FILENO);
+        if (fd > 2)
+            close(fd);
+    }
+    return 0;
+}
+
+static void 
+pserver_daemon_reapchild(
+    int signo)
+{
+    pid_t child;
+    int status;
+    char buf[128];
+
+    while ((child = waitpid(-1, &status, WNOHANG)) > (pid_t)0) {
+        if (pserverd_verbose) {
+            sprintf(buf, "cvs pserverd[%ld]: child process (pid %ld): terminated.\n", 
+                    (long)getpid(), (long)child);
+            write(STDOUT_FILENO, buf, strlen(buf));
+        }
+    }
+    signal(signo, &pserver_daemon_reapchild);
+    return;
+}
+
+int
+pserver_daemon(
+    int argc, 
+    char **argv)
+{
+    int sd;
+    pid_t child;
+    int option;
+    char *host = NULL;
+    char *port = "2401";
+    char *listen = NULL;
+    struct sockaddr_in them;
+    int detach = 0;
+    char *pidfile = NULL;
+    FILE *fp;
+    char *cp;
+    int len;
+    int ns;
+
+    /* make sure we are running with root priviledges, because
+       we need it later for chroot, switch_to_user, etc. */
+    if (geteuid() != 0)
+        error(1, 0, "root priviledges required for pserver operation");
+
+    /* process "cvs pserverd" command options */
+    optind = 0;
+    while ((option = getopt(argc, argv, "vl:dp:A:R:")) != EOF) {
+        switch ((char) option) {
+            case 'v':
+                pserverd_verbose = 1;
+                break;
+            case 'l':
+                listen = xstrdup(optarg);
+                break;
+            case 'd':
+                detach = 1;
+                pserverd_verbose = 0;
+                break;
+            case 'p':
+                pidfile = xstrdup(optarg);
+                break;
+            case 'A':
+                pserverd_anonymous_user = xstrdup(optarg);
+                break;
+            case 'R':
+                cp = xstrdup(optarg);
+                pserver_chroot.user = cp;
+                if ((cp = strchr(cp, ':')) == NULL)
+                    error(1, 0, "invalid -R option argument");
+                *cp++ = '\0';
+                pserver_chroot.repos = cp;
+                if ((cp = strchr(cp, ':')) == NULL)
+                    error(1, 0, "invalid -R option argument");
+                *cp++ = '\0';
+                pserver_chroot.chroot = cp;
+                break;
+            case '?':
+            default:
+                usage(pserverd_usage);
+                break;
+        }
+    }
+    argc -= optind;
+    argv += optind;
+    if (argc < 0)
+        usage(pserverd_usage);
+
+    /* optionally go into the background as a real daemon */
+    if (detach)
+        proc_daemon(0, 0);
+
+    /* optionally write out the pid */
+    if (pidfile != NULL) {
+        if ((fp = fopen(pidfile, "w")) == NULL)
+            error(1, 0, "unable to write pid to file %s: %s", 
+                  pidfile, strerror(errno));
+        fprintf(fp, "%ld\n", (long)getpid());
+        fclose(fp);
+    }
+
+    /* listen on the TCP/IP socket */
+    if (listen != NULL) {
+        if ((port = strrchr(listen, ':')) != NULL)
+            *(port++) = '\0';
+        if (strcasecmp(listen, "*") == 0 || strcmp(listen, "0.0.0.0") == 0) 
+            host = NULL;
+        else
+            host = listen;
+    }
+    if ((sd = tcp_listen(host, port)) < 0)
+        error(1, 0, "unable to listen (%s:%s): %s", 
+              host != NULL ? host : "*", port, strerror(errno));
+
+    /* make sure we reap the childs */
+    signal(SIGCHLD, &pserver_daemon_reapchild);
+
+    /* daemon loop */
+    for (;;) {
+        len = sizeof(them);
+        ns = accept(sd, (struct sockaddr *)&them, &len);
+        if (ns < 0) {
+            if (errno == EINTR)
+                continue;
+            error(1, 0, "accept(2) failed: %s", strerror(errno));
+        }
+        switch (child = fork()) {
+            case -1:
+                error(1, 0, "unable to fork(2): %s", strerror(errno));
+                break;
+            case 0:
+                /* child */
+                close(sd);
+                signal(SIGCHLD, SIG_DFL);
+
+                /* connect stdin/stdout to socket */
+                dup2(ns, STDIN_FILENO);
+                dup2(ns, STDOUT_FILENO);
+
+                /* 
+                 * perform "cvs pserver" authentication handshake.
+                 */
+                pserver_handshake();
+
+                /* 
+                 * just return to caller, i.e., the main() procedure
+                 * which in turn will dispatch into "cvs server" code
+                 * for us...
+                 */
+                return 0;
+                break;
+            default:
+                /* parent */
+                if (pserverd_verbose)
+                    fprintf(stderr, "cvs pserverd[%ld]: child process (pid %ld): started.\n", 
+                            (long)getpid(), (long)child);
+                close(ns);
+                break;
+        }
+    }
+    exit(0);
+    return 0;
+}
+
+static void
+pserver_handshake(
+    void)
+{
+    char *tmp = NULL;
+    size_t tmp_allocated = 0;
+    char *repository = NULL;
+    size_t repository_allocated = 0;
+    char *username = NULL;
+    size_t username_allocated = 0;
+    char *password = NULL;
+    size_t password_allocated = 0;
+    char *host_user = NULL;
+    char *descrambled_password;
+    int verify_and_exit = 0;
+    char *chrootdir = NULL;
+    int on;
+
+#ifdef SO_KEEPALIVE
+    /* Set SO_KEEPALIVE on the socket, so that we don't hang forever
+       if the client dies while we are waiting for input.  */
+    on = 1;
+    (void)setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE,
+                     (char *)&on, sizeof(on));
+#endif
+
+    /* Make sure the protocol starts off on the right foot... */
+    getline(&tmp, &tmp_allocated, stdin);
+
+    if (strcmp (tmp, "BEGIN VERIFICATION REQUEST\n") == 0)
+        verify_and_exit = 1;
+    else if (strcmp (tmp, "BEGIN AUTH REQUEST\n") == 0)
+        ;
+    else
+        error (1, 0, "bad auth protocol start: %s", tmp);
+
+    /* Get the three important pieces of information in order. */
+    getline(&repository, &repository_allocated, stdin);
+    getline(&username, &username_allocated, stdin);
+    getline(&password, &password_allocated, stdin);
+
+    /* Make them pure. */ 
+    strip_trailing_newlines(repository);
+    strip_trailing_newlines(username);
+    strip_trailing_newlines(password);
+
+#ifdef RSE_PATCH_MAPROOT
+    root_map_it(repository, &repository, 0);
+#endif
+
+    /* ... and make sure the protocol ends on the right foot. */
+    getline(&tmp, &tmp_allocated, stdin);
+    if (strcmp (tmp, verify_and_exit ?
+                "END VERIFICATION REQUEST\n" : "END AUTH REQUEST\n") != 0)
+        error (1, 0, "bad auth protocol end: %s", tmp);
+
+    if (!root_allow_ok(repository))
+        goto i_hate_you;
+    parse_config(repository);
+
+    /* We need the real cleartext before we hash it. */
+    descrambled_password = descramble(password);
+    host_user = check_password(username, descrambled_password, repository);
+    memset(descrambled_password, 0, strlen(descrambled_password));
+    free(descrambled_password);
+
+    if (host_user == NULL) {
+        i_hate_you:
+        printf("I HATE YOU\n");
+        fflush(stdout);
+        if (pserverd_verbose)
+            fprintf(stderr, "cvs pserverd[%ld]: status=FAILED user=%s root=%s\n",
+                    (long)getpid(), username, repository);
+        error_exit();
+    }
+
+    /* Don't go any farther if we're just responding to "cvs login". */
+    if (verify_and_exit) {
+        printf("I LOVE YOU\n");
+        fflush(stdout);
+        if (pserverd_verbose) 
+            fprintf(stderr, "cvs pserverd[%ld]: status=OK user=%s root=%s (huser=%s)\n",
+                    (long)getpid(), username, repository, host_user);
+        exit(0);
+    }
+
+    /* Set Pserver_Repos so that we can check later that the same
+       repository is sent in later client/server protocol. */
+    Pserver_Repos = xmalloc(strlen(repository)+1);
+    strcpy(Pserver_Repos, repository);
+
+    /* Optionally perform a chroot */
+    if (pserver_chroot.user != NULL) {
+        if (    strcmp(username, pserver_chroot.user) == 0 
+             && (   strcmp(repository, pserver_chroot.repos) == 0
+                 || strcmp(pserver_chroot.repos, "*") == 0        )) {
+            chrootdir = pserver_chroot.chroot;
+            if (chdir(chrootdir) == -1)
+                error(1, 0, "failed to chdir(2) to %s: %s", chrootdir, strerror(errno));
+            if (chroot(chrootdir) == -1)
+                error(1, 0, "failed to chroot(2) to %s: %s", chrootdir, strerror(errno));
+        }
+    }
+
+    /* Additionally switch to read-only mode for anonymous user */
+    if (pserverd_anonymous_user != NULL) {
+        if (strcmp(username, pserverd_anonymous_user) == 0) {
+#ifdef RSE_PATCH_NOLOCK
+            nolock = 1;
+#endif
+            logoff = 1;
+        }
+    }
+
+    /* Switch to run as this user. */
+    switch_to_user(host_user);
+    free(tmp);
+    free(repository);
+    free(username);
+    free(password);
+
+    printf("I LOVE YOU\n");
+    fflush(stdout);
+    if (pserverd_verbose) 
+        fprintf(stderr, "cvs pserverd[%ld]: status=OK user=%s root=%s (huser=%s hroot=%s)\n",
+                (long)getpid(), username, repository, host_user, chrootdir != NULL ? chrootdir : "/");
+    return;
+}
+
+#endif /* RSE_PATCH_PSERVERD */
+
Index: src/subr.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/subr.c,v
retrieving revision 1.1.1.6
diff -u -d -r1.1.1.6 subr.c
--- src/subr.c	19 Apr 2002 20:39:05 -0000	1.1.1.6
+++ src/subr.c	28 Dec 2002 10:48:17 -0000
@@ -336,6 +336,22 @@
     uid_t uid;
 #endif
 
+#ifdef RSE_PATCH_CVSUSER
+#ifndef RSE_PATCH_CVSUSER_CALLER
+#define RSE_PATCH_CVSUSER_CALLER "cvs"
+#endif
+    uid = getuid();
+    if ((pw = (struct passwd *)getpwnam(RSE_PATCH_CVSUSER_CALLER)) != NULL) {
+        if (pw->pw_uid == uid) {
+	    char *name;
+            if ((name = getenv("CVSUSER")) != NULL) {
+                cache = xstrdup(name);
+                return cache;
+            }
+        }
+    }
+#endif
+
     /* If there is a CVS username, return it.  */
 #ifdef AUTH_SERVER_SUPPORT
     if (CVS_Username != NULL)
@@ -763,6 +779,73 @@
 
     return backup_name;
 }
+
+#ifdef RSE_PATCH_HANDLE
+/* handle: 2000041317203601
+   date1:  2000/04/13 17:20:36 
+   date2:  2000/04/13 17:20:37 */
+int handle2dates(char *handle, time_t *t1, time_t *t2)
+{
+    int Y,M,D,h,m,s,o;
+    char buf[17];
+    time_t t;
+    struct tm tm;
+    int rev = 0;
+    int i;
+
+    /* check for correct handle format */
+    if (handle == NULL)
+        return 0;
+    if (handle[0] == '!') {
+        handle++;
+        rev = 1;
+    }
+    if (strlen(handle) != 16) 
+        return 0;
+    for (i = 0; i < 16; i++)
+        if (!isdigit(handle[i]))
+            return 0;
+
+    /* parse out handle parts */
+    strcpy(buf, handle);
+    o = atoi(buf+14);
+    buf[14] = '\0';
+    s = atoi(buf+12);
+    buf[12] = '\0';
+    m = atoi(buf+10);
+    buf[10] = '\0';
+    h = atoi(buf+8);
+    buf[8] = '\0';
+    D = atoi(buf+6);
+    buf[6] = '\0';
+    M = atoi(buf+4);
+    buf[4] = '\0';
+    Y = atoi(buf);
+
+    /* assemble parts into a time value */
+    memset(&tm, 0, sizeof tm);
+    tm.tm_sec    = s;
+    tm.tm_min    = m;
+    tm.tm_hour   = h;
+    tm.tm_mday   = D;
+    tm.tm_mon    = M - 1;
+    tm.tm_year   = Y - 1900;
+    t = mktime(&tm);
+    if (t == -1)
+        return 0;
+
+    /* output the first and second time */
+    if (rev) {
+        *t2 = t;
+        *t1 = t + o;
+    }
+    else {
+        *t1 = t;
+        *t2 = t + o;
+    }
+    return 1;
+}
+#endif
 
 /*
  * Copy a string into a buffer escaping any shell metacharacters.  The
Index: src/tag.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/tag.c,v
retrieving revision 1.1.1.7
diff -u -d -r1.1.1.7 tag.c
--- src/tag.c	28 Dec 2002 18:01:30 -0000	1.1.1.7
+++ src/tag.c	28 Dec 2002 20:14:07 -0000
@@ -1300,7 +1300,11 @@
 	/* The tags is valid but not mentioned in val-tags.  Add it.  */
 	datum value;
 
+#ifdef RSE_PATCH_NOLOCK
+	if (noexec || nowrite || nolock)
+#else
 	if (noexec || nowrite)
+#endif
 	{
 	    if (db != NULL)
 		dbm_close (db);
Index: src/update.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/update.c,v
retrieving revision 1.1.1.7
diff -u -d -r1.1.1.7 update.c
--- src/update.c	28 Dec 2002 18:01:30 -0000	1.1.1.7
+++ src/update.c	28 Dec 2002 20:14:07 -0000
@@ -203,7 +203,11 @@
 		break;
 	    case 'p':
 		pipeout = 1;
+#ifdef RSE_PATCH_NOLOCK
+		nolock = noexec = 1;		/* so no locks will be created */
+#else
 		noexec = 1;		/* so no locks will be created */
+#endif
 		break;
 	    case 'j':
 		if (join_rev2)
@@ -1815,6 +1819,17 @@
 	       patch can't handle that.  */
 	    fail = 1;
 	}
+#ifdef RSE_PATCH_FASTERUPDATE
+        else {
+            /*
+             * Don't send a diff if just sending the entire file
+             * would be smaller...
+             */
+            fseek(e, 0L, SEEK_END);
+            if (file_info->st_size < ftell(e))
+                fail = 1;
+        }
+#endif
 	fclose (e);
     }
 
@@ -2581,8 +2596,16 @@
 	write_letter (finfo, 'C');
     }
     else
+#ifdef RSE_PATCH_MERGENOKEYWORD
+    {
+        if (*t_options == '\0')
+            t_options = "-kk"; /* to ignore keyword expansions */
+#endif
 	status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
 			    t_options, rev1, rev2);
+#ifdef RSE_PATCH_MERGENOKEYWORD
+    }
+#endif
 
     if (status != 0 && status != 1)
     {
Index: src/version.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/version.c,v
retrieving revision 1.1.1.7
diff -u -d -r1.1.1.7 version.c
--- src/version.c	29 Apr 2002 04:25:58 -0000	1.1.1.7
+++ src/version.c	28 Dec 2002 11:09:23 -0000
@@ -62,6 +62,9 @@
        some idea of how long ago their version of CVS was
        released.  */
     (void) fputs (PACKAGE_STRING, stdout);
+#ifdef RSE_PATCHES
+    (void) fputs (" [RSE]", stdout);
+#endif
     (void) fputs (config_string, stdout);
 
 #ifdef CLIENT_SUPPORT
