summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin/rcs/lib
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1995-10-28 21:07:39 +0000
committerpeter <peter@FreeBSD.org>1995-10-28 21:07:39 +0000
commitf88f3a686799dfede79eb3c8d8cfec9b1e7ae343 (patch)
treef3e1577c5b11357c106fe7ee15105d608cb96192 /gnu/usr.bin/rcs/lib
parent27378b5694b4941bb63a62097f7ee523da0a35bb (diff)
downloadFreeBSD-src-f88f3a686799dfede79eb3c8d8cfec9b1e7ae343.zip
FreeBSD-src-f88f3a686799dfede79eb3c8d8cfec9b1e7ae343.tar.gz
Import rcs-5.7, required for full support of cvs-1.6.
This is going to be pretty messy.... Although the vendor import was correct, both the vendor and release tags are the same "gnu"... :-/ Getting cvs to choose the correct one might be rather interesting...
Diffstat (limited to 'gnu/usr.bin/rcs/lib')
-rw-r--r--gnu/usr.bin/rcs/lib/Makefile15
-rw-r--r--gnu/usr.bin/rcs/lib/conf.h386
-rw-r--r--gnu/usr.bin/rcs/lib/maketime.c604
-rw-r--r--gnu/usr.bin/rcs/lib/maketime.h39
-rw-r--r--gnu/usr.bin/rcs/lib/merger.c77
-rw-r--r--gnu/usr.bin/rcs/lib/partime.c1250
-rw-r--r--gnu/usr.bin/rcs/lib/partime.h71
-rw-r--r--gnu/usr.bin/rcs/lib/rcsbase.h332
-rw-r--r--gnu/usr.bin/rcs/lib/rcsedit.c989
-rw-r--r--gnu/usr.bin/rcs/lib/rcsfcmp.c114
-rw-r--r--gnu/usr.bin/rcs/lib/rcsfnms.c611
-rw-r--r--gnu/usr.bin/rcs/lib/rcsgen.c320
-rw-r--r--gnu/usr.bin/rcs/lib/rcskeep.c186
-rw-r--r--gnu/usr.bin/rcs/lib/rcskeys.c30
-rw-r--r--gnu/usr.bin/rcs/lib/rcslex.c820
-rw-r--r--gnu/usr.bin/rcs/lib/rcsmap.c9
-rw-r--r--gnu/usr.bin/rcs/lib/rcsrev.c478
-rw-r--r--gnu/usr.bin/rcs/lib/rcssyn.c407
-rw-r--r--gnu/usr.bin/rcs/lib/rcstime.c191
-rw-r--r--gnu/usr.bin/rcs/lib/rcsutil.c832
-rw-r--r--gnu/usr.bin/rcs/lib/version.c2
21 files changed, 4707 insertions, 3056 deletions
diff --git a/gnu/usr.bin/rcs/lib/Makefile b/gnu/usr.bin/rcs/lib/Makefile
index b198e9e..0170d4a 100644
--- a/gnu/usr.bin/rcs/lib/Makefile
+++ b/gnu/usr.bin/rcs/lib/Makefile
@@ -1,5 +1,14 @@
-LIB= rcs
-SRCS= maketime.c partime.c rcsedit.c rcsfcmp.c rcsfnms.c rcsgen.c rcskeep.c \
- rcskeys.c rcslex.c rcsmap.c rcsrev.c rcssyn.c rcsutil.c merger.c
+# Define FSYNC_ALL to get slower but safer writes in case of crashes in
+# the middle of CVS/RCS changes
+#CFLAGS += -DFSYNC_ALL
+
+LIB = rcs
+SRCS = maketime.c partime.c rcsedit.c rcsfcmp.c rcsfnms.c rcsgen.c \
+ rcskeep.c rcskeys.c rcslex.c rcsmap.c rcsrev.c rcssyn.c rcstime.c \
+ rcsutil.c merger.c version.c
+
+NOPROFILE=noprofile
+
+install:
.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/rcs/lib/conf.h b/gnu/usr.bin/rcs/lib/conf.h
index d29e511..ceae147 100644
--- a/gnu/usr.bin/rcs/lib/conf.h
+++ b/gnu/usr.bin/rcs/lib/conf.h
@@ -1,6 +1,6 @@
/* RCS compile-time configuration */
- /* $Id: conf.sh,v 5.14 1991/11/20 18:21:10 eggert Exp $ */
+ /* $Id: conf.sh,v 5.25 1995/06/16 06:19:24 eggert Exp $ */
/*
* This file is generated automatically.
@@ -10,7 +10,8 @@
*/
#define exitmain(n) return n /* how to exit from main() */
-/* #define _POSIX_SOURCE */ /* Define this if Posix + strict Standard C. */
+/* #define _POSIX_C_SOURCE 2147483647L */ /* if strict C + Posix 1003.1b-1993 or later */
+/* #define _POSIX_SOURCE */ /* if strict C + Posix 1003.1-1990 */
#include <errno.h>
#include <stdio.h>
@@ -22,48 +23,28 @@
#include <dirent.h>
#include <fcntl.h>
#include <limits.h>
+/* #include <mach/mach.h> */
+/* #include <net/errno.h> */
#include <pwd.h>
+/* #include <siginfo.h> */
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/wait.h>
+/* #include <ucontext.h> */
#include <unistd.h>
#include <utime.h>
/* #include <vfork.h> */
-/* Define the following symbols to be 1 or 0. */
-#define has_sys_dir_h 1 /* Does #include <sys/dir.h> work? */
+/* Define boolean symbols to be 0 (false, the default), or 1 (true). */
#define has_sys_param_h 1 /* Does #include <sys/param.h> work? */
+/* extern int errno; */ /* Uncomment if <errno.h> doesn't declare errno. */
#define has_readlink 1 /* Does readlink() work? */
+#define readlink_isreg_errno EINVAL /* errno after readlink on regular file */
-/* #undef NAME_MAX */ /* Uncomment this if NAME_MAX is broken. */
-
-#if !defined(NAME_MAX) && !defined(_POSIX_NAME_MAX)
-# if has_sys_dir_h
-# include <sys/dir.h>
-# endif
-# ifndef NAME_MAX
-# ifndef MAXNAMLEN
-# define MAXNAMLEN 14
-# endif
-# define NAME_MAX MAXNAMLEN
-# endif
-#endif
-#if !defined(PATH_MAX) && !defined(_POSIX_PATH_MAX)
-# if has_sys_param_h
-# include <sys/param.h>
-# define included_sys_param_h 1
-# endif
-# ifndef PATH_MAX
-# ifndef MAXPATHLEN
-# define MAXPATHLEN 1024
-# endif
-# define PATH_MAX (MAXPATHLEN-1)
-# endif
-#endif
#if has_readlink && !defined(MAXSYMLINKS)
-# if has_sys_param_h && !included_sys_param_h
+# if has_sys_param_h
# include <sys/param.h>
# endif
# ifndef MAXSYMLINKS
@@ -71,25 +52,55 @@
# endif
#endif
-/* Comment out the keyword definitions below if the keywords work. */
-/* #define const */
-/* #define volatile */
-
/* Comment out the typedefs below if the types are already declared. */
/* Fix any uncommented typedefs that are wrong. */
/* typedef int mode_t; */
+/* typedef long off_t; */
/* typedef int pid_t; */
-typedef int sig_atomic_t;
+/* typedef int sig_atomic_t; */
/* typedef unsigned size_t; */
/* typedef int ssize_t; */
/* typedef long time_t; */
/* typedef int uid_t; */
-/* Define the following symbols to be 1 or 0. */
+/* Comment out the keyword definitions below if the keywords work. */
+/* #define const */
+/* #define volatile */
+
+/* Define boolean symbols to be 0 (false, the default), or 1 (true). */
#define has_prototypes 1 /* Do function prototypes work? */
#define has_stdarg 1 /* Does <stdarg.h> work? */
-#define has_varargs 0 /* Does <varargs.h> work? */
+/* #define has_varargs ? */ /* Does <varargs.h> work? */
#define va_start_args 2 /* How many args does va_start() take? */
+
+#if O_BINARY
+ /* Text and binary i/o behave differently. */
+ /* This is incompatible with Posix and Unix. */
+# define FOPEN_RB "rb"
+# define FOPEN_R_WORK (Expand==BINARY_EXPAND ? "r" : "rb")
+# define FOPEN_WB "wb"
+# define FOPEN_W_WORK (Expand==BINARY_EXPAND ? "w" : "wb")
+# define FOPEN_WPLUS_WORK (Expand==BINARY_EXPAND ? "w+" : "w+b")
+# define OPEN_O_BINARY O_BINARY
+#else
+ /*
+ * Text and binary i/o behave the same.
+ * Omit "b", since some nonstandard hosts reject it.
+ */
+# define FOPEN_RB "r"
+# define FOPEN_R_WORK "r"
+# define FOPEN_WB "w"
+# define FOPEN_W_WORK "w"
+# define FOPEN_WPLUS_WORK "w+"
+# define OPEN_O_BINARY 0
+#endif
+
+/* This may need changing on non-Unix systems (notably DOS). */
+#define OPEN_CREAT_READONLY (S_IRUSR|S_IRGRP|S_IROTH) /* lock file mode */
+#define OPEN_O_LOCK 0 /* extra open flags for creating lock file */
+#define OPEN_O_WRONLY O_WRONLY /* main open flag for creating a lock file */
+
+/* Define or comment out the following symbols as needed. */
#if has_prototypes
# define P(params) params
#else
@@ -113,105 +124,114 @@ typedef int sig_atomic_t;
#else
# define vararg_start(ap,p) va_start(ap)
#endif
-
-#define text_equals_binary_stdio 1 /* Does stdio treat text like binary? */
-#define text_work_stdio 0 /* Text i/o for working file, binary for RCS file? */
-#if text_equals_binary_stdio
- /* Text and binary i/o behave the same, or binary i/o does not work. */
-# define FOPEN_R "r"
-# define FOPEN_W "w"
-# define FOPEN_WPLUS "w+"
-#else
- /* Text and binary i/o behave differently. */
- /* This is incompatible with Posix and Unix. */
-# define FOPEN_R "rb"
-# define FOPEN_W "wb"
-# define FOPEN_WPLUS "w+b"
-#endif
-#if text_work_stdio
-# define FOPEN_R_WORK "r"
-# define FOPEN_W_WORK "w"
-# define FOPEN_WPLUS_WORK "w+"
+#define bad_chmod_close 0 /* Can chmod() close file descriptors? */
+#define bad_creat0 0 /* Do writes fail after creat(f,0)? */
+#define bad_fopen_wplus 0 /* Does fopen(f,"w+") fail to truncate f? */
+#define getlogin_is_secure 0 /* Is getlogin() secure? Usually it's not. */
+#define has_attribute_noreturn 1 /* Does __attribute__((noreturn)) work? */
+#if has_attribute_noreturn
+# define exiting __attribute__((noreturn))
#else
-# define FOPEN_R_WORK FOPEN_R
-# define FOPEN_W_WORK FOPEN_W
-# define FOPEN_WPLUS_WORK FOPEN_WPLUS
+# define exiting
#endif
-
-/* Define or comment out the following symbols as needed. */
-#define bad_fopen_wplus 0 /* Does fopen(f,FOPEN_WPLUS) fail to truncate f? */
-#define getlogin_is_secure 0 /* Is getlogin() secure? Usually it's not. */
#define has_dirent 1 /* Do opendir(), readdir(), closedir() work? */
-#define has_fchmod 0 /* Does fchmod() work? */
-#define has_fputs 0 /* Does fputs() work? */
+#define void_closedir 0 /* Does closedir() yield void? */
+#define has_fchmod 1 /* Does fchmod() work? */
+#define has_fflush_input 0 /* Does fflush() work on input files? */
+#define has_fputs 1 /* Does fputs() work? */
#define has_ftruncate 1 /* Does ftruncate() work? */
#define has_getuid 1 /* Does getuid() work? */
#define has_getpwuid 1 /* Does getpwuid() work? */
-#define has_link 1 /* Does link() work? */
#define has_memcmp 1 /* Does memcmp() work? */
#define has_memcpy 1 /* Does memcpy() work? */
#define has_memmove 1 /* Does memmove() work? */
+#define has_map_fd 0 /* Does map_fd() work? */
+#define has_mmap 1 /* Does mmap() work on regular files? */
#define has_madvise 0 /* Does madvise() work? */
-#define has_mmap 0 /* Does mmap() work on regular files? */
+#define mmap_signal SIGBUS /* signal received if you reference nonexistent part of mmapped file */
#define has_rename 1 /* Does rename() work? */
#define bad_a_rename 0 /* Does rename(A,B) fail if A is unwritable? */
#define bad_b_rename 0 /* Does rename(A,B) fail if B is unwritable? */
+#define bad_NFS_rename 0 /* Can rename(A,B) falsely report success? */
+/* typedef int void; */ /* Some ancient compilers need this. */
#define VOID (void) /* 'VOID e;' discards the value of an expression 'e'. */
-#define has_seteuid 0 /* Does seteuid() work? See README. */
+#define has_seteuid 1 /* Does seteuid() work? See ../INSTALL.RCS. */
+#define has_setreuid 0 /* Does setreuid() work? See ../INSTALL.RCS. */
#define has_setuid 1 /* Does setuid() exist? */
+#define has_sigaction 1 /* Does struct sigaction work? */
+#define has_sa_sigaction 0 /* Does struct sigaction have sa_sigaction? */
#define has_signal 1 /* Does signal() work? */
-#define signal_args P((int)) /* arguments of signal handlers */
#define signal_type void /* type returned by signal handlers */
#define sig_zaps_handler 0 /* Must a signal handler reinvoke signal()? */
-#define has_sigaction 1 /* Does struct sigaction work? */
/* #define has_sigblock ? */ /* Does sigblock() work? */
/* #define sigmask(s) (1 << ((s)-1)) */ /* Yield mask for signal number. */
-#define has_sys_siglist 0 /* Does sys_siglist[] work? */
-typedef ssize_t fread_type; /* type returned by fread() and fwrite() */
+typedef size_t fread_type; /* type returned by fread() and fwrite() */
typedef size_t freadarg_type; /* type of their size arguments */
typedef void *malloc_type; /* type returned by malloc() */
#define has_getcwd 1 /* Does getcwd() work? */
/* #define has_getwd ? */ /* Does getwd() work? */
+#define needs_getabsname 0 /* Must we define getabsname? */
#define has_mktemp 1 /* Does mktemp() work? */
#define has_NFS 1 /* Might NFS be used? */
+#define has_psiginfo 0 /* Does psiginfo() work? */
+#define has_psignal 1 /* Does psignal() work? */
+/* #define has_si_errno ? */ /* Does siginfo_t have si_errno? */
+/* #define has_sys_siglist ? */ /* Does sys_siglist[] work? */
/* #define strchr index */ /* Use old-fashioned name for strchr()? */
/* #define strrchr rindex */ /* Use old-fashioned name for strrchr()? */
#define bad_unlink 0 /* Does unlink() fail on unwritable files? */
-#define has_vfork 0 /* Does vfork() work? */
+#define has_vfork 1 /* Does vfork() work? */
#define has_fork 1 /* Does fork() work? */
#define has_spawn 0 /* Does spawn*() work? */
-#define has_wait 1 /* Does wait() work? */
-#define has_waitpid 0 /* Does waitpid() work? */
+#define has_waitpid 1 /* Does waitpid() work? */
+#define bad_wait_if_SIGCHLD_ignored 0 /* Does ignoring SIGCHLD break wait()? */
#define RCS_SHELL "/bin/sh" /* shell to run RCS subprograms */
+#define has_printf_dot 1 /* Does "%.2d" print leading 0? */
#define has_vfprintf 1 /* Does vfprintf() work? */
+#define has_attribute_format_printf 1 /* Does __attribute__((format(printf,N,N+1))) work? */
+#if has_attribute_format_printf
+# define printf_string(m, n) __attribute__((format(printf, m, n)))
+#else
+# define printf_string(m, n)
+#endif
+#if has_attribute_format_printf && has_attribute_noreturn
+ /* Work around a bug in GCC 2.5.x. */
+# define printf_string_exiting(m, n) __attribute__((format(printf, m, n), noreturn))
+#else
+# define printf_string_exiting(m, n) printf_string(m, n) exiting
+#endif
/* #define has__doprintf ? */ /* Does _doprintf() work? */
/* #define has__doprnt ? */ /* Does _doprnt() work? */
/* #undef EXIT_FAILURE */ /* Uncomment this if EXIT_FAILURE is broken. */
-#define large_memory 0 /* Can main memory hold entire RCS files? */
-/* #undef ULONG_MAX */ /* Uncomment this if ULONG_MAX is broken (e.g. < 0). */
-/* struct utimbuf { time_t actime, modtime; }; */ /* Uncomment this if needed. */
-#define CO "/usr/bin/co" /* name of 'co' program */
+#define large_memory 1 /* Can main memory hold entire RCS files? */
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647L /* long maximum */
+#endif
+/* Do struct stat s and t describe the same file? Answer d if unknown. */
+#define same_file(s,t,d) ((s).st_ino==(t).st_ino && (s).st_dev==(t).st_dev)
+#define has_utimbuf 1 /* Does struct utimbuf work? */
+#define CO "/usr/local/bin/co" /* name of 'co' program */
#define COMPAT2 0 /* Are version 2 files supported? */
-#define DATEFORM "%.2d.%.2d.%.2d.%.2d.%.2d.%.2d" /* e.g. 01.01.01.01.01.01 */
#define DIFF "/usr/bin/diff" /* name of 'diff' program */
#define DIFF3 "/usr/bin/diff3" /* name of 'diff3' program */
#define DIFF3_BIN 1 /* Is diff3 user-visible (not the /usr/lib auxiliary)? */
-#define DIFF_FLAGS , "-an" /* Make diff output suitable for RCS. */
-#define DIFF_L 1 /* Does diff -L work? */
+#define DIFFFLAGS "-an" /* Make diff output suitable for RCS. */
+#define DIFF_L 1 /* Does diff -L work? */
#define DIFF_SUCCESS 0 /* DIFF status if no differences are found */
#define DIFF_FAILURE 1 /* DIFF status if differences are found */
#define DIFF_TROUBLE 2 /* DIFF status if trouble */
#define ED "/bin/ed" /* name of 'ed' program (used only if !DIFF3_BIN) */
-#define MERGE "/usr/bin/merge" /* name of 'merge' program */
+#define MERGE "/usr/local/bin/merge" /* name of 'merge' program */
#define TMPDIR "/tmp" /* default directory for temporary files */
-#define SLASH '/' /* principal pathname separator */
-#define SLASHes '/' /* `case SLASHes:' labels all pathname separators */
-#define isSLASH(c) ((c) == SLASH) /* Is arg a pathname separator? */
+#define SLASH '/' /* principal filename separator */
+#define SLASHes '/' /* `case SLASHes:' labels all filename separators */
+#define isSLASH(c) ((c) == SLASH) /* Is arg a filename separator? */
#define ROOTPATH(p) isSLASH((p)[0]) /* Is p an absolute pathname? */
#define X_DEFAULT ",v/" /* default value for -x option */
+#define SLASHSLASH_is_SLASH 1 /* Are // and / the same directory? */
+#define ALL_ABSOLUTE 1 /* Do all subprograms satisfy ROOTPATH? */
#define DIFF_ABSOLUTE 1 /* Is ROOTPATH(DIFF) true? */
-#define ALL_ABSOLUTE 1 /* Are all subprograms absolute pathnames? */
-#define SENDMAIL "/usr/bin/mail" /* how to send mail */
+#define SENDMAIL "/usr/sbin/sendmail" /* how to send mail */
#define TZ_must_be_set 0 /* Must TZ be set for gmtime() to work? */
@@ -219,40 +239,21 @@ typedef void *malloc_type; /* type returned by malloc() */
/* Adjust the following declarations as needed. */
-#if __GNUC__ && !__STRICT_ANSI__
-# define exiting volatile /* GCC extension: function cannot return */
-#else
-# define exiting
-#endif
+/* The rest is for the benefit of non-standard, traditional hosts. */
+/* Don't bother to declare functions that in traditional hosts do not appear, */
+/* or are declared in .h files, or return int or void. */
-#if has_ftruncate
- int ftruncate P((int,off_t));
-#endif
-/* <sys/mman.h> */
-#if has_madvise
- int madvise P((caddr_t,size_t,int));
-#endif
-#if has_mmap
- caddr_t mmap P((caddr_t,size_t,int,int,int,off_t));
- int munmap P((caddr_t,size_t));
+/* traditional BSD */
+
+#if has_sys_siglist && !defined(sys_siglist)
+ extern char const * const sys_siglist[];
#endif
/* Posix (ISO/IEC 9945-1: 1990 / IEEE Std 1003.1-1990) */
-/* These definitions are for the benefit of non-Posix hosts, and */
-/* Posix hosts that have Standard C compilers but traditional include files. */
-/* Unfortunately, mixed-up hosts are all too common. */
/* <fcntl.h> */
-#ifdef F_DUPFD
- int fcntl P((int,int,...));
-#else
- int dup2 P((int,int));
-#endif
-#ifndef O_BINARY /* some non-Posix hosts need O_BINARY */
-# define O_BINARY 0 /* no effect on Posix */
-#endif
#ifdef O_CREAT
# define open_can_creat 1
#else
@@ -262,43 +263,12 @@ typedef void *malloc_type; /* type returned by malloc() */
# define O_RDWR 2
# define O_CREAT 01000
# define O_TRUNC 02000
- int creat P((char const*,mode_t));
#endif
#ifndef O_EXCL
-# define O_EXCL 0
-#endif
-
-/* <pwd.h> */
-#if has_getpwuid
- struct passwd *getpwuid P((uid_t));
+#define O_EXCL 0
#endif
-/* <signal.h> */
-#if has_sigaction
- int sigaction P((int,struct sigaction const*,struct sigaction*));
- int sigaddset P((sigset_t*,int));
- int sigemptyset P((sigset_t*));
-#else
-#if has_sigblock
- /* BSD */
- int sigblock P((int));
- int sigmask P((int));
- int sigsetmask P((int));
-#endif
-#endif
-
-/* <stdio.h> */
-FILE *fdopen P((int,char const*));
-int fileno P((FILE*));
-
/* <sys/stat.h> */
-int chmod P((char const*,mode_t));
-int fstat P((int,struct stat*));
-int stat P((char const*,struct stat*));
-mode_t umask P((mode_t));
-#if has_fchmod
- int fchmod P((int,mode_t));
-#endif
#ifndef S_IRUSR
# ifdef S_IREAD
# define S_IRUSR S_IREAD
@@ -326,166 +296,100 @@ mode_t umask P((mode_t));
# endif
#endif
#ifndef S_ISREG
-# define S_ISREG(n) (((n) & S_IFMT) == S_IFREG)
+#define S_ISREG(n) (((n) & S_IFMT) == S_IFREG)
#endif
/* <sys/wait.h> */
-#if has_wait
- pid_t wait P((int*));
-#endif
#ifndef WEXITSTATUS
-# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
-# undef WIFEXITED /* Avoid 4.3BSD incompatibility with Posix. */
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#undef WIFEXITED /* Avoid 4.3BSD incompatibility with Posix. */
#endif
#ifndef WIFEXITED
-# define WIFEXITED(stat_val) (!((stat_val) & 255))
+#define WIFEXITED(stat_val) (((stat_val) & 0377) == 0)
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(stat_val) ((stat_val) & 0177)
+#undef WIFSIGNALED /* Avoid 4.3BSD incompatibility with Posix. */
+#endif
+#ifndef WIFSIGNALED
+#define WIFSIGNALED(stat_val) ((unsigned)(stat_val) - 1 < 0377)
#endif
/* <unistd.h> */
char *getlogin P((void));
-int close P((int));
-int isatty P((int));
-int link P((char const*,char const*));
-int open P((char const*,int,...));
-int unlink P((char const*));
-int _filbuf P((FILE*)); /* keeps lint quiet in traditional C */
-int _flsbuf P((int,FILE*)); /* keeps lint quiet in traditional C */
-long pathconf P((char const*,int));
-ssize_t write P((int,void const*,size_t));
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
# define STDOUT_FILENO 1
# define STDERR_FILENO 2
#endif
-#if has_fork
-# if !has_vfork
-# undef vfork
-# define vfork fork
-# endif
- pid_t vfork P((void)); /* vfork is nonstandard but faster */
+#if has_fork && !has_vfork
+# undef vfork
+# define vfork fork
#endif
#if has_getcwd || !has_getwd
char *getcwd P((char*,size_t));
#else
char *getwd P((char*));
#endif
-#if has_getuid
- uid_t getuid P((void));
-#endif
-#if has_readlink
-/* ssize_t readlink P((char const*,char*,size_t)); *//* BSD; not standard yet */
-#endif
-#if has_setuid
-# if !has_seteuid
-# undef seteuid
-# define seteuid setuid
-# endif
- int seteuid P((uid_t));
- uid_t geteuid P((void));
+#if has_setuid && !has_seteuid
+# undef seteuid
+# define seteuid setuid
#endif
#if has_spawn
- int spawnv P((int,char const*,char*const*));
# if ALL_ABSOLUTE
# define spawn_RCS spawnv
# else
# define spawn_RCS spawnvp
- int spawnvp P((int,char const*,char*const*));
# endif
#else
- int execv P((char const*,char*const*));
# if ALL_ABSOLUTE
# define exec_RCS execv
# else
# define exec_RCS execvp
- int execvp P((char const*,char*const*));
# endif
#endif
/* utime.h */
-int utime P((char const*,struct utimbuf const*));
+#if !has_utimbuf
+ struct utimbuf { time_t actime, modtime; };
+#endif
/* Standard C library */
-/* These definitions are for the benefit of hosts that have */
-/* traditional C include files, possibly with Standard C compilers. */
-/* Unfortunately, mixed-up hosts are all too common. */
-
-/* <errno.h> */
-extern int errno;
-
-/* <limits.h> */
-#ifndef ULONG_MAX
- /* This does not work in #ifs, but it's good enough for us. */
-# define ULONG_MAX ((unsigned long)-1)
-#endif
-
-/* <signal.h> */
-#if has_signal
- signal_type (*signal P((int,signal_type(*)signal_args)))signal_args;
-#endif
/* <stdio.h> */
-FILE *fopen P((char const*,char const*));
-fread_type fread P((void*,freadarg_type,freadarg_type,FILE*));
-fread_type fwrite P((void const*,freadarg_type,freadarg_type,FILE*));
-int fclose P((FILE*));
-int feof P((FILE*));
-int ferror P((FILE*));
-int fflush P((FILE*));
-int fprintf P((FILE*,char const*,...));
-int fputs P((char const*,FILE*));
-int fseek P((FILE*,long,int));
-int printf P((char const*,...));
-int rename P((char const*,char const*));
-int sprintf P((char*,char const*,...));
-/* long ftell P((FILE*)); */
-void clearerr P((FILE*));
-void perror P((char const*));
#ifndef L_tmpnam
-# define L_tmpnam 32 /* power of 2 > sizeof("/usr/tmp/xxxxxxxxxxxxxxx") */
+#define L_tmpnam 32 /* power of 2 > sizeof("/usr/tmp/xxxxxxxxxxxxxxx") */
#endif
#ifndef SEEK_SET
-# define SEEK_SET 0
+#define SEEK_SET 0
+#endif
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
#endif
#if has_mktemp
char *mktemp P((char*)); /* traditional */
#else
char *tmpnam P((char*));
#endif
-#if has_vfprintf
- int vfprintf P((FILE*,char const*,va_list));
-#else
-#if has__doprintf
- void _doprintf P((FILE*,char const*,va_list)); /* Minix */
-#else
- void _doprnt P((char const*,va_list,FILE*)); /* BSD */
-#endif
-#endif
/* <stdlib.h> */
char *getenv P((char const*));
-exiting void _exit P((int));
-exiting void exit P((int));
+void _exit P((int)) exiting;
+void exit P((int)) exiting;
malloc_type malloc P((size_t));
malloc_type realloc P((malloc_type,size_t));
-void free P((malloc_type));
#ifndef EXIT_FAILURE
-# define EXIT_FAILURE 1
+#define EXIT_FAILURE 1
#endif
#ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
-#endif
-#if !has_fork && !has_spawn
- int system P((char const*));
+#define EXIT_SUCCESS 0
#endif
/* <string.h> */
char *strcpy P((char*,char const*));
char *strchr P((char const*,int));
char *strrchr P((char const*,int));
-int memcmp P((void const*,void const*,size_t));
-int strcmp P((char const*,char const*));
-size_t strlen P((char const*));
void *memcpy P((void*,void const*,size_t));
#if has_memmove
void *memmove P((void*,void const*,size_t));
diff --git a/gnu/usr.bin/rcs/lib/maketime.c b/gnu/usr.bin/rcs/lib/maketime.c
index c95c9f0..bf14bb9 100644
--- a/gnu/usr.bin/rcs/lib/maketime.c
+++ b/gnu/usr.bin/rcs/lib/maketime.c
@@ -1,344 +1,344 @@
-#
-/*
- * MAKETIME derive 32-bit time value from TM structure.
- *
- * Usage:
- * int zone; Minutes west of GMT, or
- * 48*60 for localtime
- * time_t t;
- * struct tm *tp; Pointer to TM structure from <time.h>
- * t = maketime(tp,zone);
- *
- * Returns:
- * -1 if failure; parameter out of range or nonsensical.
- * else time-value.
- * Notes:
- * This code is quasi-public; it may be used freely in like software.
- * It is not to be sold, nor used in licensed software without
- * permission of the author.
- * For everyone's benefit, please report bugs and improvements!
- * Copyright 1981 by Ken Harrenstien, SRI International.
- * (ARPANET: KLH @ SRI)
- */
-/* $Log: maketime.c,v $
- * Revision 5.3 1991/08/19 03:13:55 eggert
- * Add setfiledate, str2time, TZ_must_be_set.
- *
- * Revision 5.2 1990/11/01 05:03:30 eggert
- * Remove lint.
- *
- * Revision 5.1 1990/10/04 06:30:13 eggert
- * Calculate the GMT offset of 'xxx LT' as of xxx, not as of now.
- * Don't assume time_t is 32 bits. Fix bugs near epoch and near end of time.
- *
- * Revision 5.0 1990/08/22 08:12:38 eggert
- * Switch to GMT and fix the bugs exposed thereby.
- * Permit dates past 1999/12/31. Ansify and Posixate.
- *
- * Revision 1.8 88/11/08 13:54:53 narten
- * allow negative timezones (-24h <= x <= 24h)
- *
- * Revision 1.7 88/08/28 14:47:52 eggert
- * Allow cc -R. Remove unportable "#endif XXX"s.
- *
- * Revision 1.6 87/12/18 17:05:58 narten
- * include rcsparam.h
- *
- * Revision 1.5 87/12/18 11:35:51 narten
- * maketime.c: fixed USG code - you have tgo call "tzset" in order to have
- * "timezone" set. ("localtime" calls it, but it's probably better not to
- * count on "localtime" having been called.)
- *
- * Revision 1.4 87/10/18 10:26:57 narten
- * Updating version numbers. Changes relative to 1.0 are actually
- * relative to 1.2
- *
- * Revision 1.3 87/09/24 13:58:45 narten
- * Sources now pass through lint (if you ignore printf/sprintf/fprintf
- * warnings)
- *
- * Revision 1.2 87/03/27 14:21:48 jenkins
- * Port to suns
- *
- * Revision 1.2 83/12/05 10:12:56 wft
- * added cond. compilation for USG Unix; long timezone;
- *
- * Revision 1.1 82/05/06 11:38:00 wft
- * Initial revision
- *
- */
-
-
-#include "rcsbase.h"
-
-libId(maketId, "$Id: maketime.c,v 5.3 1991/08/19 03:13:55 eggert Exp $")
-
-static struct tm const *time2tm P((time_t));
-
-#define given(v) (0 <= (v)) /* Negative values are unspecified. */
-
-static int const daytb[] = {
- /* # days in year thus far, indexed by month (0-12!!) */
- 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
-};
+/* Convert struct partime into time_t. */
- static time_t
-maketime(atm,zone)
- struct tm const *atm;
- int zone;
-{
- register struct tm const *tp;
- register int i;
- int year, yday, mon, day, hour, min, sec, leap, localzone;
- int attempts;
- time_t t, tres;
-
- attempts = 2;
- localzone = zone==48*60;
- tres = -1;
- year = mon = day = 0; /* Keep lint happy. */
-
- do {
-
- if (localzone || !given(atm->tm_year)) {
- if (tres == -1)
- if ((tres = time((time_t*)0)) == -1)
- return -1;
- tp = time2tm(tres);
- /* Get breakdowns of default time, adjusting to zone. */
- year = tp->tm_year; /* Use to set up defaults */
- yday = tp->tm_yday;
- mon = tp->tm_mon;
- day = tp->tm_mday;
- hour = tp->tm_hour;
- min = tp->tm_min;
- if (localzone) {
- tp = localtime(&tres);
- zone =
- min - tp->tm_min + 60*(
- hour - tp->tm_hour + 24*(
- /* If years differ, it's by one day. */
- year - tp->tm_year
- ? year - tp->tm_year
- : yday - tp->tm_yday));
- }
- /* Adjust the default day, month and year according to zone. */
- if ((min -= zone) < 0) {
- if (hour-(59-min)/60 < 0 && --day <= 0) {
- if (--mon < 0) {
- --year;
- mon = 11;
- }
- day = daytb[mon+1] - daytb[mon] + (mon==1&&!(year&3));
- }
- } else
- if (
- 24 <= hour+min/60 &&
- daytb[mon+1] - daytb[mon] + (mon==1&&!(year&3)) < ++day
- ) {
- if (11 < ++mon) {
- ++year;
- mon = 0;
- }
- day = 1;
- }
- }
- if (zone < -24*60 || 24*60 < zone)
- return -1;
+/* Copyright 1992, 1993, 1994, 1995 Paul Eggert
+ Distributed under license by the Free Software Foundation, Inc.
+This file is part of RCS.
-#ifdef DEBUG
-printf("first YMD: %d %d %d\n",year,mon,day);
-#endif
- tp = atm;
-
- /* First must find date, using specified year, month, day.
- * If one of these is unspecified, it defaults either to the
- * current date (if no more global spec was given) or to the
- * zero-value for that spec (i.e. a more global spec was seen).
- * Reject times that do not fit in time_t,
- * without assuming that time_t is 32 bits or is signed.
- */
- if (given(tp->tm_year))
- {
- year = tp->tm_year;
- mon = 0; /* Since year was given, default */
- day = 1; /* for remaining specs is zero */
- }
- if (year < 69) /* 1969/12/31 OK in some timezones. */
- return -1; /* ERR: year out of range */
- leap = !(year&3) && (year%100 || !((year+300)%400));
- year -= 70; /* UNIX time starts at 1970 */
+RCS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
- /*
- * Find day of year.
- */
- {
- if (given(tp->tm_mon))
- { mon = tp->tm_mon; /* Month was specified */
- day = 1; /* so set remaining default */
- }
- if (11 < (unsigned)mon)
- return -1; /* ERR: bad month */
- if (given(tp->tm_mday)) day = tp->tm_mday;
- if(day < 1
- || (((daytb[mon+1]-daytb[mon]) < day)
- && (day!=29 || mon!=1 || !leap) ))
- return -1; /* ERR: bad day */
- yday = daytb[mon] /* Add # of days in months so far */
- + ((leap /* Leap year, and past Feb? If */
- && mon>1)? 1:0) /* so, add leap day for this year */
- + day-1; /* And finally add # days this mon */
+RCS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
- }
- if (leap+365 <= (unsigned)yday)
- return -1; /* ERR: bad YDAY */
-
- if (year < 0) {
- if (yday != 364)
- return -1; /* ERR: too early */
- t = -1;
- } else {
- tres = year*365; /* Get # days of years so far */
- if (tres/365 != year)
- return -1; /* ERR: overflow */
- t = tres
- + ((year+1)>>2) /* plus # of leap days since 1970 */
- + yday; /* and finally add # days this year */
- if (t+4 < tres)
- return -1; /* ERR: overflow */
- }
- tres = t;
+You should have received a copy of the GNU General Public License
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- if (given(i = tp->tm_wday)) /* Check WDAY if present */
- if (i != (tres+4)%7) /* 1970/01/01 was Thu = 4 */
- return -1; /* ERR: bad WDAY */
+Report problems and direct all questions to:
-#ifdef DEBUG
-printf("YMD: %d %d %d, T=%ld\n",year,mon,day,tres);
-#endif
- /*
- * Now determine time. If not given, default to zeros
- * (since time is always the least global spec)
- */
- tres *= 86400L; /* Get # seconds (24*60*60) */
- if (tres/86400L != t)
- return -1; /* ERR: overflow */
- hour = min = sec = 0;
- if (given(tp->tm_hour)) hour = tp->tm_hour;
- if (given(tp->tm_min )) min = tp->tm_min;
- if (given(tp->tm_sec )) sec = tp->tm_sec;
- if (60 <= (unsigned)min || 60 < (unsigned)sec)
- return -1; /* ERR: MS out of range */
- if (24 <= (unsigned)hour)
- if(hour != 24 || (min+sec) !=0) /* Allow 24:00 */
- return -1; /* ERR: H out of range */
-
- t = tres;
- tres += sec + 60L*(zone + min + 60*hour);
-
-#ifdef DEBUG
-printf("HMS: %d %d %d T=%ld\n",hour,min,sec,tres);
+ rcs-bugs@cs.purdue.edu
+
+*/
+
+#if has_conf_h
+# include "conf.h"
+#else
+# ifdef __STDC__
+# define P(x) x
+# else
+# define const
+# define P(x) ()
+# endif
+# include <stdlib.h>
+# include <time.h>
#endif
- if (!localzone) /* check for overflow */
- return (year<0 ? (tres<0||86400L<=tres) : tres<t) ? -1 : tres;
-
- /* Check results; LT may have had a different GMT offset back then. */
- tp = localtime(&tres);
- if (given(atm->tm_sec) && atm->tm_sec != tp->tm_sec)
- return -1; /* If seconds don't match, we're in trouble. */
- if (!(
- given(atm->tm_min) && atm->tm_min != tp->tm_min ||
- given(atm->tm_hour) && atm->tm_hour != tp->tm_hour ||
- given(atm->tm_mday) && atm->tm_mday != tp->tm_mday ||
- given(atm->tm_mon) && atm->tm_mon != tp->tm_mon ||
- given(atm->tm_year) && atm->tm_year != tp->tm_year
- ))
- return tres; /* Everything matches. */
-
- } while (--attempts);
-
- return -1;
+#include "partime.h"
+#include "maketime.h"
+
+char const maketId[]
+ = "$Id: maketime.c,v 5.11 1995/06/16 06:19:24 eggert Exp $";
+
+static int isleap P((int));
+static int month_days P((struct tm const*));
+static time_t maketime P((struct partime const*,time_t));
+
+/*
+* For maximum portability, use only localtime and gmtime.
+* Make no assumptions about the time_t epoch or the range of time_t values.
+* Avoid mktime because it's not universal and because there's no easy,
+* portable way for mktime to yield the inverse of gmtime.
+*/
+
+#define TM_YEAR_ORIGIN 1900
+
+ static int
+isleap(y)
+ int y;
+{
+ return (y&3) == 0 && (y%100 != 0 || y%400 == 0);
+}
+
+static int const month_yday[] = {
+ /* days in year before start of months 0-12 */
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
+};
+
+/* Yield the number of days in TM's month. */
+ static int
+month_days(tm)
+ struct tm const *tm;
+{
+ int m = tm->tm_mon;
+ return month_yday[m+1] - month_yday[m]
+ + (m==1 && isleap(tm->tm_year + TM_YEAR_ORIGIN));
}
/*
-* Convert Unix time to struct tm format.
-* Use Coordinated Universal Time (UTC) if version 5 or newer;
-* use local time otherwise.
+* Convert UNIXTIME to struct tm form.
+* Use gmtime if available and if !LOCALZONE, localtime otherwise.
*/
- static struct tm const *
-time2tm(unixtime)
+ struct tm *
+time2tm(unixtime, localzone)
time_t unixtime;
+ int localzone;
{
- struct tm const *tm;
+ struct tm *tm;
# if TZ_must_be_set
static char const *TZ;
if (!TZ && !(TZ = getenv("TZ")))
- faterror("TZ is not set");
+ faterror("The TZ environment variable is not set; please set it to your timezone");
# endif
- if (!(tm = (RCSversion<VERSION(5) ? localtime : gmtime)(&unixtime)))
- faterror("UTC is not available; perhaps TZ is not set?");
+ if (localzone || !(tm = gmtime(&unixtime)))
+ tm = localtime(&unixtime);
return tm;
}
+/* Yield A - B, measured in seconds. */
+ time_t
+difftm(a, b)
+ struct tm const *a, *b;
+{
+ int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+ int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+ int difference_in_day_of_year = a->tm_yday - b->tm_yday;
+ int intervening_leap_days = (
+ ((ay >> 2) - (by >> 2))
+ - (ay/100 - by/100)
+ + ((ay/100 >> 2) - (by/100 >> 2))
+ );
+ time_t difference_in_years = ay - by;
+ time_t difference_in_days = (
+ difference_in_years*365
+ + (intervening_leap_days + difference_in_day_of_year)
+ );
+ return
+ (
+ (
+ 24*difference_in_days
+ + (a->tm_hour - b->tm_hour)
+ )*60 + (a->tm_min - b->tm_min)
+ )*60 + (a->tm_sec - b->tm_sec);
+}
+
/*
-* Convert Unix time to RCS format.
-* For compatibility with older versions of RCS,
-* dates before AD 2000 are stored without the leading "19".
+* Adjust time T by adding SECONDS. SECONDS must be at most 24 hours' worth.
+* Adjust only T's year, mon, mday, hour, min and sec members;
+* plus adjust wday if it is defined.
*/
void
-time2date(unixtime,date)
- time_t unixtime;
- char date[datesize];
+adjzone(t, seconds)
+ register struct tm *t;
+ long seconds;
{
- register struct tm const *tm = time2tm(unixtime);
- VOID sprintf(date, DATEFORM,
- tm->tm_year + (tm->tm_year<100 ? 0 : 1900),
- tm->tm_mon+1, tm->tm_mday,
- tm->tm_hour, tm->tm_min, tm->tm_sec
- );
+ /*
+ * This code can be off by a second if SECONDS is not a multiple of 60,
+ * if T is local time, and if a leap second happens during this minute.
+ * But this bug has never occurred, and most likely will not ever occur.
+ * Liberia, the last country for which SECONDS % 60 was nonzero,
+ * switched to UTC in May 1972; the first leap second was in June 1972.
+ */
+ int leap_second = t->tm_sec == 60;
+ long sec = seconds + (t->tm_sec - leap_second);
+ if (sec < 0) {
+ if ((t->tm_min -= (59-sec)/60) < 0) {
+ if ((t->tm_hour -= (59-t->tm_min)/60) < 0) {
+ t->tm_hour += 24;
+ if (TM_DEFINED(t->tm_wday) && --t->tm_wday < 0)
+ t->tm_wday = 6;
+ if (--t->tm_mday <= 0) {
+ if (--t->tm_mon < 0) {
+ --t->tm_year;
+ t->tm_mon = 11;
+ }
+ t->tm_mday = month_days(t);
+ }
+ }
+ t->tm_min += 24 * 60;
+ }
+ sec += 24L * 60 * 60;
+ } else
+ if (60 <= (t->tm_min += sec/60))
+ if (24 <= (t->tm_hour += t->tm_min/60)) {
+ t->tm_hour -= 24;
+ if (TM_DEFINED(t->tm_wday) && ++t->tm_wday == 7)
+ t->tm_wday = 0;
+ if (month_days(t) < ++t->tm_mday) {
+ if (11 < ++t->tm_mon) {
+ ++t->tm_year;
+ t->tm_mon = 0;
+ }
+ t->tm_mday = 1;
+ }
+ }
+ t->tm_min %= 60;
+ t->tm_sec = (int) (sec%60) + leap_second;
}
+/*
+* Convert TM to time_t, using localtime if LOCALZONE and gmtime otherwise.
+* Use only TM's year, mon, mday, hour, min, and sec members.
+* Ignore TM's old tm_yday and tm_wday, but fill in their correct values.
+* Yield -1 on failure (e.g. a member out of range).
+* Posix 1003.1-1990 doesn't allow leap seconds, but some implementations
+* have them anyway, so allow them if localtime/gmtime does.
+*/
+ time_t
+tm2time(tm, localzone)
+ struct tm *tm;
+ int localzone;
+{
+ /* Cache the most recent t,tm pairs; 1 for gmtime, 1 for localtime. */
+ static time_t t_cache[2];
+ static struct tm tm_cache[2];
+
+ time_t d, gt;
+ struct tm const *gtm;
+ /*
+ * The maximum number of iterations should be enough to handle any
+ * combinations of leap seconds, time zone rule changes, and solar time.
+ * 4 is probably enough; we use a bigger number just to be safe.
+ */
+ int remaining_tries = 8;
+
+ /* Avoid subscript errors. */
+ if (12 <= (unsigned)tm->tm_mon)
+ return -1;
+
+ tm->tm_yday = month_yday[tm->tm_mon] + tm->tm_mday
+ - (tm->tm_mon<2 || ! isleap(tm->tm_year + TM_YEAR_ORIGIN));
+
+ /* Make a first guess. */
+ gt = t_cache[localzone];
+ gtm = gt ? &tm_cache[localzone] : time2tm(gt,localzone);
+
+ /* Repeatedly use the error from the guess to improve the guess. */
+ while ((d = difftm(tm, gtm)) != 0) {
+ if (--remaining_tries == 0)
+ return -1;
+ gt += d;
+ gtm = time2tm(gt,localzone);
+ }
+ t_cache[localzone] = gt;
+ tm_cache[localzone] = *gtm;
+
+ /*
+ * Check that the guess actually matches;
+ * overflow can cause difftm to yield 0 even on differing times,
+ * or tm may have members out of range (e.g. bad leap seconds).
+ */
+ if ( (tm->tm_year ^ gtm->tm_year)
+ | (tm->tm_mon ^ gtm->tm_mon)
+ | (tm->tm_mday ^ gtm->tm_mday)
+ | (tm->tm_hour ^ gtm->tm_hour)
+ | (tm->tm_min ^ gtm->tm_min)
+ | (tm->tm_sec ^ gtm->tm_sec))
+ return -1;
+ tm->tm_wday = gtm->tm_wday;
+ return gt;
+}
+/*
+* Check *PT and convert it to time_t.
+* If it is incompletely specified, use DEFAULT_TIME to fill it out.
+* Use localtime if PT->zone is the special value TM_LOCAL_ZONE.
+* Yield -1 on failure.
+* ISO 8601 day-of-year and week numbers are not yet supported.
+*/
static time_t
-str2time(source)
- char const *source;
-/* Parse a free-format date in SOURCE, yielding a Unix format time. */
+maketime(pt, default_time)
+ struct partime const *pt;
+ time_t default_time;
{
- int zone;
- time_t unixtime;
- struct tm parseddate;
+ int localzone, wday;
+ struct tm tm;
+ struct tm *tm0 = 0;
+ time_t r;
+
+ tm0 = 0; /* Keep gcc -Wall happy. */
+ localzone = pt->zone==TM_LOCAL_ZONE;
+
+ tm = pt->tm;
+
+ if (TM_DEFINED(pt->ymodulus) || !TM_DEFINED(tm.tm_year)) {
+ /* Get tm corresponding to current time. */
+ tm0 = time2tm(default_time, localzone);
+ if (!localzone)
+ adjzone(tm0, pt->zone);
+ }
+
+ if (TM_DEFINED(pt->ymodulus))
+ tm.tm_year +=
+ (tm0->tm_year + TM_YEAR_ORIGIN)/pt->ymodulus * pt->ymodulus;
+ else if (!TM_DEFINED(tm.tm_year)) {
+ /* Set default year, month, day from current time. */
+ tm.tm_year = tm0->tm_year + TM_YEAR_ORIGIN;
+ if (!TM_DEFINED(tm.tm_mon)) {
+ tm.tm_mon = tm0->tm_mon;
+ if (!TM_DEFINED(tm.tm_mday))
+ tm.tm_mday = tm0->tm_mday;
+ }
+ }
+
+ /* Convert from partime year (Gregorian) to Posix year. */
+ tm.tm_year -= TM_YEAR_ORIGIN;
+
+ /* Set remaining default fields to be their minimum values. */
+ if (!TM_DEFINED(tm.tm_mon)) tm.tm_mon = 0;
+ if (!TM_DEFINED(tm.tm_mday)) tm.tm_mday = 1;
+ if (!TM_DEFINED(tm.tm_hour)) tm.tm_hour = 0;
+ if (!TM_DEFINED(tm.tm_min)) tm.tm_min = 0;
+ if (!TM_DEFINED(tm.tm_sec)) tm.tm_sec = 0;
- if (!partime(source, &parseddate, &zone))
- faterror("can't parse date/time: %s", source);
- if ((unixtime = maketime(&parseddate, zone)) == -1)
- faterror("bad date/time: %s", source);
- return unixtime;
+ if (!localzone)
+ adjzone(&tm, -pt->zone);
+ wday = tm.tm_wday;
+
+ /* Convert and fill in the rest of the tm. */
+ r = tm2time(&tm, localzone);
+
+ /* Check weekday. */
+ if (r != -1 && TM_DEFINED(wday) && wday != tm.tm_wday)
+ return -1;
+
+ return r;
}
- void
-str2date(source, target)
+/* Parse a free-format date in SOURCE, yielding a Unix format time. */
+ time_t
+str2time(source, default_time, default_zone)
char const *source;
- char target[datesize];
-/* Parse a free-format date in SOURCE, convert it
- * into RCS internal format, and store the result into TARGET.
- */
+ time_t default_time;
+ long default_zone;
{
- time2date(str2time(source), target);
+ struct partime pt;
+
+ if (*partime(source, &pt))
+ return -1;
+ if (pt.zone == TM_UNDEFINED_ZONE)
+ pt.zone = default_zone;
+ return maketime(&pt, default_time);
}
+#if TEST
+#include <stdio.h>
int
-setfiledate(file, date)
- char const *file, date[datesize];
-/* Set the access and modification time of FILE to DATE. */
+main(argc, argv) int argc; char **argv;
{
- static struct utimbuf times; /* static so unused fields are zero */
- char datebuf[datesize];
-
- if (!date)
- return 0;
- times.actime = times.modtime = str2time(date2str(date, datebuf));
- return utime(file, &times);
+ time_t default_time = time((time_t *)0);
+ long default_zone = argv[1] ? atol(argv[1]) : 0;
+ char buf[1000];
+ while (gets(buf)) {
+ time_t t = str2time(buf, default_time, default_zone);
+ printf("%s", asctime(gmtime(&t)));
+ }
+ return 0;
}
+#endif
diff --git a/gnu/usr.bin/rcs/lib/maketime.h b/gnu/usr.bin/rcs/lib/maketime.h
new file mode 100644
index 0000000..fbe1256
--- /dev/null
+++ b/gnu/usr.bin/rcs/lib/maketime.h
@@ -0,0 +1,39 @@
+/* Yield time_t from struct partime yielded by partime. */
+
+/* Copyright 1993, 1994, 1995 Paul Eggert
+ Distributed under license by the Free Software Foundation, Inc.
+
+This file is part of RCS.
+
+RCS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+RCS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Report problems and direct all questions to:
+
+ rcs-bugs@cs.purdue.edu
+
+*/
+
+#if defined(__STDC__) || has_prototypes
+# define __MAKETIME_P(x) x
+#else
+# define __MAKETIME_P(x) ()
+#endif
+
+struct tm *time2tm __MAKETIME_P((time_t,int));
+time_t difftm __MAKETIME_P((struct tm const *, struct tm const *));
+time_t str2time __MAKETIME_P((char const *, time_t, long));
+time_t tm2time __MAKETIME_P((struct tm *, int));
+void adjzone __MAKETIME_P((struct tm *, long));
diff --git a/gnu/usr.bin/rcs/lib/merger.c b/gnu/usr.bin/rcs/lib/merger.c
index 7162ffa..003e0a6 100644
--- a/gnu/usr.bin/rcs/lib/merger.c
+++ b/gnu/usr.bin/rcs/lib/merger.c
@@ -1,6 +1,6 @@
-/* merger - three-way file merge internals */
+/* three-way file merge internals */
-/* Copyright 1991 by Paul Eggert
+/* Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -16,8 +16,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -27,38 +28,40 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(mergerId, "$Id: merger.c,v 1.3 1991/08/20 23:05:00 eggert Exp $")
+libId(mergerId, "$Id: merger.c,v 1.7 1995/06/16 06:19:24 eggert Exp $")
+ static char const *normalize_arg P((char const*,char**));
static char const *
normalize_arg(s, b)
char const *s;
char **b;
/*
* If S looks like an option, prepend ./ to it. Yield the result.
- * Set *B to the address of any storage that was allocated..
+ * Set *B to the address of any storage that was allocated.
*/
{
char *t;
- switch (*s) {
- case '-': case '+':
- *b = t = testalloc(strlen(s) + 3);
- VOID sprintf(t, ".%c%s", SLASH, s);
- return t;
- default:
- *b = 0;
- return s;
+ if (*s == '-') {
+ *b = t = testalloc(strlen(s) + 3);
+ VOID sprintf(t, ".%c%s", SLASH, s);
+ return t;
+ } else {
+ *b = 0;
+ return s;
}
}
int
-merge(tostdout, label, argv)
+merge(tostdout, edarg, label, argv)
int tostdout;
- char const *const label[2];
+ char const *edarg;
+ char const *const label[3];
char const *const argv[3];
/*
- * Do `merge [-p] -L l0 -L l1 a0 a1 a2',
+ * Do `merge [-p] EDARG -L l0 -L l1 -L l2 a0 a1 a2',
* where TOSTDOUT specifies whether -p is present,
- * LABEL gives l0 and l1, and ARGV gives a0, a1, and a2.
+ * EDARG gives the editing type (e.g. "-A", or null for the default),
+ * LABEL gives l0, l1 and l2, and ARGV gives a0, a1 and a2.
* Yield DIFF_SUCCESS or DIFF_FAILURE.
*/
{
@@ -74,30 +77,35 @@ merge(tostdout, label, argv)
for (i=3; 0<=--i; )
a[i] = normalize_arg(argv[i], &b[i]);
+
+ if (!edarg)
+ edarg = "-E";
#if DIFF3_BIN
t = 0;
if (!tostdout)
t = maketemp(0);
s = run(
- (char*)0, t,
- DIFF3, "-am", "-L", label[0], "-L", label[1],
+ -1, t,
+ DIFF3, edarg, "-am",
+ "-L", label[0],
+ "-L", label[1],
+ "-L", label[2],
a[0], a[1], a[2], (char*)0
);
switch (s) {
case DIFF_SUCCESS:
break;
case DIFF_FAILURE:
- if (!quietflag)
- warn("overlaps during merge");
+ warn("conflicts during merge");
break;
default:
exiterr();
}
if (t) {
- if (!(f = fopen(argv[0], FOPEN_W)))
+ if (!(f = fopenSafer(argv[0], "w")))
efaterror(argv[0]);
- if (!(rt = Iopen(t, FOPEN_R, (struct stat*)0)))
+ if (!(rt = Iopen(t, "r", (struct stat*)0)))
efaterror(t);
fastcopy(rt, f);
Ifclose(rt);
@@ -106,29 +114,30 @@ merge(tostdout, label, argv)
#else
for (i=0; i<2; i++)
switch (run(
- (char*)0, d[i]=maketemp(i),
+ -1, d[i]=maketemp(i),
DIFF, a[i], a[2], (char*)0
)) {
case DIFF_FAILURE: case DIFF_SUCCESS: break;
- default: exiterr();
+ default: faterror("diff failed");
}
t = maketemp(2);
s = run(
- (char*)0, t,
- DIFF3, "-E", d[0], d[1], a[0], a[1], a[2],
- label[0], label[1], (char*)0
+ -1, t,
+ DIFF3, edarg, d[0], d[1], a[0], a[1], a[2],
+ label[0], label[2], (char*)0
);
if (s != DIFF_SUCCESS) {
s = DIFF_FAILURE;
- if (!quietflag)
- warn("overlaps or other problems during merge");
+ warn("overlaps or other problems during merge");
}
- if (!(f = fopen(t, "a")))
+ if (!(f = fopenSafer(t, "a+")))
efaterror(t);
aputs(tostdout ? "1,$p\n" : "w\n", f);
- Ofclose(f);
- if (run(t, (char*)0, ED, "-", a[0], (char*)0))
+ Orewind(f);
+ aflush(f);
+ if (run(fileno(f), (char*)0, ED, "-", a[0], (char*)0))
exiterr();
+ Ofclose(f);
#endif
tempunlink();
diff --git a/gnu/usr.bin/rcs/lib/partime.c b/gnu/usr.bin/rcs/lib/partime.c
index 4751fc5..4246566 100644
--- a/gnu/usr.bin/rcs/lib/partime.c
+++ b/gnu/usr.bin/rcs/lib/partime.c
@@ -1,639 +1,701 @@
-/*
- * PARTIME parse date/time string into a TM structure
- *
- * Returns:
- * 0 if parsing failed
- * else time values in specified TM structure and zone (unspecified values
- * set to TMNULL)
- * Notes:
- * This code is quasi-public; it may be used freely in like software.
- * It is not to be sold, nor used in licensed software without
- * permission of the author.
- * For everyone's benefit, please report bugs and improvements!
- * Copyright 1980 by Ken Harrenstien, SRI International.
- * (ARPANET: KLH @ SRI)
- */
-
-/* Hacknotes:
- * If parsing changed so that no backup needed, could perhaps modify
- * to use a FILE input stream. Need terminator, though.
- * Perhaps should return 0 on success, else a non-zero error val?
- */
-
-/* $Log: partime.c,v $
- * Revision 5.6 1991/08/19 03:13:55 eggert
- * Update timezones.
- *
- * Revision 5.5 1991/04/21 11:58:18 eggert
- * Don't put , just before } in initializer.
- *
- * Revision 5.4 1990/10/04 06:30:15 eggert
- * Remove date vs time heuristics that fail between 2000 and 2400.
- * Check for overflow when lexing an integer.
- * Parse 'Jan 10 LT' as 'Jan 10, LT', not 'Jan, 10 LT'.
- *
- * Revision 5.3 1990/09/24 18:56:31 eggert
- * Update timezones.
- *
- * Revision 5.2 1990/09/04 08:02:16 eggert
- * Don't parse two-digit years, because it won't work after 1999/12/31.
- * Don't permit 'Aug Aug'.
- *
- * Revision 5.1 1990/08/29 07:13:49 eggert
- * Be able to parse our own date format. Don't assume year<10000.
- *
- * Revision 5.0 1990/08/22 08:12:40 eggert
- * Switch to GMT and fix the bugs exposed thereby. Update timezones.
- * Ansify and Posixate. Fix peekahead and int-size bugs.
- *
- * Revision 1.4 89/05/01 14:48:46 narten
- * fixed #ifdef DEBUG construct
- *
- * Revision 1.3 88/08/28 14:53:40 eggert
- * Remove unportable "#endif XXX"s.
- *
- * Revision 1.2 87/03/27 14:21:53 jenkins
- * Port to suns
- *
- * Revision 1.1 82/05/06 11:38:26 wft
- * Initial revision
- *
- */
-
-#include "rcsbase.h"
-
-libId(partId, "$Id: partime.c,v 5.6 1991/08/19 03:13:55 eggert Exp $")
-
-#define given(v) (0 <= (v))
-#define TMNULL (-1) /* Items not given are given this value */
-#define TZ_OFFSET (24*60) /* TMNULL < zone_offset - TZ_OFFSET */
-
-struct tmwent {
- char const *went;
- short wval;
- char wflgs;
- char wtype;
-};
- /* wflgs */
-#define TWTIME 02 /* Word is a time value (absence implies date) */
-#define TWDST 04 /* Word is a DST-type timezone */
- /* wtype */
-#define TM_MON 1 /* month name */
-#define TM_WDAY 2 /* weekday name */
-#define TM_ZON 3 /* time zone name */
-#define TM_LT 4 /* local time */
-#define TM_DST 5 /* daylight savings time */
-#define TM_12 6 /* AM, PM, NOON, or MIDNIGHT */
- /* wval (for wtype==TM_12) */
-#define T12_AM 1
-#define T12_PM 2
-#define T12_NOON 12
-#define T12_MIDNIGHT 0
-
-static struct tmwent const tmwords [] = {
- {"january", 0, 0, TM_MON},
- {"february", 1, 0, TM_MON},
- {"march", 2, 0, TM_MON},
- {"april", 3, 0, TM_MON},
- {"may", 4, 0, TM_MON},
- {"june", 5, 0, TM_MON},
- {"july", 6, 0, TM_MON},
- {"august", 7, 0, TM_MON},
- {"september", 8, 0, TM_MON},
- {"october", 9, 0, TM_MON},
- {"november", 10, 0, TM_MON},
- {"december", 11, 0, TM_MON},
-
- {"sunday", 0, 0, TM_WDAY},
- {"monday", 1, 0, TM_WDAY},
- {"tuesday", 2, 0, TM_WDAY},
- {"wednesday", 3, 0, TM_WDAY},
- {"thursday", 4, 0, TM_WDAY},
- {"friday", 5, 0, TM_WDAY},
- {"saturday", 6, 0, TM_WDAY},
-
- {"gmt", 0*60, TWTIME, TM_ZON}, /* Greenwich */
- {"utc", 0*60, TWTIME, TM_ZON},
- {"ut", 0*60, TWTIME, TM_ZON},
- {"cut", 0*60, TWTIME, TM_ZON},
-
- {"nzst", -12*60, TWTIME, TM_ZON}, /* New Zealand */
- {"jst", -9*60, TWTIME, TM_ZON}, /* Japan */
- {"kst", -9*60, TWTIME, TM_ZON}, /* Korea */
- {"ist", -5*60-30, TWTIME, TM_ZON},/* India */
- {"eet", -2*60, TWTIME, TM_ZON}, /* Eastern Europe */
- {"cet", -1*60, TWTIME, TM_ZON}, /* Central Europe */
- {"met", -1*60, TWTIME, TM_ZON}, /* Middle Europe */
- {"wet", 0*60, TWTIME, TM_ZON}, /* Western Europe */
- {"nst", 3*60+30, TWTIME, TM_ZON},/* Newfoundland */
- {"ast", 4*60, TWTIME, TM_ZON}, /* Atlantic */
- {"est", 5*60, TWTIME, TM_ZON}, /* Eastern */
- {"cst", 6*60, TWTIME, TM_ZON}, /* Central */
- {"mst", 7*60, TWTIME, TM_ZON}, /* Mountain */
- {"pst", 8*60, TWTIME, TM_ZON}, /* Pacific */
- {"akst", 9*60, TWTIME, TM_ZON}, /* Alaska */
- {"hast", 10*60, TWTIME, TM_ZON}, /* Hawaii-Aleutian */
- {"hst", 10*60, TWTIME, TM_ZON}, /* Hawaii */
- {"sst", 11*60, TWTIME, TM_ZON}, /* Samoa */
-
- {"nzdt", -12*60, TWTIME+TWDST, TM_ZON}, /* New Zealand */
- {"kdt", -9*60, TWTIME+TWDST, TM_ZON}, /* Korea */
- {"bst", 0*60, TWTIME+TWDST, TM_ZON}, /* Britain */
- {"ndt", 3*60+30, TWTIME+TWDST, TM_ZON}, /* Newfoundland */
- {"adt", 4*60, TWTIME+TWDST, TM_ZON}, /* Atlantic */
- {"edt", 5*60, TWTIME+TWDST, TM_ZON}, /* Eastern */
- {"cdt", 6*60, TWTIME+TWDST, TM_ZON}, /* Central */
- {"mdt", 7*60, TWTIME+TWDST, TM_ZON}, /* Mountain */
- {"pdt", 8*60, TWTIME+TWDST, TM_ZON}, /* Pacific */
- {"akdt", 9*60, TWTIME+TWDST, TM_ZON}, /* Alaska */
- {"hadt", 10*60, TWTIME+TWDST, TM_ZON}, /* Hawaii-Aleutian */
+/* Parse a string, yielding a struct partime that describes it. */
-#if 0
- /*
- * The following names are duplicates or are not well attested.
- * A standard is needed.
- */
- {"east", -10*60, TWTIME, TM_ZON}, /* Eastern Australia */
- {"cast", -9*60-30, TWTIME, TM_ZON},/* Central Australia */
- {"cst", -8*60, TWTIME, TM_ZON}, /* China */
- {"hkt", -8*60, TWTIME, TM_ZON}, /* Hong Kong */
- {"sst", -8*60, TWTIME, TM_ZON}, /* Singapore */
- {"wast", -8*60, TWTIME, TM_ZON}, /* Western Australia */
- {"?", -6*60-30, TWTIME, TM_ZON},/* Burma */
- {"?", -4*60-30, TWTIME, TM_ZON},/* Afghanistan */
- {"it", -3*60-30, TWTIME, TM_ZON},/* Iran */
- {"ist", -2*60, TWTIME, TM_ZON}, /* Israel */
- {"mez", -1*60, TWTIME, TM_ZON}, /* Mittel-Europaeische Zeit */
- {"ast", 1*60, TWTIME, TM_ZON}, /* Azores */
- {"fst", 2*60, TWTIME, TM_ZON}, /* Fernando de Noronha */
- {"bst", 3*60, TWTIME, TM_ZON}, /* Brazil */
- {"wst", 4*60, TWTIME, TM_ZON}, /* Western Brazil */
- {"ast", 5*60, TWTIME, TM_ZON}, /* Acre Brazil */
- {"?", 9*60+30, TWTIME, TM_ZON},/* Marquesas */
- {"?", 12*60, TWTIME, TM_ZON}, /* Kwajalein */
-
- {"eadt", -10*60, TWTIME+TWDST, TM_ZON}, /* Eastern Australia */
- {"cadt", -9*60-30, TWTIME+TWDST, TM_ZON}, /* Central Australia */
- {"cdt", -8*60, TWTIME+TWDST, TM_ZON}, /* China */
- {"wadt", -8*60, TWTIME+TWDST, TM_ZON}, /* Western Australia */
- {"idt", -2*60, TWTIME+TWDST, TM_ZON}, /* Israel */
- {"eest", -2*60, TWTIME+TWDST, TM_ZON}, /* Eastern Europe */
- {"cest", -1*60, TWTIME+TWDST, TM_ZON}, /* Central Europe */
- {"mest", -1*60, TWTIME+TWDST, TM_ZON}, /* Middle Europe */
- {"mesz", -1*60, TWTIME+TWDST, TM_ZON}, /* Mittel-Europaeische Sommerzeit */
- {"west", 0*60, TWTIME+TWDST, TM_ZON}, /* Western Europe */
- {"adt", 1*60, TWTIME+TWDST, TM_ZON}, /* Azores */
- {"fdt", 2*60, TWTIME+TWDST, TM_ZON}, /* Fernando de Noronha */
- {"edt", 3*60, TWTIME+TWDST, TM_ZON}, /* Eastern Brazil */
- {"wdt", 4*60, TWTIME+TWDST, TM_ZON}, /* Western Brazil */
- {"adt", 5*60, TWTIME+TWDST, TM_ZON}, /* Acre Brazil */
+/* Copyright 1993, 1994, 1995 Paul Eggert
+ Distributed under license by the Free Software Foundation, Inc.
+
+This file is part of RCS.
+
+RCS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+RCS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Report problems and direct all questions to:
+
+ rcs-bugs@cs.purdue.edu
+
+*/
+
+#if has_conf_h
+# include "conf.h"
+#else
+# ifdef __STDC__
+# define P(x) x
+# else
+# define const
+# define P(x) ()
+# endif
+# include <limits.h>
+# include <time.h>
#endif
- {"lt", 0, TWTIME, TM_LT}, /* local time */
- {"dst", 1*60, TWTIME, TM_DST}, /* daylight savings time */
- {"ddst", 2*60, TWTIME, TM_DST}, /* double dst */
+#include <ctype.h>
+#undef isdigit
+#define isdigit(c) (((unsigned)(c)-'0') <= 9) /* faster than stock */
+
+#include "partime.h"
+
+char const partimeId[]
+ = "$Id: partime.c,v 5.13 1995/06/16 06:19:24 eggert Exp $";
- {"am", T12_AM, TWTIME, TM_12},
- {"pm", T12_PM, TWTIME, TM_12},
- {"noon", T12_NOON, TWTIME, TM_12},
- {"midnight", T12_MIDNIGHT, TWTIME, TM_12},
- {0, 0, 0, 0} /* Zero entry to terminate searches */
+/* Lookup tables for names of months, weekdays, time zones. */
+
+#define NAME_LENGTH_MAXIMUM 4
+
+struct name_val {
+ char name[NAME_LENGTH_MAXIMUM];
+ int val;
};
-struct token {
- char const *tcp;/* pointer to string */
- int tcnt; /* # chars */
- char tbrk; /* "break" char */
- char tbrkl; /* last break char */
- char tflg; /* 0 = alpha, 1 = numeric */
- union { /* Resulting value; */
- int tnum;/* either a #, or */
- struct tmwent const *ttmw;/* a ptr to a tmwent. */
- } tval;
+
+static char const *parse_decimal P((char const*,int,int,int,int,int*,int*));
+static char const *parse_fixed P((char const*,int,int*));
+static char const *parse_pattern_letter P((char const*,int,struct partime*));
+static char const *parse_prefix P((char const*,struct partime*,int*));
+static char const *parse_ranged P((char const*,int,int,int,int*));
+static int lookup P((char const*,struct name_val const[]));
+static int merge_partime P((struct partime*, struct partime const*));
+static void undefine P((struct partime*));
+
+
+static struct name_val const month_names[] = {
+ {"jan",0}, {"feb",1}, {"mar",2}, {"apr",3}, {"may",4}, {"jun",5},
+ {"jul",6}, {"aug",7}, {"sep",8}, {"oct",9}, {"nov",10}, {"dec",11},
+ {"", TM_UNDEFINED}
};
-static struct tmwent const*ptmatchstr P((char const*,int,struct tmwent const*));
-static int pt12hack P((struct tm *,int));
-static int ptitoken P((struct token *));
-static int ptstash P((int *,int));
-static int pttoken P((struct token *));
+static struct name_val const weekday_names[] = {
+ {"sun",0}, {"mon",1}, {"tue",2}, {"wed",3}, {"thu",4}, {"fri",5}, {"sat",6},
+ {"", TM_UNDEFINED}
+};
+
+#define hr60nonnegative(t) ((t)/100 * 60 + (t)%100)
+#define hr60(t) ((t)<0 ? -hr60nonnegative(-(t)) : hr60nonnegative(t))
+#define zs(t,s) {s, hr60(t)}
+#define zd(t,s,d) zs(t, s), zs((t)+100, d)
+
+static struct name_val const zone_names[] = {
+ zs(-1000, "hst"), /* Hawaii */
+ zd(-1000,"hast","hadt"),/* Hawaii-Aleutian */
+ zd(- 900,"akst","akdt"),/* Alaska */
+ zd(- 800, "pst", "pdt"),/* Pacific */
+ zd(- 700, "mst", "mdt"),/* Mountain */
+ zd(- 600, "cst", "cdt"),/* Central */
+ zd(- 500, "est", "edt"),/* Eastern */
+ zd(- 400, "ast", "adt"),/* Atlantic */
+ zd(- 330, "nst", "ndt"),/* Newfoundland */
+ zs( 000, "utc"), /* Coordinated Universal */
+ zs( 000, "cut"), /* " */
+ zs( 000, "ut"), /* Universal */
+ zs( 000, "z"), /* Zulu (required by ISO 8601) */
+ zd( 000, "gmt", "bst"),/* Greenwich Mean, British Summer */
+ zs( 000, "wet"), /* Western Europe */
+ zs( 100, "met"), /* Middle Europe */
+ zs( 100, "cet"), /* Central Europe */
+ zs( 200, "eet"), /* Eastern Europe */
+ zs( 530, "ist"), /* India */
+ zd( 900, "jst", "jdt"),/* Japan */
+ zd( 900, "kst", "kdt"),/* Korea */
+ zd( 1200,"nzst","nzdt"),/* New Zealand */
+ { "lt", 1 },
+#if 0
+ /* The following names are duplicates or are not well attested. */
+ zs(-1100, "sst"), /* Samoa */
+ zs(-1000, "tht"), /* Tahiti */
+ zs(- 930, "mqt"), /* Marquesas */
+ zs(- 900, "gbt"), /* Gambier */
+ zd(- 900, "yst", "ydt"),/* Yukon - name is no longer used */
+ zs(- 830, "pit"), /* Pitcairn */
+ zd(- 500, "cst", "cdt"),/* Cuba */
+ zd(- 500, "ast", "adt"),/* Acre */
+ zd(- 400, "wst", "wdt"),/* Western Brazil */
+ zd(- 400, "ast", "adt"),/* Andes */
+ zd(- 400, "cst", "cdt"),/* Chile */
+ zs(- 300, "wgt"), /* Western Greenland */
+ zd(- 300, "est", "edt"),/* Eastern South America */
+ zs(- 300, "mgt"), /* Middle Greenland */
+ zd(- 200, "fst", "fdt"),/* Fernando de Noronha */
+ zs(- 100, "egt"), /* Eastern Greenland */
+ zs(- 100, "aat"), /* Atlantic Africa */
+ zs(- 100, "act"), /* Azores and Canaries */
+ zs( 000, "wat"), /* West Africa */
+ zs( 100, "cat"), /* Central Africa */
+ zd( 100, "mez","mesz"),/* Mittel-Europaeische Zeit */
+ zs( 200, "sat"), /* South Africa */
+ zd( 200, "ist", "idt"),/* Israel */
+ zs( 300, "eat"), /* East Africa */
+ zd( 300, "ast", "adt"),/* Arabia */
+ zd( 300, "msk", "msd"),/* Moscow */
+ zd( 330, "ist", "idt"),/* Iran */
+ zs( 400, "gst"), /* Gulf */
+ zs( 400, "smt"), /* Seychelles & Mascarene */
+ zd( 400, "esk", "esd"),/* Yekaterinburg */
+ zd( 400, "bsk", "bsd"),/* Baku */
+ zs( 430, "aft"), /* Afghanistan */
+ zd( 500, "osk", "osd"),/* Omsk */
+ zs( 500, "pkt"), /* Pakistan */
+ zd( 500, "tsk", "tsd"),/* Tashkent */
+ zs( 545, "npt"), /* Nepal */
+ zs( 600, "bgt"), /* Bangladesh */
+ zd( 600, "nsk", "nsd"),/* Novosibirsk */
+ zs( 630, "bmt"), /* Burma */
+ zs( 630, "cct"), /* Cocos */
+ zs( 700, "ict"), /* Indochina */
+ zs( 700, "jvt"), /* Java */
+ zd( 700, "isk", "isd"),/* Irkutsk */
+ zs( 800, "hkt"), /* Hong Kong */
+ zs( 800, "pst"), /* Philippines */
+ zs( 800, "sgt"), /* Singapore */
+ zd( 800, "cst", "cdt"),/* China */
+ zd( 800, "ust", "udt"),/* Ulan Bator */
+ zd( 800, "wst", "wst"),/* Western Australia */
+ zd( 800, "ysk", "ysd"),/* Yakutsk */
+ zs( 900, "blt"), /* Belau */
+ zs( 900, "mlt"), /* Moluccas */
+ zd( 900, "vsk", "vsd"),/* Vladivostok */
+ zd( 930, "cst", "cst"),/* Central Australia */
+ zs( 1000, "gst"), /* Guam */
+ zd( 1000, "gsk", "gsd"),/* Magadan */
+ zd( 1000, "est", "est"),/* Eastern Australia */
+ zd( 1100,"lhst","lhst"),/* Lord Howe */
+ zd( 1100, "psk", "psd"),/* Petropavlovsk-Kamchatski */
+ zs( 1100,"ncst"), /* New Caledonia */
+ zs( 1130,"nrft"), /* Norfolk */
+ zd( 1200, "ask", "asd"),/* Anadyr */
+ zs( 1245,"nz-chat"), /* Chatham */
+ zs( 1300, "tgt"), /* Tongatapu */
+#endif
+ {"", -1}
+};
static int
-goodzone(t, offset, am)
- register struct token const *t;
- int offset;
- int *am;
+lookup (s, table)
+ char const *s;
+ struct name_val const table[];
+/* Look for a prefix of S in TABLE, returning val for first matching entry. */
{
- register int m;
- if (
- t->tflg &&
- t->tcnt == 4+offset &&
- (m = t->tval.tnum) <= 2400 &&
- isdigit(t->tcp[offset]) &&
- (m%=100) < 60
- ) {
- m += t->tval.tnum/100 * 60;
- if (t->tcp[offset-1]=='+')
- m = -m;
- *am = m;
- return 1;
+ int j;
+ char buf[NAME_LENGTH_MAXIMUM];
+
+ for (j = 0; j < NAME_LENGTH_MAXIMUM; j++) {
+ unsigned char c = *s++;
+ buf[j] = isupper (c) ? tolower (c) : c;
+ if (!isalpha (c))
+ break;
+ }
+ for (; table[0].name[0]; table++)
+ for (j = 0; buf[j] == table[0].name[j]; )
+ if (++j == NAME_LENGTH_MAXIMUM || !table[0].name[j])
+ goto done;
+ done:
+ return table[0].val;
+}
+
+
+ static void
+undefine (t) struct partime *t;
+/* Set *T to ``undefined'' values. */
+{
+ t->tm.tm_sec = t->tm.tm_min = t->tm.tm_hour = t->tm.tm_mday = t->tm.tm_mon
+ = t->tm.tm_year = t->tm.tm_wday = t->tm.tm_yday
+ = t->ymodulus = t->yweek
+ = TM_UNDEFINED;
+ t->zone = TM_UNDEFINED_ZONE;
+}
+
+/*
+* Array of patterns to look for in a date string.
+* Order is important: we look for the first matching pattern
+* whose values do not contradict values that we already know about.
+* See `parse_pattern_letter' below for the meaning of the pattern codes.
+*/
+static char const * const patterns[] = {
+ /*
+ * These traditional patterns must come first,
+ * to prevent an ISO 8601 format from misinterpreting their prefixes.
+ */
+ "E_n_y", "x", /* RFC 822 */
+ "E_n", "n_E", "n", "t:m:s_A", "t:m_A", "t_A", /* traditional */
+ "y/N/D$", /* traditional RCS */
+
+ /* ISO 8601:1988 formats, generalized a bit. */
+ "y-N-D$", "4ND$", "Y-N$",
+ "RND$", "-R=N$", "-R$", "--N=D$", "N=DT",
+ "--N$", "---D$", "DT",
+ "Y-d$", "4d$", "R=d$", "-d$", "dT",
+ "y-W-X", "yWX", "y=W",
+ "-r-W-X", "r-W-XT", "-rWX", "rWXT", "-W=X", "W=XT", "-W",
+ "-w-X", "w-XT", "---X$", "XT", "4$",
+ "T",
+ "h:m:s$", "hms$", "h:m$", "hm$", "h$", "-m:s$", "-ms$", "-m$", "--s$",
+ "Y", "Z",
+
+ 0
+};
+
+ static char const *
+parse_prefix (str, t, pi) char const *str; struct partime *t; int *pi;
+/*
+* Parse an initial prefix of STR, setting *T accordingly.
+* Return the first character after the prefix, or 0 if it couldn't be parsed.
+* Start with pattern *PI; if success, set *PI to the next pattern to try.
+* Set *PI to -1 if we know there are no more patterns to try;
+* if *PI is initially negative, give up immediately.
+*/
+{
+ int i = *pi;
+ char const *pat;
+ unsigned char c;
+
+ if (i < 0)
+ return 0;
+
+ /* Remove initial noise. */
+ while (!isalnum (c = *str) && c != '-' && c != '+') {
+ if (!c) {
+ undefine (t);
+ *pi = -1;
+ return str;
+ }
+ str++;
}
+
+ /* Try a pattern until one succeeds. */
+ while ((pat = patterns[i++]) != 0) {
+ char const *s = str;
+ undefine (t);
+ do {
+ if (!(c = *pat++)) {
+ *pi = i;
+ return s;
+ }
+ } while ((s = parse_pattern_letter (s, c, t)) != 0);
+ }
+
return 0;
}
- int
-partime(astr, atm, zone)
-char const *astr;
-register struct tm *atm;
-int *zone;
+ static char const *
+parse_fixed (s, digits, res) char const *s; int digits, *res;
+/*
+* Parse an initial prefix of S of length DIGITS; it must be a number.
+* Store the parsed number into *RES.
+* Return the first character after the prefix, or 0 if it couldn't be parsed.
+*/
{
- register int i;
- struct token btoken, atoken;
- int zone_offset; /* minutes west of GMT, plus TZ_OFFSET */
- register char const *cp;
- register char ch;
- int ord, midnoon;
- int *atmfield, dst, m;
- int got1 = 0;
-
- atm->tm_sec = TMNULL;
- atm->tm_min = TMNULL;
- atm->tm_hour = TMNULL;
- atm->tm_mday = TMNULL;
- atm->tm_mon = TMNULL;
- atm->tm_year = TMNULL;
- atm->tm_wday = TMNULL;
- atm->tm_yday = TMNULL;
- midnoon = TMNULL; /* and our own temp stuff */
- zone_offset = TMNULL;
- dst = TMNULL;
- btoken.tcnt = btoken.tbrk = 0;
- btoken.tcp = astr;
-
- for (;; got1=1) {
- if (!ptitoken(&btoken)) /* Get a token */
- { if(btoken.tval.tnum) return(0); /* Read error? */
- if (given(midnoon)) /* EOF, wrap up */
- if (!pt12hack(atm, midnoon))
- return 0;
- if (!given(atm->tm_min))
- atm->tm_min = 0;
- *zone =
- (given(zone_offset) ? zone_offset-TZ_OFFSET : 0)
- - (given(dst) ? dst : 0);
- return got1;
- }
- if(btoken.tflg == 0) /* Alpha? */
- { i = btoken.tval.ttmw->wval;
- switch (btoken.tval.ttmw->wtype) {
- default:
+ int n = 0;
+ char const *lim = s + digits;
+ while (s < lim) {
+ unsigned d = *s++ - '0';
+ if (9 < d)
return 0;
- case TM_MON:
- atmfield = &atm->tm_mon;
- break;
- case TM_WDAY:
- atmfield = &atm->tm_wday;
- break;
- case TM_DST:
- atmfield = &dst;
+ n = 10*n + d;
+ }
+ *res = n;
+ return s;
+}
+
+ static char const *
+parse_ranged (s, digits, lo, hi, res) char const *s; int digits, lo, hi, *res;
+/*
+* Parse an initial prefix of S of length DIGITS;
+* it must be a number in the range LO through HI.
+* Store the parsed number into *RES.
+* Return the first character after the prefix, or 0 if it couldn't be parsed.
+*/
+{
+ s = parse_fixed (s, digits, res);
+ return s && lo<=*res && *res<=hi ? s : 0;
+}
+
+ static char const *
+parse_decimal (s, digits, lo, hi, resolution, res, fres)
+ char const *s;
+ int digits, lo, hi, resolution, *res, *fres;
+/*
+* Parse an initial prefix of S of length DIGITS;
+* it must be a number in the range LO through HI
+* and it may be followed by a fraction that is to be computed using RESOLUTION.
+* Store the parsed number into *RES; store the fraction times RESOLUTION,
+* rounded to the nearest integer, into *FRES.
+* Return the first character after the prefix, or 0 if it couldn't be parsed.
+*/
+{
+ s = parse_fixed (s, digits, res);
+ if (s && lo<=*res && *res<=hi) {
+ int f = 0;
+ if ((s[0]==',' || s[0]=='.') && isdigit ((unsigned char) s[1])) {
+ char const *s1 = ++s;
+ int num10 = 0, denom10 = 10, product;
+ while (isdigit ((unsigned char) *++s))
+ denom10 *= 10;
+ s = parse_fixed (s1, s - s1, &num10);
+ product = num10*resolution;
+ f = (product + (denom10>>1)) / denom10;
+ f -= f & (product%denom10 == denom10>>1); /* round to even */
+ if (f < 0 || product/resolution != num10)
+ return 0; /* overflow */
+ }
+ *fres = f;
+ return s;
+ }
+ return 0;
+}
+
+ char *
+parzone (s, zone) char const *s; long *zone;
+/*
+* Parse an initial prefix of S; it must denote a time zone.
+* Set *ZONE to the number of seconds east of GMT,
+* or to TM_LOCAL_ZONE if it is the local time zone.
+* Return the first character after the prefix, or 0 if it couldn't be parsed.
+*/
+{
+ char sign;
+ int hh, mm, ss;
+ int minutesEastOfUTC;
+ long offset, z;
+
+ /*
+ * The formats are LT, n, n DST, nDST, no, o
+ * where n is a time zone name
+ * and o is a time zone offset of the form [-+]hh[:mm[:ss]].
+ */
+ switch (*s) {
+ case '-': case '+':
+ z = 0;
break;
- case TM_LT:
- if (ptstash(&dst, 0))
+
+ default:
+ minutesEastOfUTC = lookup (s, zone_names);
+ if (minutesEastOfUTC == -1)
return 0;
- i = 48*60; /* local time magic number -- see maketime() */
- /* fall into */
- case TM_ZON:
- i += TZ_OFFSET;
- if (btoken.tval.ttmw->wflgs & TWDST)
- if (ptstash(&dst, 60))
- return 0;
- /* Peek ahead for offset immediately afterwards. */
+
+ /* Don't bother to check rest of spelling. */
+ while (isalpha ((unsigned char) *s))
+ s++;
+
+ /* Don't modify LT. */
+ if (minutesEastOfUTC == 1) {
+ *zone = TM_LOCAL_ZONE;
+ return (char *) s;
+ }
+
+ z = minutesEastOfUTC * 60L;
+
+ /* Look for trailing " DST". */
+ if (
+ (s[-1]=='T' || s[-1]=='t') &&
+ (s[-2]=='S' || s[-2]=='s') &&
+ (s[-3]=='D' || s[-3]=='t')
+ )
+ goto trailing_dst;
+ while (isspace ((unsigned char) *s))
+ s++;
if (
- (btoken.tbrk=='-' || btoken.tbrk=='+') &&
- (atoken=btoken, ++atoken.tcnt, ptitoken(&atoken)) &&
- goodzone(&atoken, 0, &m)
+ (s[0]=='D' || s[0]=='d') &&
+ (s[1]=='S' || s[1]=='s') &&
+ (s[2]=='T' || s[2]=='t')
) {
- i += m;
- btoken = atoken;
+ s += 3;
+ trailing_dst:
+ *zone = z + 60*60;
+ return (char *) s;
+ }
+
+ switch (*s) {
+ case '-': case '+': break;
+ default: return (char *) s;
}
- atmfield = &zone_offset;
- break;
- case TM_12:
- atmfield = &midnoon;
- }
- if (ptstash(atmfield, i))
- return(0); /* ERR: val already set */
- continue;
- }
-
- /* Token is number. Lots of hairy heuristics. */
- if (!isdigit(*btoken.tcp)) {
- if (!goodzone(&btoken, 1, &m))
- return 0;
- zone_offset = TZ_OFFSET + m;
- continue;
}
+ sign = *s++;
- i = btoken.tval.tnum; /* Value now known to be valid; get it. */
- if (btoken.tcnt == 3) /* 3 digits = HMM */
- {
-hhmm4: if (ptstash(&atm->tm_min, i%100))
- return(0); /* ERR: min conflict */
- i /= 100;
-hh2: if (ptstash(&atm->tm_hour, i))
- return(0); /* ERR: hour conflict */
- continue;
- }
-
- if (4 < btoken.tcnt)
- goto year4; /* far in the future */
- if(btoken.tcnt == 4) /* 4 digits = YEAR or HHMM */
- { if (given(atm->tm_year)) goto hhmm4; /* Already got yr? */
- if (given(atm->tm_hour)) goto year4; /* Already got hr? */
- if(btoken.tbrk == ':') /* HHMM:SS ? */
- if ( ptstash(&atm->tm_hour, i/100)
- || ptstash(&atm->tm_min, i%100))
- return(0); /* ERR: hr/min clash */
- else goto coltm2; /* Go handle SS */
- if(btoken.tbrk != ',' && btoken.tbrk != '/'
- && (atoken=btoken, ptitoken(&atoken)) /* Peek */
- && ( atoken.tflg
- ? !isdigit(*atoken.tcp)
- : atoken.tval.ttmw->wflgs & TWTIME)) /* HHMM-ZON */
- goto hhmm4;
- goto year4; /* Give up, assume year. */
- }
-
- /* From this point on, assume tcnt == 1 or 2 */
- /* 2 digits = MM, DD, or HH (MM and SS caught at coltime) */
- if(btoken.tbrk == ':') /* HH:MM[:SS] */
- goto coltime; /* must be part of time. */
- if (31 < i)
+ if (!(s = parse_ranged (s, 2, 0, 23, &hh)))
return 0;
-
- /* Check for numerical-format date */
- for (cp = "/-."; ch = *cp++;)
- { ord = (ch == '.' ? 0 : 1); /* n/m = D/M or M/D */
- if(btoken.tbrk == ch) /* "NN-" */
- { if(btoken.tbrkl != ch)
- {
- atoken = btoken;
- atoken.tcnt++;
- if (ptitoken(&atoken)
- && atoken.tflg == 0
- && atoken.tval.ttmw->wtype == TM_MON)
- goto dd2;
- if(ord)goto mm2; else goto dd2; /* "NN-" */
- } /* "-NN-" */
- if (!given(atm->tm_mday)
- && given(atm->tm_year)) /* If "YYYY-NN-" */
- goto mm2; /* then always MM */
- if(ord)goto dd2; else goto mm2;
- }
- if(btoken.tbrkl == ch /* "-NN" */
- && given(ord ? atm->tm_mon : atm->tm_mday))
- if (!given(ord ? atm->tm_mday : atm->tm_mon)) /* MM/DD */
- if(ord)goto dd2; else goto mm2;
- }
-
- /* Now reduced to choice between HH and DD */
- if (given(atm->tm_hour)) goto dd2; /* Have hour? Assume day. */
- if (given(atm->tm_mday)) goto hh2; /* Have day? Assume hour. */
- if (given(atm->tm_mon)) goto dd2; /* Have month? Assume day. */
- if(i > 24) goto dd2; /* Impossible HH means DD */
- atoken = btoken;
- if (!ptitoken(&atoken)) /* Read ahead! */
- if(atoken.tval.tnum) return(0); /* ERR: bad token */
- else goto dd2; /* EOF, assume day. */
- if ( atoken.tflg
- ? !isdigit(*atoken.tcp)
- : atoken.tval.ttmw->wflgs & TWTIME)
- /* If next token is a time spec, assume hour */
- goto hh2; /* e.g. "3 PM", "11-EDT" */
-
-dd2: if (ptstash(&atm->tm_mday, i)) /* Store day (1 based) */
- return(0);
- continue;
-
-mm2: if (ptstash(&atm->tm_mon, i-1)) /* Store month (make zero based) */
- return(0);
- continue;
-
-year4: if ((i-=1900) < 0 || ptstash(&atm->tm_year, i)) /* Store year-1900 */
- return(0); /* ERR: year conflict */
- continue;
-
- /* Hack HH:MM[[:]SS] */
-coltime:
- if (ptstash(&atm->tm_hour, i)) return 0;
- if (!ptitoken(&btoken))
- return(!btoken.tval.tnum);
- if(!btoken.tflg) return(0); /* ERR: HH:<alpha> */
- if(btoken.tcnt == 4) /* MMSS */
- if (ptstash(&atm->tm_min, btoken.tval.tnum/100)
- || ptstash(&atm->tm_sec, btoken.tval.tnum%100))
- return(0);
- else continue;
- if(btoken.tcnt != 2
- || ptstash(&atm->tm_min, btoken.tval.tnum))
- return(0); /* ERR: MM bad */
- if (btoken.tbrk != ':') continue; /* Seconds follow? */
-coltm2: if (!ptitoken(&btoken))
- return(!btoken.tval.tnum);
- if(!btoken.tflg || btoken.tcnt != 2 /* Verify SS */
- || ptstash(&atm->tm_sec, btoken.tval.tnum))
- return(0); /* ERR: SS bad */
- }
-}
-
-/* Store date/time value, return 0 if successful.
- * Fail if entry is already set.
- */
- static int
-ptstash(adr,val)
-int *adr;
-int val;
-{ register int *a;
- if (given(*(a=adr)))
- return 1;
- *a = val;
- return(0);
-}
-
-/* This subroutine is invoked for AM, PM, NOON and MIDNIGHT when wrapping up
- * just prior to returning from partime.
- */
- static int
-pt12hack(tm, aval)
-register struct tm *tm;
-register int aval;
-{ register int h = tm->tm_hour;
- switch (aval) {
- case T12_AM:
- case T12_PM:
- if (h > 12)
- return 0;
- if (h == 12)
- tm->tm_hour = 0;
- if (aval == T12_PM)
- tm->tm_hour += 12;
- break;
- default:
- if (0 < tm->tm_min || 0 < tm->tm_sec)
- return 0;
- if (!given(h) || h==12)
- tm->tm_hour = aval;
- else if (aval==T12_MIDNIGHT && (h==0 || h==24))
+ mm = ss = 0;
+ if (*s == ':')
+ s++;
+ if (isdigit ((unsigned char) *s)) {
+ if (!(s = parse_ranged (s, 2, 0, 59, &mm)))
return 0;
+ if (*s==':' && s[-3]==':' && isdigit ((unsigned char) s[1])) {
+ if (!(s = parse_ranged (s + 1, 2, 0, 59, &ss)))
+ return 0;
+ }
}
- return 1;
+ if (isdigit ((unsigned char) *s))
+ return 0;
+ offset = (hh*60 + mm)*60L + ss;
+ *zone = z + (sign=='-' ? -offset : offset);
+ /*
+ * ?? Are fractions allowed here?
+ * If so, they're not implemented.
+ */
+ return (char *) s;
}
-/* Get a token and identify it to some degree.
- * Returns 0 on failure; token.tval will be 0 for normal EOF, otherwise
- * hit error of some sort
- */
-
- static int
-ptitoken(tkp)
-register struct token *tkp;
+ static char const *
+parse_pattern_letter (s, c, t) char const *s; int c; struct partime *t;
+/*
+* Parse an initial prefix of S, matching the pattern whose code is C.
+* Set *T accordingly.
+* Return the first character after the prefix, or 0 if it couldn't be parsed.
+*/
{
- register char const *cp;
- register int i, j, k;
-
- if (!pttoken(tkp))
-#ifdef DEBUG
- {
- VOID printf("EOF\n");
- return(0);
- }
-#else
- return(0);
-#endif
- cp = tkp->tcp;
+ switch (c) {
+ case '$': /* The next character must be a non-digit. */
+ if (isdigit ((unsigned char) *s))
+ return 0;
+ break;
-#ifdef DEBUG
- VOID printf("Token: \"%.*s\" ", tkp->tcnt, cp);
-#endif
+ case '-': case '/': case ':':
+ /* These characters stand for themselves. */
+ if (*s++ != c)
+ return 0;
+ break;
- if (tkp->tflg) {
- i = tkp->tcnt;
- if (*cp == '+' || *cp == '-') {
- cp++;
- i--;
- }
- while (0 <= --i) {
- j = tkp->tval.tnum*10;
- k = j + (*cp++ - '0');
- if (j/10 != tkp->tval.tnum || k < j) {
- /* arithmetic overflow */
- tkp->tval.tnum = 1;
+ case '4': /* 4-digit year */
+ s = parse_fixed (s, 4, &t->tm.tm_year);
+ break;
+
+ case '=': /* optional '-' */
+ s += *s == '-';
+ break;
+
+ case 'A': /* AM or PM */
+ /*
+ * This matches the regular expression [AaPp][Mm]?.
+ * It must not be followed by a letter or digit;
+ * otherwise it would match prefixes of strings like "PST".
+ */
+ switch (*s++) {
+ case 'A': case 'a':
+ if (t->tm.tm_hour == 12)
+ t->tm.tm_hour = 0;
+ break;
+
+ case 'P': case 'p':
+ if (t->tm.tm_hour != 12)
+ t->tm.tm_hour += 12;
+ break;
+
+ default: return 0;
+ }
+ switch (*s) {
+ case 'M': case 'm': s++; break;
+ }
+ if (isalnum (*s))
return 0;
+ break;
+
+ case 'D': /* day of month [01-31] */
+ s = parse_ranged (s, 2, 1, 31, &t->tm.tm_mday);
+ break;
+
+ case 'd': /* day of year [001-366] */
+ s = parse_ranged (s, 3, 1, 366, &t->tm.tm_yday);
+ t->tm.tm_yday--;
+ break;
+
+ case 'E': /* extended day of month [1-9, 01-31] */
+ s = parse_ranged (s, (
+ isdigit ((unsigned char) s[0]) &&
+ isdigit ((unsigned char) s[1])
+ ) + 1, 1, 31, &t->tm.tm_mday);
+ break;
+
+ case 'h': /* hour [00-23 followed by optional fraction] */
+ {
+ int frac;
+ s = parse_decimal (s, 2, 0, 23, 60*60, &t->tm.tm_hour, &frac);
+ t->tm.tm_min = frac / 60;
+ t->tm.tm_sec = frac % 60;
}
- tkp->tval.tnum = k;
- }
- } else if (!(tkp->tval.ttmw = ptmatchstr(cp, tkp->tcnt, tmwords)))
- {
-#ifdef DEBUG
- VOID printf("Not found!\n");
-#endif
- tkp->tval.tnum = 1;
- return 0;
- }
+ break;
-#ifdef DEBUG
- if(tkp->tflg)
- VOID printf("Val: %d.\n",tkp->tval.tnum);
- else VOID printf("Found: \"%s\", val: %d, type %d\n",
- tkp->tval.ttmw->went,tkp->tval.ttmw->wval,tkp->tval.ttmw->wtype);
-#endif
+ case 'm': /* minute [00-59 followed by optional fraction] */
+ s = parse_decimal (s, 2, 0, 59, 60, &t->tm.tm_min, &t->tm.tm_sec);
+ break;
+
+ case 'n': /* month name [e.g. "Jan"] */
+ if (!TM_DEFINED (t->tm.tm_mon = lookup (s, month_names)))
+ return 0;
+ /* Don't bother to check rest of spelling. */
+ while (isalpha ((unsigned char) *s))
+ s++;
+ break;
+
+ case 'N': /* month [01-12] */
+ s = parse_ranged (s, 2, 1, 12, &t->tm.tm_mon);
+ t->tm.tm_mon--;
+ break;
- return(1);
+ case 'r': /* year % 10 (remainder in origin-0 decade) [0-9] */
+ s = parse_fixed (s, 1, &t->tm.tm_year);
+ t->ymodulus = 10;
+ break;
+
+ case_R:
+ case 'R': /* year % 100 (remainder in origin-0 century) [00-99] */
+ s = parse_fixed (s, 2, &t->tm.tm_year);
+ t->ymodulus = 100;
+ break;
+
+ case 's': /* second [00-60 followed by optional fraction] */
+ {
+ int frac;
+ s = parse_decimal (s, 2, 0, 60, 1, &t->tm.tm_sec, &frac);
+ t->tm.tm_sec += frac;
+ }
+ break;
+
+ case 'T': /* 'T' or 't' */
+ switch (*s++) {
+ case 'T': case 't': break;
+ default: return 0;
+ }
+ break;
+
+ case 't': /* traditional hour [1-9 or 01-12] */
+ s = parse_ranged (s, (
+ isdigit ((unsigned char) s[0]) && isdigit ((unsigned char) s[1])
+ ) + 1, 1, 12, &t->tm.tm_hour);
+ break;
+
+ case 'w': /* 'W' or 'w' only (stands for current week) */
+ switch (*s++) {
+ case 'W': case 'w': break;
+ default: return 0;
+ }
+ break;
+
+ case 'W': /* 'W' or 'w', followed by a week of year [00-53] */
+ switch (*s++) {
+ case 'W': case 'w': break;
+ default: return 0;
+ }
+ s = parse_ranged (s, 2, 0, 53, &t->yweek);
+ break;
+
+ case 'X': /* weekday (1=Mon ... 7=Sun) [1-7] */
+ s = parse_ranged (s, 1, 1, 7, &t->tm.tm_wday);
+ t->tm.tm_wday--;
+ break;
+
+ case 'x': /* weekday name [e.g. "Sun"] */
+ if (!TM_DEFINED (t->tm.tm_wday = lookup (s, weekday_names)))
+ return 0;
+ /* Don't bother to check rest of spelling. */
+ while (isalpha ((unsigned char) *s))
+ s++;
+ break;
+
+ case 'y': /* either R or Y */
+ if (
+ isdigit ((unsigned char) s[0]) &&
+ isdigit ((unsigned char) s[1]) &&
+ !isdigit ((unsigned char) s[2])
+ )
+ goto case_R;
+ /* fall into */
+ case 'Y': /* year in full [4 or more digits] */
+ {
+ int len = 0;
+ while (isdigit ((unsigned char) s[len]))
+ len++;
+ if (len < 4)
+ return 0;
+ s = parse_fixed (s, len, &t->tm.tm_year);
+ }
+ break;
+
+ case 'Z': /* time zone */
+ s = parzone (s, &t->zone);
+ break;
+
+ case '_': /* possibly empty sequence of non-alphanumerics */
+ while (!isalnum (*s) && *s)
+ s++;
+ break;
+
+ default: /* bad pattern */
+ return 0;
+ }
+ return s;
}
-/* Read token from input string into token structure */
static int
-pttoken(tkp)
-register struct token *tkp;
+merge_partime (t, u) struct partime *t; struct partime const *u;
+/*
+* If there is no conflict, merge into *T the additional information in *U
+* and return 0. Otherwise do nothing and return -1.
+*/
{
- register char const *cp;
- register int c;
- char const *astr;
-
- tkp->tcp = astr = cp = tkp->tcp + tkp->tcnt;
- tkp->tbrkl = tkp->tbrk; /* Set "last break" */
- tkp->tcnt = tkp->tbrk = tkp->tflg = 0;
- tkp->tval.tnum = 0;
-
- while(c = *cp++)
- { switch(c)
- { case ' ': case '\t': /* Flush all whitespace */
- case '\r': case '\n':
- case '\v': case '\f':
- if (!tkp->tcnt) { /* If no token yet */
- tkp->tcp = cp; /* ignore the brk */
- continue; /* and go on. */
- }
- /* fall into */
- case '(': case ')': /* Perhaps any non-alphanum */
- case '-': case ',': /* shd qualify as break? */
- case '+':
- case '/': case ':': case '.': /* Break chars */
- if(tkp->tcnt == 0) /* If no token yet */
- { tkp->tcp = cp; /* ignore the brk */
- tkp->tbrkl = c;
- continue; /* and go on. */
- }
- tkp->tbrk = c;
- return(tkp->tcnt);
- }
- if (!tkp->tcnt++) { /* If first char of token, */
- if (isdigit(c)) {
- tkp->tflg = 1;
- if (astr<cp-2 && (cp[-2]=='-'||cp[-2]=='+')) {
- /* timezone is break+sign+digit */
- tkp->tcp--;
- tkp->tcnt++;
- }
- }
- } else if ((isdigit(c)!=0) != tkp->tflg) { /* else check type */
- tkp->tbrk = c;
- return --tkp->tcnt; /* Wrong type, back up */
- }
- }
- return(tkp->tcnt); /* When hit EOF */
+# define conflict(a,b) ((a) != (b) && TM_DEFINED (a) && TM_DEFINED (b))
+ if (
+ conflict (t->tm.tm_sec, u->tm.tm_sec) ||
+ conflict (t->tm.tm_min, u->tm.tm_min) ||
+ conflict (t->tm.tm_hour, u->tm.tm_hour) ||
+ conflict (t->tm.tm_mday, u->tm.tm_mday) ||
+ conflict (t->tm.tm_mon, u->tm.tm_mon) ||
+ conflict (t->tm.tm_year, u->tm.tm_year) ||
+ conflict (t->tm.tm_wday, u->tm.tm_yday) ||
+ conflict (t->ymodulus, u->ymodulus) ||
+ conflict (t->yweek, u->yweek) ||
+ (
+ t->zone != u->zone &&
+ t->zone != TM_UNDEFINED_ZONE &&
+ u->zone != TM_UNDEFINED_ZONE
+ )
+ )
+ return -1;
+# undef conflict
+# define merge_(a,b) if (TM_DEFINED (b)) (a) = (b);
+ merge_ (t->tm.tm_sec, u->tm.tm_sec)
+ merge_ (t->tm.tm_min, u->tm.tm_min)
+ merge_ (t->tm.tm_hour, u->tm.tm_hour)
+ merge_ (t->tm.tm_mday, u->tm.tm_mday)
+ merge_ (t->tm.tm_mon, u->tm.tm_mon)
+ merge_ (t->tm.tm_year, u->tm.tm_year)
+ merge_ (t->tm.tm_wday, u->tm.tm_yday)
+ merge_ (t->ymodulus, u->ymodulus)
+ merge_ (t->yweek, u->yweek)
+# undef merge_
+ if (u->zone != TM_UNDEFINED_ZONE) t->zone = u->zone;
+ return 0;
}
-
- static struct tmwent const *
-ptmatchstr(astr,cnt,astruc)
- char const *astr;
- int cnt;
- struct tmwent const *astruc;
+ char *
+partime (s, t) char const *s; struct partime *t;
+/*
+* Parse a date/time prefix of S, putting the parsed result into *T.
+* Return the first character after the prefix.
+* The prefix may contain no useful information;
+* in that case, *T will contain only undefined values.
+*/
{
- register char const *cp, *mp;
- register int c;
- struct tmwent const *lastptr;
- int i;
-
- lastptr = 0;
- for(;mp = astruc->went; astruc += 1)
- { cp = astr;
- for(i = cnt; i > 0; i--)
- {
- switch (*cp++ - (c = *mp++))
- { case 0: continue; /* Exact match */
- case 'A'-'a':
- if (ctab[c] == Letter)
- continue;
- }
- break;
- }
- if(i==0)
- if (!*mp) return astruc; /* Exact match */
- else if(lastptr) return(0); /* Ambiguous */
- else lastptr = astruc; /* 1st ambig */
- }
- return lastptr;
+ struct partime p;
+
+ undefine (t);
+ while (*s) {
+ int i = 0;
+ char const *s1;
+ do {
+ if (!(s1 = parse_prefix (s, &p, &i)))
+ return (char *) s;
+ } while (merge_partime (t, &p) != 0);
+ s = s1;
+ }
+ return (char *) s;
}
diff --git a/gnu/usr.bin/rcs/lib/partime.h b/gnu/usr.bin/rcs/lib/partime.h
new file mode 100644
index 0000000..5d3983f
--- /dev/null
+++ b/gnu/usr.bin/rcs/lib/partime.h
@@ -0,0 +1,71 @@
+/* Parse a string, yielding a struct partime that describes it. */
+
+/* Copyright 1993, 1994, 1995 Paul Eggert
+ Distributed under license by the Free Software Foundation, Inc.
+
+This file is part of RCS.
+
+RCS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+RCS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Report problems and direct all questions to:
+
+ rcs-bugs@cs.purdue.edu
+
+*/
+
+#define TM_UNDEFINED (-1)
+#define TM_DEFINED(x) (0 <= (x))
+
+#define TM_UNDEFINED_ZONE ((long) -24 * 60 * 60)
+#define TM_LOCAL_ZONE (TM_UNDEFINED_ZONE - 1)
+
+struct partime {
+ /*
+ * This structure describes the parsed time.
+ * Only the following tm_* values in it are used:
+ * sec, min, hour, mday, mon, year, wday, yday.
+ * If TM_UNDEFINED(value), the parser never found the value.
+ * The tm_year field is the actual year, not the year - 1900;
+ * but see ymodulus below.
+ */
+ struct tm tm;
+
+ /*
+ * If !TM_UNDEFINED(ymodulus),
+ * then tm.tm_year is actually modulo ymodulus.
+ */
+ int ymodulus;
+
+ /*
+ * Week of year, ISO 8601 style.
+ * If TM_UNDEFINED(yweek), the parser never found yweek.
+ * Weeks start on Mondays.
+ * Week 1 includes Jan 4.
+ */
+ int yweek;
+
+ /* Seconds east of UTC; or TM_LOCAL_ZONE or TM_UNDEFINED_ZONE. */
+ long zone;
+};
+
+#if defined(__STDC__) || has_prototypes
+# define __PARTIME_P(x) x
+#else
+# define __PARTIME_P(x) ()
+#endif
+
+char *partime __PARTIME_P((char const *, struct partime *));
+char *parzone __PARTIME_P((char const *, long *));
diff --git a/gnu/usr.bin/rcs/lib/rcsbase.h b/gnu/usr.bin/rcs/lib/rcsbase.h
index c0904bb..147f7d7 100644
--- a/gnu/usr.bin/rcs/lib/rcsbase.h
+++ b/gnu/usr.bin/rcs/lib/rcsbase.h
@@ -1,11 +1,9 @@
+/* RCS common definitions and data structures */
-/*
- * RCS common definitions and data structures
- */
-#define RCSBASE "$Id: rcsbase.h,v 5.11 1991/10/07 17:32:46 eggert Exp $"
+#define RCSBASE "$Id: rcsbase.h,v 5.20 1995/06/16 06:19:24 eggert Exp $"
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -21,8 +19,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -30,19 +29,55 @@ Report problems and direct all questions to:
*/
-
-
-/*****************************************************************************
- * INSTRUCTIONS:
- * =============
- * See the Makefile for how to define C preprocessor symbols.
- * If you need to change the comment leaders, update the table comtable[]
- * in rcsfnms.c. (This can wait until you know what a comment leader is.)
- *****************************************************************************
- */
-
-
-/* $Log: rcsbase.h,v $
+/*
+ * $Log: rcsbase.h,v $
+ * Revision 5.20 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.19 1995/06/01 16:23:43 eggert
+ * (SIZEABLE_PATH): Don't depend on PATH_MAX: it's not worth configuring.
+ * (Ioffset_type,BINARY_EXPAND,MIN_UNEXPAND,MIN_UNCHANGED_EXPAND): New macros.
+ * (maps_memory): New macro; replaces many instances of `has_mmap'.
+ * (cacheptr): Renamed from cachetell.
+ * (struct RILE): New alternate name for RILE; the type is now recursive.
+ * (deallocate): New member for RILE, used for generic buffer deallocation.
+ * (cacheunget_): No longer take a failure arg; just call Ierror on failure.
+ * (struct rcslock): Renamed from struct lock, to avoid collisions with
+ * system headers on some hosts. All users changed.
+ * (basefilename): Renamed from basename, likewise.
+ * (dirtpname): Remove; no longer external.
+ * (dirlen, dateform): Remove; no longer used.
+ * (cmpdate, fopenSafer, fdSafer, readAccessFilenameBuffer): New functions.
+ * (zonelenmax): Increase to 9 for full ISO 8601 format.
+ * (catchmmapints): Depend on has_NFS.
+ *
+ * Revision 5.18 1994/03/17 14:05:48 eggert
+ * Add primitives for reading backwards from a RILE;
+ * this is needed to go back and find the $Log prefix.
+ * Specify subprocess input via file descriptor, not file name. Remove lint.
+ *
+ * Revision 5.17 1993/11/09 17:40:15 eggert
+ * Move RCS-specific time handling into rcstime.c.
+ * printf_string now takes two arguments, alas.
+ *
+ * Revision 5.16 1993/11/03 17:42:27 eggert
+ * Don't arbitrarily limit the number of joins. Remove `nil'.
+ * Add Name keyword. Don't discard ignored phrases.
+ * Add support for merge -A vs -E, and allow up to three labels.
+ * Improve quality of diagnostics and prototypes.
+ *
+ * Revision 5.15 1992/07/28 16:12:44 eggert
+ * Statement macro names now end in _.
+ *
+ * Revision 5.14 1992/02/17 23:02:22 eggert
+ * Add -T support. Work around NFS mmap SIGBUS problem.
+ *
+ * Revision 5.13 1992/01/24 18:44:19 eggert
+ * Add support for bad_creat0. lint -> RCS_lint
+ *
+ * Revision 5.12 1992/01/06 02:42:34 eggert
+ * while (E) ; -> while (E) continue;
+ *
* Revision 5.11 1991/10/07 17:32:46 eggert
* Support piece tables even if !has_mmap.
*
@@ -156,10 +191,10 @@ Report problems and direct all questions to:
#define EXIT_TROUBLE DIFF_TROUBLE
-#ifdef PATH_MAX
-# define SIZEABLE_PATH PATH_MAX /* size of a large path; not a hard limit */
-#else
+#ifdef _POSIX_PATH_MAX
# define SIZEABLE_PATH _POSIX_PATH_MAX
+#else
+# define SIZEABLE_PATH 255 /* size of a large path; not a hard limit */
#endif
/* for traditional C hosts with unusual size arguments */
@@ -188,8 +223,7 @@ Report problems and direct all questions to:
/* used in production environments. */
#define yearlength 16 /* (good through AD 9,999,999,999,999,999) */
-#define datesize (yearlength+16) /* size of output of DATEFORM */
-#define joinlength 20 /* number of joined revisions permitted */
+#define datesize (yearlength+16) /* size of output of time2date */
#define RCSTMPPREFIX '_' /* prefix for temp files in working dir */
#define KDELIM '$' /* delimiter for keywords */
#define VDELIM ':' /* separates keywords from values */
@@ -199,7 +233,6 @@ Report problems and direct all questions to:
#define true 1
#define false 0
-#define nil 0
/*
@@ -208,68 +241,79 @@ Report problems and direct all questions to:
* setupcache - sets up the local RILE cache, but does not initialize it
* cache, uncache - caches and uncaches the local RILE;
* (uncache,cache) is needed around functions that advance the RILE pointer
- * Igeteof(f,c,s) - get a char c from f, executing statement s at EOF
- * cachegeteof(c,s) - Igeteof applied to the local RILE
- * Iget(f,c) - like Igeteof, except EOF is an error
- * cacheget(c) - Iget applied to the local RILE
- * Ifileno, Irewind, Iseek, Itell - analogs to stdio routines
+ * Igeteof_(f,c,s) - get a char c from f, executing statement s at EOF
+ * cachegeteof_(c,s) - Igeteof_ applied to the local RILE
+ * Iget_(f,c) - like Igeteof_, except EOF is an error
+ * cacheget_(c) - Iget_ applied to the local RILE
+ * cacheunget_(f,c,s) - read c backwards from cached f, executing s at BOF
+ * Ifileno, Ioffset_type, Irewind, Itell - analogs to stdio routines
+ *
+ * By conventions, macros whose names end in _ are statements, not expressions.
+ * Following such macros with `; else' results in a syntax error.
*/
+#define maps_memory (has_map_fd || has_mmap)
+
#if large_memory
typedef unsigned char const *Iptr_type;
- typedef struct {
+ typedef struct RILE {
Iptr_type ptr, lim;
- unsigned char *base; /* for lint, not Iptr_type even if has_mmap */
-# if has_mmap
-# define Ifileno(f) ((f)->fd)
- int fd;
+ unsigned char *base; /* not Iptr_type for lint's sake */
+ unsigned char *readlim;
+ int fd;
+# if maps_memory
+ void (*deallocate) P((struct RILE *));
# else
-# define Ifileno(f) fileno((f)->stream)
FILE *stream;
- unsigned char *readlim;
# endif
} RILE;
-# if has_mmap
+# if maps_memory
# define declarecache register Iptr_type ptr, lim
# define setupcache(f) (lim = (f)->lim)
-# define Igeteof(f,c,s) if ((f)->ptr==(f)->lim) s else (c)= *(f)->ptr++
-# define cachegeteof(c,s) if (ptr==lim) s else (c)= *ptr++
+# define Igeteof_(f,c,s) if ((f)->ptr==(f)->lim) s else (c)= *(f)->ptr++;
+# define cachegeteof_(c,s) if (ptr==lim) s else (c)= *ptr++;
# else
+ int Igetmore P((RILE*));
# define declarecache register Iptr_type ptr; register RILE *rRILE
# define setupcache(f) (rRILE = (f))
-# define Igeteof(f,c,s) if ((f)->ptr==(f)->readlim && !Igetmore(f)) s else (c)= *(f)->ptr++
-# define cachegeteof(c,s) if (ptr==rRILE->readlim && !Igetmore(rRILE)) s else (c)= *ptr++
+# define Igeteof_(f,c,s) if ((f)->ptr==(f)->readlim && !Igetmore(f)) s else (c)= *(f)->ptr++;
+# define cachegeteof_(c,s) if (ptr==rRILE->readlim && !Igetmore(rRILE)) s else (c)= *ptr++;
# endif
# define uncache(f) ((f)->ptr = ptr)
# define cache(f) (ptr = (f)->ptr)
-# define Iget(f,c) Igeteof(f,c,Ieof();)
-# define cacheget(c) cachegeteof(c,Ieof();)
-# define Itell(f) ((f)->ptr)
-# define Iseek(f,p) ((f)->ptr = (p))
-# define Irewind(f) Iseek(f, (f)->base)
-# define cachetell() ptr
+# define Iget_(f,c) Igeteof_(f,c,Ieof();)
+# define cacheget_(c) cachegeteof_(c,Ieof();)
+# define cacheunget_(f,c) (c)=(--ptr)[-1];
+# define Ioffset_type size_t
+# define Itell(f) ((f)->ptr - (f)->base)
+# define Irewind(f) ((f)->ptr = (f)->base)
+# define cacheptr() ptr
+# define Ifileno(f) ((f)->fd)
#else
# define RILE FILE
# define declarecache register FILE *ptr
# define setupcache(f) (ptr = (f))
# define uncache(f)
# define cache(f)
-# define Igeteof(f,c,s) if(((c)=getc(f))<0){testIerror(f);if(feof(f))s}else
-# define cachegeteof(c,s) Igeteof(ptr,c,s)
-# define Iget(f,c) if (((c)=getc(f))<0) testIeof(f); else
-# define cacheget(c) Iget(ptr,c)
+# define Igeteof_(f,c,s) {if(((c)=getc(f))==EOF){testIerror(f);if(feof(f))s}}
+# define cachegeteof_(c,s) Igeteof_(ptr,c,s)
+# define Iget_(f,c) { if (((c)=getc(f))==EOF) testIeof(f); }
+# define cacheget_(c) Iget_(ptr,c)
+# define cacheunget_(f,c) if(fseek(ptr,-2L,SEEK_CUR))Ierror();else cacheget_(c)
+# define Ioffset_type long
+# define Itell(f) ftell(f)
# define Ifileno(f) fileno(f)
#endif
/* Print a char, but abort on write error. */
-#define aputc(c,o) if (putc(c,o)<0) testOerror(o); else
+#define aputc_(c,o) { if (putc(c,o)==EOF) testOerror(o); }
/* Get a character from an RCS file, perhaps copying to a new RCS file. */
-#define GETCeof(o,c,s) { cachegeteof(c,s); if (o) aputc(c,o); }
-#define GETC(o,c) { cacheget(c); if (o) aputc(c,o); }
+#define GETCeof_(o,c,s) { cachegeteof_(c,s) if (o) aputc_(c,o) }
+#define GETC_(o,c) { cacheget_(c) if (o) aputc_(c,o) }
-#define WORKMODE(RCSmode, writable) ((RCSmode)&~(S_IWUSR|S_IWGRP|S_IWOTH) | ((writable)?S_IWUSR:0))
+#define WORKMODE(RCSmode, writable) (((RCSmode)&(mode_t)~(S_IWUSR|S_IWGRP|S_IWOTH)) | ((writable)?S_IWUSR:0))
/* computes mode of working file: same as RCSmode, but write permission */
/* determined by writable */
@@ -286,7 +330,7 @@ enum tokens {
* there should be no overlap among SDELIM, KDELIM, and VDELIM
*/
-#define isdigit(c) ((unsigned)((c)-'0') <= 9) /* faster than ctab[c]==DIGIT */
+#define isdigit(c) (((unsigned)(c)-'0') <= 9) /* faster than ctab[c]==DIGIT */
@@ -313,13 +357,15 @@ struct hshentry {
char const * author; /* login of person checking in */
char const * lockedby; /* who locks the revision */
char const * state; /* state of revision (Exp by default) */
+ char const * name; /* name (if any) by which retrieved */
struct cbuf log; /* log message requested at checkin */
struct branchhead * branches; /* list of first revisions on branches*/
- struct cbuf ig; /* ignored phrases of revision */
+ struct cbuf ig; /* ignored phrases in admin part */
+ struct cbuf igtext; /* ignored phrases in deltatext part */
struct hshentry * next; /* next revision on same branch */
struct hshentry * nexthsh; /* next revision with same hash value */
- unsigned long insertlns;/* lines inserted (computed by rlog) */
- unsigned long deletelns;/* lines deleted (computed by rlog) */
+ long insertlns;/* lines inserted (computed by rlog) */
+ long deletelns;/* lines deleted (computed by rlog) */
char selector; /* true if selected, false if deleted */
};
@@ -342,10 +388,10 @@ struct access {
};
/* list element for locks */
-struct lock {
+struct rcslock {
char const * login;
struct hshentry * delta;
- struct lock * nextlock;
+ struct rcslock * nextlock;
};
/* list element for symbolic names */
@@ -358,12 +404,12 @@ struct assoc {
#define mainArgs (argc,argv) int argc; char **argv;
-#if lint
+#if RCS_lint
# define libId(name,rcsid)
# define mainProg(name,cmd,rcsid) int name mainArgs
#else
# define libId(name,rcsid) char const name[] = rcsid;
-# define mainProg(name,cmd,rcsid) char const copyright[] = "Copyright 1982,1988,1989 by Walter F. Tichy\nPurdue CS\nCopyright 1990,1991 by Paul Eggert", rcsbaseId[] = RCSBASE, cmdid[] = cmd; libId(name,rcsid) int main mainArgs
+# define mainProg(n,c,i) char const Copyright[] = "Copyright 1982,1988,1989 Walter F. Tichy, Purdue CS\nCopyright 1990,1991,1992,1993,1994,1995 Paul Eggert", baseid[] = RCSBASE, cmdid[] = c; libId(n,i) int main P((int,char**)); int main mainArgs
#endif
/*
@@ -376,6 +422,7 @@ struct assoc {
#define IDH "Id"
#define LOCKER "Locker"
#define LOG "Log"
+#define NAME "Name"
#define RCSFILE "RCSfile"
#define REVISION "Revision"
#define SOURCE "Source"
@@ -383,7 +430,7 @@ struct assoc {
#define keylength 8 /* max length of any of the above keywords */
enum markers { Nomatch, Author, Date, Header, Id,
- Locker, Log, RCSfile, Revision, Source, State };
+ Locker, Log, Name, RCSfile, Revision, Source, State };
/* This must be in the same order as rcskeys.c's Keyword[] array. */
#define DELNUMFORM "\n\n%s\n%s\n"
@@ -393,39 +440,31 @@ enum markers { Nomatch, Author, Date, Header, Id,
/* main program */
extern char const cmdid[];
-exiting void exiterr P((void));
-
-/* maketime */
-int setfiledate P((char const*,char const[datesize]));
-void str2date P((char const*,char[datesize]));
-void time2date P((time_t,char[datesize]));
+void exiterr P((void)) exiting;
/* merge */
-int merge P((int,char const*const[2],char const*const[3]));
-
-/* partime */
-int partime P((char const*,struct tm*,int*));
+int merge P((int,char const*,char const*const[3],char const*const[3]));
/* rcsedit */
#define ciklogsize 23 /* sizeof("checked in with -k by ") */
extern FILE *fcopy;
-extern char const *resultfile;
+extern char const *resultname;
extern char const ciklog[ciklogsize];
extern int locker_expansion;
-extern struct buf dirtfname[];
-#define newRCSfilename (dirtfname[0].string)
RILE *rcswriteopen P((struct buf*,struct stat*,int));
-char const *makedirtemp P((char const*,int));
+char const *makedirtemp P((int));
char const *getcaller P((void));
-int addlock P((struct hshentry*));
+int addlock P((struct hshentry*,int));
int addsymbol P((char const*,char const*,int));
int checkaccesslist P((void));
-int chnamemod P((FILE**,char const*,char const*,mode_t));
-int donerewrite P((int));
+int chnamemod P((FILE**,char const*,char const*,int,mode_t,time_t));
+int donerewrite P((int,time_t));
int dorewrite P((int,int));
-int expandline P((RILE*,FILE*,struct hshentry const*,int,FILE*));
+int expandline P((RILE*,FILE*,struct hshentry const*,int,FILE*,int));
int findlock P((int,struct hshentry**));
-void aflush P((FILE*));
+int setmtime P((char const*,time_t));
+void ORCSclose P((void));
+void ORCSerror P((void));
void copystring P((void));
void dirtempunlink P((void));
void enterstring P((void));
@@ -450,20 +489,21 @@ void xpandstring P((struct hshentry const*));
int rcsfcmp P((RILE*,struct stat const*,char const*,struct hshentry const*));
/* rcsfnms */
-#define bufautobegin(b) ((void) ((b)->string = 0, (b)->size = 0))
+#define bufautobegin(b) clear_buf(b)
+#define clear_buf(b) (VOID ((b)->string = 0, (b)->size = 0))
extern FILE *workstdout;
-extern char *workfilename;
-extern char const *RCSfilename;
+extern char *workname;
+extern char const *RCSname;
extern char const *suffixes;
+extern int fdlock;
extern struct stat RCSstat;
RILE *rcsreadopen P((struct buf*,struct stat*,int));
char *bufenlarge P((struct buf*,char const**));
-char const *basename P((char const*));
+char const *basefilename P((char const*));
char const *getfullRCSname P((void));
char const *maketemp P((int));
char const *rcssuffix P((char const*));
-int pairfilenames P((int,char**,RILE*(*)P((struct buf*,struct stat*,int)),int,int));
-size_t dirlen P((char const*));
+int pairnames P((int,char**,RILE*(*)P((struct buf*,struct stat*,int)),int,int));
struct cbuf bufremember P((struct buf*,size_t));
void bufalloc P((struct buf*,size_t));
void bufautoend P((struct buf*));
@@ -477,15 +517,17 @@ extern int interactiveflag;
extern struct buf curlogbuf;
char const *buildrevision P((struct hshentries const*,struct hshentry*,FILE*,int));
int getcstdin P((void));
+int putdtext P((struct hshentry const*,char const*,FILE*,int));
int ttystdin P((void));
-int yesorno P((int,char const*,...));
+int yesorno P((int,char const*,...)) printf_string(2,3);
struct cbuf cleanlogmsg P((char*,size_t));
struct cbuf getsstdin P((char const*,char const*,char const*,struct buf*));
void putdesc P((int,char*));
+void putdftext P((struct hshentry const*,RILE*,FILE*,int));
/* rcskeep */
extern int prevkeys;
-extern struct buf prevauthor, prevdate, prevrev, prevstate;
+extern struct buf prevauthor, prevdate, prevname, prevrev, prevstate;
int getoldkeys P((RILE*));
/* rcskeys */
@@ -502,16 +544,19 @@ extern int hshenter;
extern int nerror;
extern int nextc;
extern int quietflag;
-extern unsigned long rcsline;
+extern long rcsline;
char const *getid P((void));
-exiting void efaterror P((char const*));
-exiting void enfaterror P((int,char const*));
-exiting void faterror P((char const*,...));
-exiting void fatserror P((char const*,...));
-exiting void Ieof P((void));
-exiting void Ierror P((void));
-exiting void Oerror P((void));
+void efaterror P((char const*)) exiting;
+void enfaterror P((int,char const*)) exiting;
+void fatcleanup P((int)) exiting;
+void faterror P((char const*,...)) printf_string_exiting(1,2);
+void fatserror P((char const*,...)) printf_string_exiting(1,2);
+void rcsfaterror P((char const*,...)) printf_string_exiting(1,2);
+void Ieof P((void)) exiting;
+void Ierror P((void)) exiting;
+void Oerror P((void)) exiting;
char *checkid P((char*,int));
+char *checksym P((char*,int));
int eoflex P((void));
int getkeyopt P((char const*));
int getlex P((enum tokens));
@@ -522,16 +567,19 @@ void Ifclose P((RILE*));
void Izclose P((RILE**));
void Lexinit P((void));
void Ofclose P((FILE*));
+void Orewind P((FILE*));
void Ozclose P((FILE**));
+void aflush P((FILE*));
void afputc P((int,FILE*));
-void aprintf P((FILE*,char const*,...));
+void aprintf P((FILE*,char const*,...)) printf_string(2,3);
void aputs P((char const*,FILE*));
void checksid P((char*));
-void diagnose P((char const*,...));
+void checkssym P((char*));
+void diagnose P((char const*,...)) printf_string(1,2);
void eerror P((char const*));
void eflush P((void));
void enerror P((int,char const*));
-void error P((char const*,...));
+void error P((char const*,...)) printf_string(1,2);
void fvfprintf P((FILE*,char const*,va_list));
void getkey P((char const*));
void getkeystring P((char const*));
@@ -540,10 +588,14 @@ void oflush P((void));
void printstring P((void));
void readstring P((void));
void redefined P((int));
+void rcserror P((char const*,...)) printf_string(1,2);
+void rcswarn P((char const*,...)) printf_string(1,2);
void testIerror P((FILE*));
void testOerror P((FILE*));
-void warn P((char const*,...));
+void warn P((char const*,...)) printf_string(1,2);
void warnignore P((void));
+void workerror P((char const*,...)) printf_string(1,2);
+void workwarn P((char const*,...)) printf_string(1,2);
#if has_madvise && has_mmap && large_memory
void advise_access P((RILE*,int));
# define if_advise_access(p,f,advice) if (p) advise_access(f,advice)
@@ -551,7 +603,7 @@ void warnignore P((void));
# define advise_access(f,advice)
# define if_advise_access(p,f,advice)
#endif
-#if has_mmap && large_memory
+#if large_memory && maps_memory
RILE *I_open P((char const*,struct stat*));
# define Iopen(f,m,s) I_open(f,s)
#else
@@ -563,18 +615,20 @@ void warnignore P((void));
#endif
/* rcsmap */
-extern const enum tokens ctab[];
+extern enum tokens const ctab[];
/* rcsrev */
-char *partialno P((struct buf*,char const*,unsigned));
+char *partialno P((struct buf*,char const*,int));
+char const *namedrev P((char const*,struct hshentry*));
char const *tiprev P((void));
+int cmpdate P((char const*,char const*));
int cmpnum P((char const*,char const*));
-int cmpnumfld P((char const*,char const*,unsigned));
-int compartial P((char const*,char const*,unsigned));
+int cmpnumfld P((char const*,char const*,int));
+int compartial P((char const*,char const*,int));
int expandsym P((char const*,struct buf*));
int fexpandsym P((char const*,struct buf*,RILE*));
struct hshentry *genrevs P((char const*,char const*,char const*,char const*,struct hshentries**));
-unsigned countnumflds P((char const*));
+int countnumflds P((char const*));
void getbranchno P((char const*,struct buf*));
/* rcssyn */
@@ -584,8 +638,12 @@ void getbranchno P((char const*,struct buf*));
#define KEY_EXPAND 2 /* -kk `$Keyword$' */
#define VAL_EXPAND 3 /* -kv `value' */
#define OLD_EXPAND 4 /* -ko use old string, omitting expansion */
+#define BINARY_EXPAND 5 /* -kb like -ko, but use binary mode I/O */
+#define MIN_UNEXPAND OLD_EXPAND /* min value for no logical expansion */
+#define MIN_UNCHANGED_EXPAND (OPEN_O_BINARY ? BINARY_EXPAND : OLD_EXPAND)
+ /* min value guaranteed to yield an identical file */
struct diffcmd {
- unsigned long
+ long
line1, /* number of first line */
nlines, /* number of lines affected */
adprev, /* previous 'a' line1+1 or 'd' line1 */
@@ -595,45 +653,55 @@ extern char const * Dbranch;
extern struct access * AccessList;
extern struct assoc * Symbols;
extern struct cbuf Comment;
-extern struct lock * Locks;
+extern struct cbuf Ignored;
+extern struct rcslock *Locks;
extern struct hshentry * Head;
extern int Expand;
extern int StrictLocks;
-extern unsigned TotalDeltas;
+extern int TotalDeltas;
extern char const *const expand_names[];
-extern char const Kdesc[];
-extern char const Klog[];
-extern char const Ktext[];
+extern char const
+ Kaccess[], Kauthor[], Kbranch[], Kcomment[],
+ Kdate[], Kdesc[], Kexpand[], Khead[], Klocks[], Klog[],
+ Knext[], Kstate[], Kstrict[], Ksymbols[], Ktext[];
+void unexpected_EOF P((void)) exiting;
int getdiffcmd P((RILE*,int,FILE*,struct diffcmd*));
-int putdftext P((char const*,struct cbuf,RILE*,FILE*,int));
-int putdtext P((char const*,struct cbuf,char const*,FILE*,int));
int str2expmode P((char const*));
void getadmin P((void));
void getdesc P((int));
void gettree P((void));
-void ignorephrase P((void));
+void ignorephrases P((char const*));
void initdiffcmd P((struct diffcmd*));
-void putadmin P((FILE*));
+void putadmin P((void));
void putstring P((FILE*,int,struct cbuf,int));
void puttree P((struct hshentry const*,FILE*));
+/* rcstime */
+#define zonelenmax 9 /* maxiumum length of time zone string, e.g. "+12:34:56" */
+char const *date2str P((char const[datesize],char[datesize + zonelenmax]));
+time_t date2time P((char const[datesize]));
+void str2date P((char const*,char[datesize]));
+void time2date P((time_t,char[datesize]));
+void zone_set P((char const*));
+
/* rcsutil */
extern int RCSversion;
+FILE *fopenSafer P((char const*,char const*));
char *cgetenv P((char const*));
char *fstr_save P((char const*));
char *str_save P((char const*));
-char const *date2str P((char const[datesize],char[datesize]));
char const *getusername P((int));
+int fdSafer P((int));
int getRCSINIT P((int,char**,char***));
-int run P((char const*,char const*,...));
-int runv P((char const**));
+int run P((int,char const*,...));
+int runv P((int,char const*,char const**));
malloc_type fremember P((malloc_type));
malloc_type ftestalloc P((size_t));
malloc_type testalloc P((size_t));
malloc_type testrealloc P((malloc_type,size_t));
#define ftalloc(T) ftnalloc(T,1)
#define talloc(T) tnalloc(T,1)
-#if lint
+#if RCS_lint
extern malloc_type lintalloc;
# define ftnalloc(T,n) (lintalloc = ftestalloc(sizeof(T)*(n)), (T*)0)
# define tnalloc(T,n) (lintalloc = testalloc(sizeof(T)*(n)), (T*)0)
@@ -645,6 +713,7 @@ malloc_type testrealloc P((malloc_type,size_t));
# define trealloc(T,p,n) ((T*) testrealloc((malloc_type)(p), sizeof(T)*(n)))
# define tfree(p) free((malloc_type)(p))
#endif
+time_t now P((void));
void awrite P((char const*,size_t,FILE*));
void fastcopy P((RILE*,FILE*));
void ffree P((void));
@@ -659,6 +728,14 @@ void setRCSversion P((char const*));
# define ignoreints()
# define restoreints()
#endif
+#if has_mmap && large_memory
+# if has_NFS && mmap_signal
+ void catchmmapints P((void));
+ void readAccessFilenameBuffer P((char const*,unsigned char const*));
+# else
+# define catchmmapints()
+# endif
+#endif
#if has_getuid
uid_t ruid P((void));
# define myself(u) ((u) == ruid())
@@ -675,3 +752,6 @@ void setRCSversion P((char const*));
# define seteid()
# define setrid()
#endif
+
+/* version */
+extern char const RCS_version_string[];
diff --git a/gnu/usr.bin/rcs/lib/rcsedit.c b/gnu/usr.bin/rcs/lib/rcsedit.c
index fab4f62..6000a68 100644
--- a/gnu/usr.bin/rcs/lib/rcsedit.c
+++ b/gnu/usr.bin/rcs/lib/rcsedit.c
@@ -1,15 +1,14 @@
-/*
- * RCS stream editor
- */
-/**********************************************************************************
+/* RCS stream editor */
+
+/******************************************************************************
* edits the input file according to a
* script from stdin, generated by diff -n
* performs keyword expansion
- **********************************************************************************
+ ******************************************************************************
*/
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -25,8 +24,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -34,8 +34,56 @@ Report problems and direct all questions to:
*/
-
-/* $Log: rcsedit.c,v $
+/*
+ * $Log: rcsedit.c,v $
+ * Revision 5.19 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.18 1995/06/01 16:23:43 eggert
+ * (dirtpname): No longer external.
+ * (do_link): Simplify logic.
+ * (finisheditline, finishedit): Replace Iseek/Itell with what they stand for.
+ * (fopen_update_truncate): Replace `#if' with `if'.
+ * (keyreplace, makedirtemp): dirlen(x) -> basefilename(x)-x.
+ *
+ * (edit_string): Fix bug: if !large_memory, a bogus trailing `@' was output
+ * at the end of incomplete lines.
+ *
+ * (keyreplace): Do not assume that seeking backwards
+ * at the start of a file will fail; on some systems it succeeds.
+ * Convert C- and Pascal-style comment starts to ` *' in comment leader.
+ *
+ * (rcswriteopen): Use fdSafer to get safer file descriptor.
+ * Open RCS file with FOPEN_RB.
+ *
+ * (chnamemod): Work around bad_NFS_rename bug; don't ignore un_link result.
+ * Fall back on chmod if fchmod fails, since it might be ENOSYS.
+ *
+ * (aflush): Move to rcslex.c.
+ *
+ * Revision 5.17 1994/03/20 04:52:58 eggert
+ * Normally calculate the $Log prefix from context, not from RCS file.
+ * Move setmtime here from rcsutil.c. Add ORCSerror. Remove lint.
+ *
+ * Revision 5.16 1993/11/03 17:42:27 eggert
+ * Add -z. Add Name keyword. If bad_unlink, ignore errno when unlink fails.
+ * Escape white space, $, and \ in keyword string file names.
+ * Don't output 2 spaces between date and time after Log.
+ *
+ * Revision 5.15 1992/07/28 16:12:44 eggert
+ * Some hosts have readlink but not ELOOP. Avoid `unsigned'.
+ * Preserve dates more systematically. Statement macro names now end in _.
+ *
+ * Revision 5.14 1992/02/17 23:02:24 eggert
+ * Add -T support.
+ *
+ * Revision 5.13 1992/01/24 18:44:19 eggert
+ * Add support for bad_chmod_close, bad_creat0.
+ *
+ * Revision 5.12 1992/01/06 02:42:34 eggert
+ * Add setmode parameter to chnamemod. addsymbol now reports changes.
+ * while (E) ; -> while (E) continue;
+ *
* Revision 5.11 1991/11/03 01:11:44 eggert
* Move the warning about link breaking to where they're actually being broken.
*
@@ -154,27 +202,36 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(editId, "$Id: rcsedit.c,v 5.11 1991/11/03 01:11:44 eggert Exp $")
-
-static void keyreplace P((enum markers,struct hshentry const*,FILE*));
+libId(editId, "$Id: rcsedit.c,v 5.19 1995/06/16 06:19:24 eggert Exp $")
+static void editEndsPrematurely P((void)) exiting;
+static void editLineNumberOverflow P((void)) exiting;
+static void escape_string P((FILE*,char const*));
+static void keyreplace P((enum markers,struct hshentry const*,int,RILE*,FILE*,int));
FILE *fcopy; /* result file descriptor */
-char const *resultfile; /* result file name */
+char const *resultname; /* result pathname */
int locker_expansion; /* should the locker name be appended to Id val? */
#if !large_memory
static RILE *fedit; /* edit file descriptor */
- static char const *editfile; /* edit pathname */
+ static char const *editname; /* edit pathname */
#endif
-static unsigned long editline; /* edit line counter; #lines before cursor */
+static long editline; /* edit line counter; #lines before cursor */
static long linecorr; /* #adds - #deletes in each edit run. */
/*used to correct editline in case file is not rewound after */
/* applying one delta */
-#define DIRTEMPNAMES 2
+/* indexes into dirtpname */
+#define lockdirtp_index 0
+#define newRCSdirtp_index bad_creat0
+#define newworkdirtp_index (newRCSdirtp_index+1)
+#define DIRTEMPNAMES (newworkdirtp_index + 1)
+
enum maker {notmade, real, effective};
-struct buf dirtfname[DIRTEMPNAMES]; /* unlink these when done */
-static enum maker volatile dirtfmaker[DIRTEMPNAMES]; /* if these are set */
+static struct buf dirtpname[DIRTEMPNAMES]; /* unlink these when done */
+static enum maker volatile dirtpmaker[DIRTEMPNAMES]; /* if these are set */
+#define lockname (dirtpname[lockdirtp_index].string)
+#define newRCSname (dirtpname[newRCSdirtp_index].string)
#if has_NFS || bad_unlink
@@ -187,17 +244,19 @@ un_link(s)
*/
{
# if bad_unlink
- int e;
if (unlink(s) == 0)
return 0;
- e = errno;
-# if has_NFS
- if (e == ENOENT)
- return 0;
-# endif
- if (chmod(s, S_IWUSR) != 0) {
- errno = e;
- return -1;
+ else {
+ int e = errno;
+ /*
+ * Forge ahead even if errno == ENOENT; some completely
+ * brain-damaged hosts (e.g. PCTCP 2.2) yield ENOENT
+ * even for existing unwritable files.
+ */
+ if (chmod(s, S_IWUSR) != 0) {
+ errno = e;
+ return -1;
+ }
}
# endif
# if has_NFS
@@ -212,38 +271,37 @@ un_link(s)
# if !has_NFS
# define do_link(s,t) link(s,t)
# else
+ static int do_link P((char const*,char const*));
static int
do_link(s, t)
char const *s, *t;
/* Link S to T, ignoring bogus EEXIST problems due to NFS failures. */
{
- struct stat sb, tb;
-
- if (link(s,t) == 0)
- return 0;
- if (errno != EEXIST)
- return -1;
- if (
- stat(s, &sb) == 0 &&
- stat(t, &tb) == 0 &&
- sb.st_ino == tb.st_ino &&
- sb.st_dev == tb.st_dev
- )
- return 0;
- errno = EEXIST;
- return -1;
+ int r = link(s, t);
+
+ if (r != 0 && errno == EEXIST) {
+ struct stat sb, tb;
+ if (
+ stat(s, &sb) == 0 &&
+ stat(t, &tb) == 0 &&
+ same_file(sb, tb, 0)
+ )
+ r = 0;
+ errno = EEXIST;
+ }
+ return r;
}
# endif
#endif
- static exiting void
+ static void
editEndsPrematurely()
{
fatserror("edit script ends prematurely");
}
- static exiting void
+ static void
editLineNumberOverflow()
{
fatserror("edit script refers to line past end of file");
@@ -255,11 +313,12 @@ editLineNumberOverflow()
#if has_memmove
# define movelines(s1, s2, n) VOID memmove(s1, s2, (n)*sizeof(Iptr_type))
#else
+ static void movelines P((Iptr_type*,Iptr_type const*,long));
static void
movelines(s1, s2, n)
register Iptr_type *s1;
register Iptr_type const *s2;
- register unsigned long n;
+ register long n;
{
if (s1 < s2)
do {
@@ -275,22 +334,26 @@ movelines(s1, s2, n)
}
#endif
+static void deletelines P((long,long));
+static void finisheditline P((RILE*,FILE*,Iptr_type,struct hshentry const*));
+static void insertline P((long,Iptr_type));
+static void snapshotline P((FILE*,Iptr_type));
+
/*
* `line' contains pointers to the lines in the currently `edited' file.
* It is a 0-origin array that represents linelim-gapsize lines.
- * line[0..gap-1] and line[gap+gapsize..linelim-1] contain pointers to lines.
- * line[gap..gap+gapsize-1] contains garbage.
+ * line[0 .. gap-1] and line[gap+gapsize .. linelim-1] hold pointers to lines.
+ * line[gap .. gap+gapsize-1] contains garbage.
*
* Any @s in lines are duplicated.
* Lines are terminated by \n, or (for a last partial line only) by single @.
*/
static Iptr_type *line;
-static unsigned long gap, gapsize, linelim;
-
+static size_t gap, gapsize, linelim;
static void
insertline(n, l)
- unsigned long n;
+ long n;
Iptr_type l;
/* Before line N, insert line L. N is 0-origin. */
{
@@ -316,10 +379,10 @@ insertline(n, l)
static void
deletelines(n, nlines)
- unsigned long n, nlines;
+ long n, nlines;
/* Delete lines N through N+NLINES-1. N is 0-origin. */
{
- unsigned long l = n + nlines;
+ long l = n + nlines;
if (linelim-gapsize < l || l < n)
editLineNumberOverflow();
if (l < gap)
@@ -340,7 +403,7 @@ snapshotline(f, l)
do {
if ((c = *l++) == SDELIM && *l++ != SDELIM)
return;
- aputc(c, f);
+ aputc_(c, f)
} while (c != '\n');
}
@@ -363,8 +426,8 @@ finisheditline(fin, fout, l, delta)
Iptr_type l;
struct hshentry const *delta;
{
- Iseek(fin, l);
- if (expandline(fin, fout, delta, true, (FILE*)0) < 0)
+ fin->ptr = l;
+ if (expandline(fin, fout, delta, true, (FILE*)0, true) < 0)
faterror("finisheditline internal error");
}
@@ -386,28 +449,27 @@ finishedit(delta, outfile, done)
else {
register Iptr_type *p, *lim, *l = line;
register RILE *fin = finptr;
- Iptr_type here = Itell(fin);
+ Iptr_type here = fin->ptr;
for (p=l, lim=l+gap; p<lim; )
finisheditline(fin, outfile, *p++, delta);
for (p+=gapsize, lim=l+linelim; p<lim; )
finisheditline(fin, outfile, *p++, delta);
- Iseek(fin, here);
+ fin->ptr = here;
}
}
}
-/* Open a temporary FILENAME for output, truncating any previous contents. */
-# define fopen_update_truncate(filename) fopen(filename, FOPEN_W_WORK)
+/* Open a temporary NAME for output, truncating any previous contents. */
+# define fopen_update_truncate(name) fopenSafer(name, FOPEN_W_WORK)
#else /* !large_memory */
+ static FILE * fopen_update_truncate P((char const*));
static FILE *
-fopen_update_truncate(filename)
- char const *filename;
+fopen_update_truncate(name)
+ char const *name;
{
-# if bad_fopen_wplus
- if (un_link(filename) != 0)
- efaterror(filename);
-# endif
- return fopen(filename, FOPEN_WPLUS_WORK);
+ if (bad_fopen_wplus && un_link(name) != 0)
+ efaterror(name);
+ return fopenSafer(name, FOPEN_WPLUS_WORK);
}
#endif
@@ -417,31 +479,31 @@ openfcopy(f)
FILE *f;
{
if (!(fcopy = f)) {
- if (!resultfile)
- resultfile = maketemp(2);
- if (!(fcopy = fopen_update_truncate(resultfile)))
- efaterror(resultfile);
+ if (!resultname)
+ resultname = maketemp(2);
+ if (!(fcopy = fopen_update_truncate(resultname)))
+ efaterror(resultname);
}
}
#if !large_memory
+ static void swapeditfiles P((FILE*));
static void
swapeditfiles(outfile)
FILE *outfile;
-/* Function: swaps resultfile and editfile, assigns fedit=fcopy,
+/* Function: swaps resultname and editname, assigns fedit=fcopy,
* and rewinds fedit for reading. Set fcopy to outfile if nonnull;
- * otherwise, set fcopy to be resultfile opened for reading and writing.
+ * otherwise, set fcopy to be resultname opened for reading and writing.
*/
{
char const *tmpptr;
editline = 0; linecorr = 0;
- if (fseek(fcopy, 0L, SEEK_SET) != 0)
- Oerror();
+ Orewind(fcopy);
fedit = fcopy;
- tmpptr=editfile; editfile=resultfile; resultfile=tmpptr;
+ tmpptr=editname; editname=resultname; resultname=tmpptr;
openfcopy(outfile);
}
@@ -450,7 +512,7 @@ snapshotedit(f)
FILE *f;
/* Copy the current state of the edits to F. */
{
- finishedit((struct hshentry *)nil, (FILE*)0, false);
+ finishedit((struct hshentry *)0, (FILE*)0, false);
fastcopy(fedit, f);
Irewind(fedit);
}
@@ -461,7 +523,7 @@ finishedit(delta, outfile, done)
FILE *outfile;
int done;
/* copy the rest of the edit file and close it (if it exists).
- * if delta!=nil, perform keyword substitution at the same time.
+ * if delta, perform keyword substitution at the same time.
* If DONE is set, we are finishing the last pass.
*/
{
@@ -471,8 +533,8 @@ finishedit(delta, outfile, done)
fe = fedit;
if (fe) {
fc = fcopy;
- if (delta!=nil) {
- while (1 < expandline(fe,fc,delta,false,(FILE*)0))
+ if (delta) {
+ while (1 < expandline(fe,fc,delta,false,(FILE*)0,true))
;
} else {
fastcopy(fe,fc);
@@ -489,13 +551,14 @@ finishedit(delta, outfile, done)
#if large_memory
# define copylines(upto,delta) (editline = (upto))
#else
+ static void copylines P((long,struct hshentry const*));
static void
-copylines(upto,delta)
- register unsigned long upto;
+copylines(upto, delta)
+ register long upto;
struct hshentry const *delta;
/*
* Copy input lines editline+1..upto from fedit to fcopy.
- * If delta != nil, keyword expansion is done simultaneously.
+ * If delta, keyword expansion is done simultaneously.
* editline is updated. Rewinds a file only if necessary.
*/
{
@@ -506,7 +569,7 @@ copylines(upto,delta)
if (upto < editline) {
/* swap files */
- finishedit((struct hshentry *)nil, (FILE*)0, false);
+ finishedit((struct hshentry *)0, (FILE*)0, false);
/* assumes edit only during last pass, from the beginning*/
}
fe = fedit;
@@ -514,15 +577,15 @@ copylines(upto,delta)
if (editline < upto)
if (delta)
do {
- if (expandline(fe,fc,delta,false,(FILE*)0) <= 1)
- editLineNumberOverflow();
+ if (expandline(fe,fc,delta,false,(FILE*)0,true) <= 1)
+ editLineNumberOverflow();
} while (++editline < upto);
else {
setupcache(fe); cache(fe);
do {
do {
- cachegeteof(c, editLineNumberOverflow(););
- aputc(c, fc);
+ cachegeteof_(c, editLineNumberOverflow();)
+ aputc_(c, fc)
} while (c != '\n');
} while (++editline < upto);
uncache(fe);
@@ -541,8 +604,8 @@ xpandstring(delta)
* If foutptr is nonnull, the string is also copied unchanged to foutptr.
*/
{
- while (1 < expandline(finptr,fcopy,delta,true,foutptr))
- ;
+ while (1 < expandline(finptr,fcopy,delta,true,foutptr,true))
+ continue;
}
@@ -566,7 +629,7 @@ copystring()
fcop = fcopy;
amidline = false;
for (;;) {
- GETC(frew,c);
+ GETC_(frew,c)
switch (c) {
case '\n':
++editline;
@@ -574,7 +637,7 @@ copystring()
amidline = false;
break;
case SDELIM:
- GETC(frew,c);
+ GETC_(frew,c)
if (c != SDELIM) {
/* end of string */
nextc = c;
@@ -587,7 +650,7 @@ copystring()
amidline = true;
break;
}
- aputc(c,fcop);
+ aputc_(c,fcop)
}
}
@@ -597,18 +660,18 @@ enterstring()
/* Like copystring, except the string is put into the edit data structure. */
{
#if !large_memory
- editfile = 0;
+ editname = 0;
fedit = 0;
editline = linecorr = 0;
- resultfile = maketemp(1);
- if (!(fcopy = fopen_update_truncate(resultfile)))
- efaterror(resultfile);
+ resultname = maketemp(1);
+ if (!(fcopy = fopen_update_truncate(resultname)))
+ efaterror(resultname);
copystring();
#else
register int c;
declarecache;
register FILE *frew;
- register unsigned long e, oe;
+ register long e, oe;
register int amidline, oamidline;
register Iptr_type optr;
register RILE *fin;
@@ -622,8 +685,8 @@ enterstring()
frew = foutptr;
amidline = false;
for (;;) {
- optr = cachetell();
- GETC(frew,c);
+ optr = cacheptr();
+ GETC_(frew,c)
oamidline = amidline;
oe = e;
switch (c) {
@@ -633,7 +696,7 @@ enterstring()
amidline = false;
break;
case SDELIM:
- GETC(frew,c);
+ GETC_(frew,c)
if (c != SDELIM) {
/* end of string */
nextc = c;
@@ -667,13 +730,13 @@ edit_string()
* Read an edit script from finptr and applies it to the edit file.
#if !large_memory
* The result is written to fcopy.
- * If delta!=nil, keyword expansion is performed simultaneously.
+ * If delta, keyword expansion is performed simultaneously.
* If running out of lines in fedit, fedit and fcopy are swapped.
- * editfile is the name of the file that goes with fedit.
+ * editname is the name of the file that goes with fedit.
#endif
* If foutptr is set, the edit script is also copied verbatim to foutptr.
* Assumes that all these files are open.
- * resultfile is the name of the file that goes with fcopy.
+ * resultname is the name of the file that goes with fcopy.
* Assumes the next input character from finptr is the first character of
* the edit script. Resets nextc on exit.
*/
@@ -684,13 +747,13 @@ edit_string()
register FILE *frew;
# if !large_memory
register FILE *f;
- unsigned long line_lim = ULONG_MAX;
+ long line_lim = LONG_MAX;
register RILE *fe;
# endif
- register unsigned long i;
+ register long i;
register RILE *fin;
# if large_memory
- register unsigned long j;
+ register long j;
# endif
struct diffcmd dc;
@@ -718,12 +781,13 @@ edit_string()
do {
/*skip next line*/
do {
- Igeteof(fe, c, { if (i!=1) editLineNumberOverflow(); line_lim = dc.dafter; break; } );
+ Igeteof_(fe, c, { if (i!=1) editLineNumberOverflow(); line_lim = dc.dafter; break; } )
} while (c != '\n');
} while (--i);
# endif
} else {
- copylines(dc.line1, delta); /*copy only; no delete*/
+ /* Copy lines without deleting any. */
+ copylines(dc.line1, delta);
i = dc.nlines;
# if large_memory
j = editline+linecorr;
@@ -733,7 +797,7 @@ edit_string()
f = fcopy;
if (delta)
do {
- switch (expandline(fin,f,delta,true,frew)) {
+ switch (expandline(fin,f,delta,true,frew,true)){
case 0: case 1:
if (i==1)
return;
@@ -748,17 +812,12 @@ edit_string()
cache(fin);
do {
# if large_memory
- insertline(j++, cachetell());
+ insertline(j++, cacheptr());
# endif
for (;;) {
- GETC(frew, c);
-# if !large_memory
- aputc(c, f);
-# endif
- if (c == '\n')
- break;
+ GETC_(frew, c)
if (c==SDELIM) {
- GETC(frew, c);
+ GETC_(frew, c)
if (c!=SDELIM) {
if (--i)
editEndsPrematurely();
@@ -767,6 +826,11 @@ edit_string()
return;
}
}
+# if !large_memory
+ aputc_(c, f)
+# endif
+ if (c == '\n')
+ break;
}
++rcsline;
} while (--i);
@@ -782,17 +846,18 @@ edit_string()
int
-expandline(infile, outfile, delta, delimstuffed, frewfile)
+expandline(infile, outfile, delta, delimstuffed, frewfile, dolog)
RILE *infile;
FILE *outfile, *frewfile;
struct hshentry const *delta;
- int delimstuffed;
+ int delimstuffed, dolog;
/*
* Read a line from INFILE and write it to OUTFILE.
+ * Do keyword expansion with data from DELTA.
* If DELIMSTUFFED is true, double SDELIM is replaced with single SDELIM.
- * Keyword expansion is performed with data from delta.
* If FREWFILE is set, copy the line unchanged to FREWFILE.
* DELIMSTUFFED must be true if FREWFILE is set.
+ * Append revision history to log only if DOLOG is set.
* Yields -1 if no data is copied, 0 if an incomplete line is copied,
* 2 if a complete line is copied; adds 1 to yield if expansion occurred.
*/
@@ -815,15 +880,15 @@ expandline(infile, outfile, delta, delimstuffed, frewfile)
r = -1;
for (;;) {
- if (ds) {
- GETC(frew, c);
- } else
- cachegeteof(c, goto uncache_exit;);
+ if (ds)
+ GETC_(frew, c)
+ else
+ cachegeteof_(c, goto uncache_exit;)
for (;;) {
switch (c) {
case SDELIM:
if (ds) {
- GETC(frew, c);
+ GETC_(frew, c)
if (c != SDELIM) {
/* end of string */
nextc=c;
@@ -832,13 +897,13 @@ expandline(infile, outfile, delta, delimstuffed, frewfile)
}
/* fall into */
default:
- aputc(c,out);
+ aputc_(c,out)
r = 0;
break;
case '\n':
rcsline += ds;
- aputc(c,out);
+ aputc_(c,out)
r = 2;
goto uncache_exit;
@@ -849,11 +914,11 @@ expandline(infile, outfile, delta, delimstuffed, frewfile)
tp = keyval.string;
*tp++ = KDELIM;
for (;;) {
- if (ds) {
- GETC(frew, c);
- } else
- cachegeteof(c, goto keystring_eof;);
- if (tp < keyval.string+keylength+1)
+ if (ds)
+ GETC_(frew, c)
+ else
+ cachegeteof_(c, goto keystring_eof;)
+ if (tp <= &keyval.string[keylength])
switch (ctab[c]) {
case LETTER: case Letter:
*tp++ = c;
@@ -876,17 +941,17 @@ expandline(infile, outfile, delta, delimstuffed, frewfile)
/* try to find closing KDELIM, and replace value */
tlim = keyval.string + keyval.size;
for (;;) {
- if (ds) {
- GETC(frew, c);
- } else
- cachegeteof(c, goto keystring_eof;);
+ if (ds)
+ GETC_(frew, c)
+ else
+ cachegeteof_(c, goto keystring_eof;)
if (c=='\n' || c==KDELIM)
break;
*tp++ =c;
if (tlim <= tp)
tp = bufenlarge(&keyval, &tlim);
if (c==SDELIM && ds) { /*skip next SDELIM */
- GETC(frew, c);
+ GETC_(frew, c)
if (c != SDELIM) {
/* end of string before closing KDELIM or newline */
nextc = c;
@@ -902,7 +967,9 @@ expandline(infile, outfile, delta, delimstuffed, frewfile)
}
}
/* now put out the new keyword value */
- keyreplace(matchresult,delta,out);
+ uncache(infile);
+ keyreplace(matchresult, delta, ds, infile, out, dolog);
+ cache(infile);
e = 1;
break;
}
@@ -919,113 +986,228 @@ expandline(infile, outfile, delta, delimstuffed, frewfile)
}
+ static void
+escape_string(out, s)
+ register FILE *out;
+ register char const *s;
+/* Output to OUT the string S, escaping chars that would break `ci -k'. */
+{
+ register char c;
+ for (;;)
+ switch ((c = *s++)) {
+ case 0: return;
+ case '\t': aputs("\\t", out); break;
+ case '\n': aputs("\\n", out); break;
+ case ' ': aputs("\\040", out); break;
+ case KDELIM: aputs("\\044", out); break;
+ case '\\': if (VERSION(5)<=RCSversion) {aputs("\\\\", out); break;}
+ /* fall into */
+ default: aputc_(c, out) break;
+ }
+}
+
char const ciklog[ciklogsize] = "checked in with -k by ";
static void
-keyreplace(marker,delta,out)
+keyreplace(marker, delta, delimstuffed, infile, out, dolog)
enum markers marker;
register struct hshentry const *delta;
+ int delimstuffed;
+ RILE *infile;
register FILE *out;
+ int dolog;
/* function: outputs the keyword value(s) corresponding to marker.
* Attributes are derived from delta.
*/
{
register char const *sp, *cp, *date;
- register char c;
+ register int c;
register size_t cs, cw, ls;
char const *sp1;
- char datebuf[datesize];
+ char datebuf[datesize + zonelenmax];
int RCSv;
+ int exp;
sp = Keyword[(int)marker];
-
- if (Expand == KEY_EXPAND) {
- aprintf(out, "%c%s%c", KDELIM, sp, KDELIM);
- return;
- }
-
- date= delta->date;
+ exp = Expand;
+ date = delta->date;
RCSv = RCSversion;
- if (Expand == KEYVAL_EXPAND || Expand == KEYVALLOCK_EXPAND)
- aprintf(out, "%c%s%c%c", KDELIM, sp, VDELIM,
+ if (exp != VAL_EXPAND)
+ aprintf(out, "%c%s", KDELIM, sp);
+ if (exp != KEY_EXPAND) {
+
+ if (exp != VAL_EXPAND)
+ aprintf(out, "%c%c", VDELIM,
marker==Log && RCSv<VERSION(5) ? '\t' : ' '
);
- switch (marker) {
- case Author:
+ switch (marker) {
+ case Author:
aputs(delta->author, out);
break;
- case Date:
+ case Date:
aputs(date2str(date,datebuf), out);
break;
- case Id:
- case Header:
- aprintf(out, "%s %s %s %s %s",
- marker==Id || RCSv<VERSION(4)
- ? basename(RCSfilename)
- : getfullRCSname(),
+ case Id:
+ case Header:
+ escape_string(out,
+ marker==Id || RCSv<VERSION(4)
+ ? basefilename(RCSname)
+ : getfullRCSname()
+ );
+ aprintf(out, " %s %s %s %s",
delta->num,
date2str(date, datebuf),
delta->author,
RCSv==VERSION(3) && delta->lockedby ? "Locked"
: delta->state
);
- if (delta->lockedby!=nil)
+ if (delta->lockedby)
if (VERSION(5) <= RCSv) {
- if (locker_expansion || Expand==KEYVALLOCK_EXPAND)
+ if (locker_expansion || exp==KEYVALLOCK_EXPAND)
aprintf(out, " %s", delta->lockedby);
} else if (RCSv == VERSION(4))
aprintf(out, " Locker: %s", delta->lockedby);
break;
- case Locker:
+ case Locker:
if (delta->lockedby)
if (
locker_expansion
- || Expand == KEYVALLOCK_EXPAND
+ || exp == KEYVALLOCK_EXPAND
|| RCSv <= VERSION(4)
)
aputs(delta->lockedby, out);
break;
- case Log:
- case RCSfile:
- aputs(basename(RCSfilename), out);
+ case Log:
+ case RCSfile:
+ escape_string(out, basefilename(RCSname));
break;
- case Revision:
+ case Name:
+ if (delta->name)
+ aputs(delta->name, out);
+ break;
+ case Revision:
aputs(delta->num, out);
break;
- case Source:
- aputs(getfullRCSname(), out);
+ case Source:
+ escape_string(out, getfullRCSname());
break;
- case State:
+ case State:
aputs(delta->state, out);
break;
- default:
+ default:
break;
- }
- if (Expand == KEYVAL_EXPAND || Expand == KEYVALLOCK_EXPAND) {
+ }
+ if (exp != VAL_EXPAND)
afputc(' ', out);
- afputc(KDELIM, out);
}
- if (marker == Log) {
+ if (exp != VAL_EXPAND)
+ afputc(KDELIM, out);
+
+ if (marker == Log && dolog) {
+ struct buf leader;
+
sp = delta->log.string;
ls = delta->log.size;
if (sizeof(ciklog)-1<=ls && !memcmp(sp,ciklog,sizeof(ciklog)-1))
return;
+ bufautobegin(&leader);
+ if (RCSversion < VERSION(5)) {
+ cp = Comment.string;
+ cs = Comment.size;
+ } else {
+ int kdelim_found = 0;
+ Ioffset_type chars_read = Itell(infile);
+ declarecache;
+ setupcache(infile); cache(infile);
+
+ c = 0; /* Pacify `gcc -Wall'. */
+
+ /*
+ * Back up to the start of the current input line,
+ * setting CS to the number of characters before `$Log'.
+ */
+ cs = 0;
+ for (;;) {
+ if (!--chars_read)
+ goto done_backing_up;
+ cacheunget_(infile, c)
+ if (c == '\n')
+ break;
+ if (c == SDELIM && delimstuffed) {
+ if (!--chars_read)
+ break;
+ cacheunget_(infile, c)
+ if (c != SDELIM) {
+ cacheget_(c)
+ break;
+ }
+ }
+ cs += kdelim_found;
+ kdelim_found |= c==KDELIM;
+ }
+ cacheget_(c)
+ done_backing_up:;
+
+ /* Copy characters before `$Log' into LEADER. */
+ bufalloc(&leader, cs);
+ cp = leader.string;
+ for (cw = 0; cw < cs; cw++) {
+ leader.string[cw] = c;
+ if (c == SDELIM && delimstuffed)
+ cacheget_(c)
+ cacheget_(c)
+ }
+
+ /* Convert traditional C or Pascal leader to ` *'. */
+ for (cw = 0; cw < cs; cw++)
+ if (ctab[(unsigned char) cp[cw]] != SPACE)
+ break;
+ if (
+ cw+1 < cs
+ && cp[cw+1] == '*'
+ && (cp[cw] == '/' || cp[cw] == '(')
+ ) {
+ size_t i = cw+1;
+ for (;;)
+ if (++i == cs) {
+ warn(
+ "`%c* $Log' is obsolescent; use ` * $Log'.",
+ cp[cw]
+ );
+ leader.string[cw] = ' ';
+ break;
+ } else if (ctab[(unsigned char) cp[i]] != SPACE)
+ break;
+ }
+
+ /* Skip `$Log ... $' string. */
+ do {
+ cacheget_(c)
+ } while (c != KDELIM);
+ uncache(infile);
+ }
afputc('\n', out);
- cp = Comment.string;
- cw = cs = Comment.size;
awrite(cp, cs, out);
- /* oddity: 2 spaces between date and time, not 1 as usual */
- sp1 = strchr(date2str(date,datebuf), ' ');
- aprintf(out, "Revision %s %.*s %s %s",
- delta->num, (int)(sp1-datebuf), datebuf, sp1, delta->author
- );
+ sp1 = date2str(date, datebuf);
+ if (VERSION(5) <= RCSv) {
+ aprintf(out, "Revision %s %s %s",
+ delta->num, sp1, delta->author
+ );
+ } else {
+ /* oddity: 2 spaces between date and time, not 1 as usual */
+ sp1 = strchr(sp1, ' ');
+ aprintf(out, "Revision %s %.*s %s %s",
+ delta->num, (int)(sp1-datebuf), datebuf, sp1,
+ delta->author
+ );
+ }
/* Do not include state: it may change and is not updated. */
- /* Comment is the comment leader. */
+ cw = cs;
if (VERSION(5) <= RCSv)
for (; cw && (cp[cw-1]==' ' || cp[cw-1]=='\t'); --cw)
- ;
+ continue;
for (;;) {
afputc('\n', out);
awrite(cp, cw, out);
@@ -1044,10 +1226,12 @@ keyreplace(marker,delta,out)
} while (c != '\n');
}
}
+ bufautoend(&leader);
}
}
#if has_readlink
+ static int resolve_symlink P((struct buf*));
static int
resolve_symlink(L)
struct buf *L;
@@ -1063,7 +1247,7 @@ resolve_symlink(L)
size_t s;
ssize_t r;
struct buf bigbuf;
- unsigned linkcount = MAXSYMLINKS + 1;
+ int linkcount = MAXSYMLINKS;
b = a;
s = sizeof(a);
@@ -1073,21 +1257,29 @@ resolve_symlink(L)
bufalloc(&bigbuf, s<<1);
b = bigbuf.string;
s = bigbuf.size;
- } else if (!--linkcount) {
+ } else if (!linkcount--) {
+# ifndef ELOOP
+ /*
+ * Some pedantic Posix 1003.1-1990 hosts have readlink
+ * but not ELOOP. Approximate ELOOP with EMLINK.
+ */
+# define ELOOP EMLINK
+# endif
errno = ELOOP;
return -1;
} else {
/* Splice symbolic link into L. */
b[r] = '\0';
- L->string[ROOTPATH(b) ? (size_t)0 : dirlen(L->string)] = '\0';
+ L->string[
+ ROOTPATH(b) ? 0 : basefilename(L->string) - L->string
+ ] = '\0';
bufscat(L, b);
}
e = errno;
bufautoend(&bigbuf);
errno = e;
switch (e) {
- case ENXIO:
- case EINVAL: return 1;
+ case readlink_isreg_errno: return 1;
case ENOENT: return 0;
default: return -1;
}
@@ -1100,24 +1292,23 @@ rcswriteopen(RCSbuf, status, mustread)
struct stat *status;
int mustread;
/*
- * Create the lock file corresponding to RCSNAME.
- * Then try to open RCSNAME for reading and yield its FILE* descriptor.
+ * Create the lock file corresponding to RCSBUF.
+ * Then try to open RCSBUF for reading and yield its RILE* descriptor.
* Put its status into *STATUS too.
* MUSTREAD is true if the file must already exist, too.
* If all goes well, discard any previously acquired locks,
- * and set frewrite to the FILE* descriptor of the lock file,
- * which will eventually turn into the new RCS file.
+ * and set fdlock to the file descriptor of the RCS lockfile.
*/
{
register char *tp;
- register char const *sp, *RCSname, *x;
+ register char const *sp, *RCSpath, *x;
RILE *f;
size_t l;
- int e, exists, fdesc, previouslock, r;
+ int e, exists, fdesc, fdescSafer, r, waslocked;
struct buf *dirt;
struct stat statbuf;
- previouslock = frewrite != 0;
+ waslocked = 0 <= fdlock;
exists =
# if has_readlink
resolve_symlink(RCSbuf);
@@ -1125,7 +1316,7 @@ rcswriteopen(RCSbuf, status, mustread)
stat(RCSbuf->string, &statbuf) == 0 ? 1
: errno==ENOENT ? 0 : -1;
# endif
- if (exists < (mustread|previouslock))
+ if (exists < (mustread|waslocked))
/*
* There's an unusual problem with the RCS file;
* or the RCS file doesn't exist,
@@ -1133,26 +1324,26 @@ rcswriteopen(RCSbuf, status, mustread)
*/
return 0;
- RCSname = RCSbuf->string;
- sp = basename(RCSname);
- l = sp - RCSname;
- dirt = &dirtfname[previouslock];
- bufscpy(dirt, RCSname);
+ RCSpath = RCSbuf->string;
+ sp = basefilename(RCSpath);
+ l = sp - RCSpath;
+ dirt = &dirtpname[waslocked];
+ bufscpy(dirt, RCSpath);
tp = dirt->string + l;
- x = rcssuffix(RCSname);
+ x = rcssuffix(RCSpath);
# if has_readlink
if (!x) {
- error("symbolic link to non RCS filename `%s'", RCSname);
+ error("symbolic link to non RCS file `%s'", RCSpath);
errno = EINVAL;
return 0;
}
# endif
if (*sp == *x) {
- error("RCS filename `%s' incompatible with suffix `%s'", sp, x);
+ error("RCS pathname `%s' incompatible with suffix `%s'", sp, x);
errno = EINVAL;
return 0;
}
- /* Create a lock file whose name is a function of the RCS filename. */
+ /* Create a lock filename that is a function of the RCS filename. */
if (*x) {
/*
* The suffix is nonempty.
@@ -1172,38 +1363,41 @@ rcswriteopen(RCSbuf, status, mustread)
* with last char replaced by '_'.
*/
while ((*tp++ = *sp++))
- ;
+ continue;
tp -= 2;
if (*tp == '_') {
- error("RCS filename `%s' ends with `%c'", RCSname, *tp);
+ error("RCS pathname `%s' ends with `%c'", RCSpath, *tp);
errno = EINVAL;
return 0;
}
*tp = '_';
}
- sp = tp = dirt->string;
+ sp = dirt->string;
f = 0;
/*
* good news:
- * open(f, O_CREAT|O_EXCL|O_TRUNC|O_WRONLY, READONLY) is atomic
- * according to Posix 1003.1-1990.
+ * open(f, O_CREAT|O_EXCL|O_TRUNC|..., OPEN_CREAT_READONLY)
+ * is atomic according to Posix 1003.1-1990.
* bad news:
* NFS ignores O_EXCL and doesn't comply with Posix 1003.1-1990.
* good news:
- * (O_TRUNC,READONLY) normally guarantees atomicity even with NFS.
+ * (O_TRUNC,OPEN_CREAT_READONLY) normally guarantees atomicity
+ * even with NFS.
* bad news:
- * If you're root, (O_TRUNC,READONLY) doesn't guarantee atomicity.
+ * If you're root, (O_TRUNC,OPEN_CREAT_READONLY) doesn't
+ * guarantee atomicity.
* good news:
* Root-over-the-wire NFS access is rare for security reasons.
* This bug has never been reported in practice with RCS.
* So we don't worry about this bug.
*
* An even rarer NFS bug can occur when clients retry requests.
- * Suppose client A renames the lock file ",f," to "f,v"
- * at about the same time that client B creates ",f,",
+ * This can happen in the usual case of NFS over UDP.
+ * Suppose client A releases a lock by renaming ",f," to "f,v" at
+ * about the same time that client B obtains a lock by creating ",f,",
* and suppose A's first rename request is delayed, so A reissues it.
* The sequence of events might be:
* A sends rename(",f,", "f,v")
@@ -1216,20 +1410,20 @@ rcswriteopen(RCSbuf, status, mustread)
* This not only wrongly deletes B's lock, it removes the RCS file!
* Most NFS implementations have idempotency caches that usually prevent
* this scenario, but such caches are finite and can be overrun.
- * This problem afflicts programs that use the traditional
+ * This problem afflicts not only RCS, which uses open() and rename()
+ * to get and release locks; it also afflicts the traditional
* Unix method of using link() and unlink() to get and release locks,
- * as well as RCS's method of using open() and rename().
- * There is no easy workaround for either link-unlink or open-rename.
+ * and the less traditional method of using mkdir() and rmdir().
+ * There is no easy workaround.
* Any new method based on lockf() seemingly would be incompatible with
* the old methods; besides, lockf() is notoriously buggy under NFS.
* Since this problem afflicts scads of Unix programs, but is so rare
* that nobody seems to be worried about it, we won't worry either.
*/
-# define READONLY (S_IRUSR|S_IRGRP|S_IROTH)
# if !open_can_creat
-# define create(f) creat(f, READONLY)
+# define create(f) creat(f, OPEN_CREAT_READONLY)
# else
-# define create(f) open(f, O_BINARY|O_CREAT|O_EXCL|O_TRUNC|O_WRONLY, READONLY)
+# define create(f) open(f, OPEN_O_BINARY|OPEN_O_LOCK|OPEN_O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, OPEN_CREAT_READONLY)
# endif
catchints();
@@ -1241,34 +1435,35 @@ rcswriteopen(RCSbuf, status, mustread)
*/
seteid();
fdesc = create(sp);
+ fdescSafer = fdSafer(fdesc); /* Do it now; setrid might use stderr. */
e = errno;
setrid();
- if (fdesc < 0) {
- if (e == EACCES && stat(tp,&statbuf) == 0)
+ if (0 <= fdesc)
+ dirtpmaker[0] = effective;
+
+ if (fdescSafer < 0) {
+ if (e == EACCES && stat(sp,&statbuf) == 0)
/* The RCS file is busy. */
e = EEXIST;
} else {
- dirtfmaker[0] = effective;
e = ENOENT;
if (exists) {
- f = Iopen(RCSname, FOPEN_R, status);
+ f = Iopen(RCSpath, FOPEN_RB, status);
e = errno;
- if (f && previouslock) {
+ if (f && waslocked) {
/* Discard the previous lock in favor of this one. */
- Ozclose(&frewrite);
+ ORCSclose();
seteid();
- if ((r = un_link(newRCSfilename)) != 0)
- e = errno;
+ r = un_link(lockname);
+ e = errno;
setrid();
if (r != 0)
- enfaterror(e, newRCSfilename);
- bufscpy(&dirtfname[0], tp);
+ enfaterror(e, lockname);
+ bufscpy(&dirtpname[lockdirtp_index], sp);
}
}
- if (!(frewrite = fdopen(fdesc, FOPEN_W))) {
- efaterror(newRCSfilename);
- }
+ fdlock = fdescSafer;
}
restoreints();
@@ -1286,33 +1481,31 @@ keepdirtemp(name)
{
register int i;
for (i=DIRTEMPNAMES; 0<=--i; )
- if (dirtfname[i].string == name) {
- dirtfmaker[i] = notmade;
+ if (dirtpname[i].string == name) {
+ dirtpmaker[i] = notmade;
return;
}
faterror("keepdirtemp");
}
char const *
-makedirtemp(name, n)
- register char const *name;
- int n;
+makedirtemp(isworkfile)
+ int isworkfile;
/*
- * Have maketemp() do all the work if name is null.
- * Otherwise, create a unique filename in name's dir using n and name
- * and store it into the dirtfname[n].
- * Because of storage in tfnames, dirtempunlink() can unlink the file later.
- * Return a pointer to the filename created.
+ * Create a unique pathname and store it into dirtpname.
+ * Because of storage in tpnames, dirtempunlink() can unlink the file later.
+ * Return a pointer to the pathname created.
+ * If ISWORKFILE is 1, put it into the working file's directory;
+ * if 0, put the unique file in RCSfile's directory.
*/
{
register char *tp, *np;
register size_t dl;
register struct buf *bn;
+ register char const *name = isworkfile ? workname : RCSname;
- if (!name)
- return maketemp(n);
- dl = dirlen(name);
- bn = &dirtfname[n];
+ dl = basefilename(name) - name;
+ bn = &dirtpname[newRCSdirtp_index + isworkfile];
bufalloc(bn,
# if has_mktemp
dl + 9
@@ -1324,19 +1517,19 @@ makedirtemp(name, n)
np = tp = bn->string;
tp += dl;
*tp++ = '_';
- *tp++ = '0'+n;
+ *tp++ = '0'+isworkfile;
catchints();
# if has_mktemp
VOID strcpy(tp, "XXXXXX");
if (!mktemp(np) || !*np)
- faterror("can't make temporary file name `%.*s%c_%cXXXXXX'",
- (int)dl, name, SLASH, '0'+n
+ faterror("can't make temporary pathname `%.*s_%cXXXXXX'",
+ (int)dl, name, '0'+isworkfile
);
# else
/*
* Posix 1003.1-1990 has no reliable way
* to create a unique file in a named directory.
- * We fudge here. If the working file name is abcde,
+ * We fudge here. If the filename is abcde,
* the temp filename is _Ncde where N is a digit.
*/
name += dl;
@@ -1344,7 +1537,7 @@ makedirtemp(name, n)
if (*name) name++;
VOID strcpy(tp, name);
# endif
- dirtfmaker[n] = real;
+ dirtpmaker[newRCSdirtp_index + isworkfile] = real;
return np;
}
@@ -1356,84 +1549,127 @@ dirtempunlink()
enum maker m;
for (i = DIRTEMPNAMES; 0 <= --i; )
- if ((m = dirtfmaker[i]) != notmade) {
+ if ((m = dirtpmaker[i]) != notmade) {
if (m == effective)
seteid();
- VOID un_link(dirtfname[i].string);
+ VOID un_link(dirtpname[i].string);
if (m == effective)
setrid();
- dirtfmaker[i] = notmade;
+ dirtpmaker[i] = notmade;
}
}
int
#if has_prototypes
-chnamemod(FILE **fromp, char const *from, char const *to, mode_t mode)
+chnamemod(
+ FILE **fromp, char const *from, char const *to,
+ int set_mode, mode_t mode, time_t mtime
+)
/* The `#if has_prototypes' is needed because mode_t might promote to int. */
#else
- chnamemod(fromp,from,to,mode) FILE **fromp; char const *from,*to; mode_t mode;
+ chnamemod(fromp, from, to, set_mode, mode, mtime)
+ FILE **fromp; char const *from,*to;
+ int set_mode; mode_t mode; time_t mtime;
#endif
/*
- * Rename a file (with optional stream pointer *FROMP) from FROM to TO.
+ * Rename a file (with stream pointer *FROMP) from FROM to TO.
* FROM already exists.
- * Change its mode to MODE, before renaming if possible.
- * If FROMP, close and clear *FROMP before renaming it.
+ * If 0 < SET_MODE, change the mode to MODE, before renaming if possible.
+ * If MTIME is not -1, change its mtime to MTIME before renaming.
+ * Close and clear *FROMP before renaming it.
* Unlink TO if it already exists.
* Return -1 on error (setting errno), 0 otherwise.
*/
{
+ mode_t mode_while_renaming = mode;
+ int fchmod_set_mode = 0;
+
+# if bad_a_rename || bad_NFS_rename
+ struct stat st;
+ if (bad_NFS_rename || (bad_a_rename && set_mode <= 0)) {
+ if (fstat(fileno(*fromp), &st) != 0)
+ return -1;
+ if (bad_a_rename && set_mode <= 0)
+ mode = st.st_mode;
+ }
+# endif
+
# if bad_a_rename
/*
- * This host is brain damaged. A race condition is possible
- * while the lock file is temporarily writable.
- * There doesn't seem to be a workaround.
- */
- mode_t mode_while_renaming = mode|S_IWUSR;
-# else
-# define mode_while_renaming mode
+ * There's a short window of inconsistency
+ * during which the lock file is writable.
+ */
+ mode_while_renaming = mode|S_IWUSR;
+ if (mode != mode_while_renaming)
+ set_mode = 1;
# endif
- if (fromp) {
-# if has_fchmod
- if (fchmod(fileno(*fromp), mode_while_renaming) != 0)
- return -1;
-# endif
- Ozclose(fromp);
- }
+
# if has_fchmod
- else
+ if (0<set_mode && fchmod(fileno(*fromp),mode_while_renaming) == 0)
+ fchmod_set_mode = set_mode;
# endif
- if (chmod(from, mode_while_renaming) != 0)
+ /* If bad_chmod_close, we must close before chmod. */
+ Ozclose(fromp);
+ if (fchmod_set_mode<set_mode && chmod(from, mode_while_renaming) != 0)
+ return -1;
+
+ if (setmtime(from, mtime) != 0)
return -1;
# if !has_rename || bad_b_rename
- VOID un_link(to);
/*
- * We need not check the result;
- * link() or rename() will catch it.
- * No harm is done if TO does not exist.
- * However, there's a short window of inconsistency
- * during which TO does not exist.
- */
+ * There's a short window of inconsistency
+ * during which TO does not exist.
+ */
+ if (un_link(to) != 0 && errno != ENOENT)
+ return -1;
# endif
- return
-# if !has_rename
- do_link(from,to) != 0 ? -1 : un_link(from)
-# else
- rename(from, to) != 0
-# if has_NFS
- && errno != ENOENT
-# endif
- ? -1
-# if bad_a_rename
- : mode != mode_while_renaming ? chmod(to, mode)
-# endif
- : 0
-# endif
- ;
+# if has_rename
+ if (rename(from,to) != 0 && !(has_NFS && errno==ENOENT))
+ return -1;
+# else
+ if (do_link(from,to) != 0 || un_link(from) != 0)
+ return -1;
+# endif
-# undef mode_while_renaming
+# if bad_NFS_rename
+ {
+ /*
+ * Check whether the rename falsely reported success.
+ * A race condition can occur between the rename and the stat.
+ */
+ struct stat tostat;
+ if (stat(to, &tostat) != 0)
+ return -1;
+ if (! same_file(st, tostat, 0)) {
+ errno = EIO;
+ return -1;
+ }
+ }
+# endif
+
+# if bad_a_rename
+ if (0 < set_mode && chmod(to, mode) != 0)
+ return -1;
+# endif
+
+ return 0;
+}
+
+ int
+setmtime(file, mtime)
+ char const *file;
+ time_t mtime;
+/* Set FILE's last modified time to MTIME, but do nothing if MTIME is -1. */
+{
+ static struct utimbuf amtime; /* static so unused fields are zero */
+ if (mtime == -1)
+ return 0;
+ amtime.actime = now();
+ amtime.modtime = mtime;
+ return utime(file, &amtime);
}
@@ -1449,13 +1685,13 @@ findlock(delete, target)
* Return 0 for no locks, 1 for one, 2 for two or more.
*/
{
- register struct lock *next, **trail, **found;
+ register struct rcslock *next, **trail, **found;
found = 0;
for (trail = &Locks; (next = *trail); trail = &next->nextlock)
if (strcmp(getcaller(), next->login) == 0) {
if (found) {
- error("multiple revisions locked by %s; please specify one", getcaller());
+ rcserror("multiple revisions locked by %s; please specify one", getcaller());
return 2;
}
found = trail;
@@ -1465,36 +1701,37 @@ findlock(delete, target)
next = *found;
*target = next->delta;
if (delete) {
- next->delta->lockedby = nil;
+ next->delta->lockedby = 0;
*found = next->nextlock;
}
return 1;
}
int
-addlock(delta)
+addlock(delta, verbose)
struct hshentry * delta;
+ int verbose;
/*
* Add a lock held by caller to DELTA and yield 1 if successful.
- * Print an error message and yield -1 if no lock is added because
+ * Print an error message if verbose and yield -1 if no lock is added because
* DELTA is locked by somebody other than caller.
* Return 0 if the caller already holds the lock.
*/
{
- register struct lock *next;
+ register struct rcslock *next;
- next=Locks;
for (next = Locks; next; next = next->nextlock)
if (cmpnum(delta->num, next->delta->num) == 0)
if (strcmp(getcaller(), next->login) == 0)
return 0;
else {
- error("revision %s already locked by %s",
- delta->num, next->login
- );
+ if (verbose)
+ rcserror("Revision %s is already locked by %s.",
+ delta->num, next->login
+ );
return -1;
}
- next = ftalloc(struct lock);
+ next = ftalloc(struct rcslock);
delta->lockedby = next->login = getcaller();
next->delta = delta;
next->nextlock = Locks;
@@ -1511,28 +1748,30 @@ addsymbol(num, name, rebind)
* Associate with revision NUM the new symbolic NAME.
* If NAME already exists and REBIND is set, associate NAME with NUM;
* otherwise, print an error message and return false;
- * Return true if successful.
+ * Return -1 if unsuccessful, 0 if no change, 1 if change.
*/
{
register struct assoc *next;
for (next = Symbols; next; next = next->nextassoc)
if (strcmp(name, next->symbol) == 0)
- if (rebind || strcmp(next->num,num) == 0) {
+ if (strcmp(next->num,num) == 0)
+ return 0;
+ else if (rebind) {
next->num = num;
- return true;
+ return 1;
} else {
- error("symbolic name %s already bound to %s",
+ rcserror("symbolic name %s already bound to %s",
name, next->num
);
- return false;
+ return -1;
}
next = ftalloc(struct assoc);
next->symbol = name;
next->num = num;
next->nextassoc = Symbols;
Symbols = next;
- return true;
+ return 1;
}
@@ -1568,7 +1807,7 @@ checkaccesslist()
return true;
} while ((next = next->nextaccess));
- error("user %s not on the access list", getcaller());
+ rcserror("user %s not on the access list", getcaller());
return false;
}
@@ -1581,45 +1820,65 @@ dorewrite(lockflag, changed)
* Prepare to rewrite an RCS file if CHANGED is positive.
* Stop rewriting if CHANGED is zero, because there won't be any changes.
* Fail if CHANGED is negative.
- * Return true on success.
+ * Return 0 on success, -1 on failure.
*/
{
- int r, e;
+ int r = 0, e;
if (lockflag)
if (changed) {
if (changed < 0)
- return false;
- putadmin(frewrite);
+ return -1;
+ putadmin();
puttree(Head, frewrite);
aprintf(frewrite, "\n\n%s%c", Kdesc, nextc);
foutptr = frewrite;
} else {
- Ozclose(&frewrite);
+# if bad_creat0
+ int nr = !!frewrite, ne = 0;
+# endif
+ ORCSclose();
seteid();
ignoreints();
- r = un_link(newRCSfilename);
+# if bad_creat0
+ if (nr) {
+ nr = un_link(newRCSname);
+ ne = errno;
+ keepdirtemp(newRCSname);
+ }
+# endif
+ r = un_link(lockname);
e = errno;
- keepdirtemp(newRCSfilename);
+ keepdirtemp(lockname);
restoreints();
setrid();
- if (r != 0) {
- enerror(e, RCSfilename);
- return false;
- }
+ if (r != 0)
+ enerror(e, lockname);
+# if bad_creat0
+ if (nr != 0) {
+ enerror(ne, newRCSname);
+ r = -1;
+ }
+# endif
}
- return true;
+ return r;
}
int
-donerewrite(changed)
+donerewrite(changed, newRCStime)
int changed;
+ time_t newRCStime;
/*
* Finish rewriting an RCS file if CHANGED is nonzero.
- * Return true on success.
+ * Set its mode if CHANGED is positive.
+ * Set its modification time to NEWRCSTIME unless it is -1.
+ * Return 0 on success, -1 on failure.
*/
{
- int r, e;
+ int r = 0, e = 0;
+# if bad_creat0
+ int lr, le;
+# endif
if (changed && !nerror) {
if (finptr) {
@@ -1627,30 +1886,64 @@ donerewrite(changed)
Izclose(&finptr);
}
if (1 < RCSstat.st_nlink)
- warn("breaking hard link to %s", RCSfilename);
+ rcswarn("breaking hard link");
+ aflush(frewrite);
seteid();
ignoreints();
- r = chnamemod(&frewrite, newRCSfilename, RCSfilename,
- RCSstat.st_mode & ~(S_IWUSR|S_IWGRP|S_IWOTH)
+ r = chnamemod(
+ &frewrite, newRCSname, RCSname, changed,
+ RCSstat.st_mode & (mode_t)~(S_IWUSR|S_IWGRP|S_IWOTH),
+ newRCStime
);
e = errno;
- keepdirtemp(newRCSfilename);
+ keepdirtemp(newRCSname);
+# if bad_creat0
+ lr = un_link(lockname);
+ le = errno;
+ keepdirtemp(lockname);
+# endif
restoreints();
setrid();
if (r != 0) {
- enerror(e, RCSfilename);
- error("saved in %s", newRCSfilename);
- dirtempunlink();
- return false;
+ enerror(e, RCSname);
+ error("saved in %s", newRCSname);
}
+# if bad_creat0
+ if (lr != 0) {
+ enerror(le, lockname);
+ r = -1;
+ }
+# endif
}
- return true;
+ return r;
}
void
-aflush(f)
- FILE *f;
+ORCSclose()
+{
+ if (0 <= fdlock) {
+ if (close(fdlock) != 0)
+ efaterror(lockname);
+ fdlock = -1;
+ }
+ Ozclose(&frewrite);
+}
+
+ void
+ORCSerror()
+/*
+* Like ORCSclose, except we are cleaning up after an interrupt or fatal error.
+* Do not report errors, since this may loop. This is needed only because
+* some brain-damaged hosts (e.g. OS/2) cannot unlink files that are open, and
+* some nearly-Posix hosts (e.g. NFS) work better if the files are closed first.
+* This isn't a completely reliable away to work around brain-damaged hosts,
+* because of the gap between actual file opening and setting frewrite etc.,
+* but it's better than nothing.
+*/
{
- if (fflush(f) != 0)
- Oerror();
+ if (0 <= fdlock)
+ VOID close(fdlock);
+ if (frewrite)
+ /* Avoid fclose, since stdio may not be reentrant. */
+ VOID close(fileno(frewrite));
}
diff --git a/gnu/usr.bin/rcs/lib/rcsfcmp.c b/gnu/usr.bin/rcs/lib/rcsfcmp.c
index 75a6bbc..9adfa17 100644
--- a/gnu/usr.bin/rcs/lib/rcsfcmp.c
+++ b/gnu/usr.bin/rcs/lib/rcsfcmp.c
@@ -1,14 +1,13 @@
-/*
- * RCS file comparison
- */
+/* Compare working files, ignoring RCS keyword strings. */
+
/*****************************************************************************
* rcsfcmp()
* Testprogram: define FCMPTEST
*****************************************************************************
*/
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -24,8 +23,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -37,7 +37,25 @@ Report problems and direct all questions to:
-/* $Log: rcsfcmp.c,v $
+/*
+ * $Log: rcsfcmp.c,v $
+ * Revision 5.14 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.13 1995/06/01 16:23:43 eggert
+ * (rcsfcmp): Add -kb support.
+ *
+ * Revision 5.12 1994/03/17 14:05:48 eggert
+ * Normally calculate the $Log prefix from context, not from RCS file.
+ * Calculate line numbers correctly even if the $Log prefix contains newlines.
+ * Remove lint.
+ *
+ * Revision 5.11 1993/11/03 17:42:27 eggert
+ * Fix yet another off-by-one error when comparing Log string expansions.
+ *
+ * Revision 5.10 1992/07/28 16:12:44 eggert
+ * Statement macro names now end in _.
+ *
* Revision 5.9 1991/10/07 17:32:46 eggert
* Count log lines correctly.
*
@@ -101,8 +119,9 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(fcmpId, "$Id: rcsfcmp.c,v 5.9 1991/10/07 17:32:46 eggert Exp $")
+libId(fcmpId, "$Id: rcsfcmp.c,v 5.14 1995/06/16 06:19:24 eggert Exp $")
+ static int discardkeyval P((int,RILE*));
static int
discardkeyval(c, f)
register int c;
@@ -114,24 +133,24 @@ discardkeyval(c, f)
case '\n':
return c;
default:
- Igeteof(f, c, return EOF;);
+ Igeteof_(f, c, return EOF;)
break;
}
}
int
-rcsfcmp(xfp, xstatp, ufname, delta)
+rcsfcmp(xfp, xstatp, uname, delta)
register RILE *xfp;
struct stat const *xstatp;
- char const *ufname;
+ char const *uname;
struct hshentry const *delta;
-/* Compare the files xfp and ufname. Return zero
- * if xfp has the same contents as ufname and neither has keywords,
+/* Compare the files xfp and uname. Return zero
+ * if xfp has the same contents as uname and neither has keywords,
* otherwise -1 if they are the same ignoring keyword values,
* and 1 if they differ even ignoring
* keyword values. For the LOG-keyword, rcsfcmp skips the log message
* given by the parameter delta in xfp. Thus, rcsfcmp returns nonpositive
- * if xfp contains the same as ufname, with the keywords expanded.
+ * if xfp contains the same as uname, with the keywords expanded.
* Implementation: character-by-character comparison until $ is found.
* If a $ is found, read in the marker keywords; if they are real keywords
* and identical, read in keyword value. If value is terminated properly,
@@ -145,23 +164,24 @@ rcsfcmp(xfp, xstatp, ufname, delta)
register int xeof, ueof;
register char * tp;
register char const *sp;
+ register size_t leaderlen;
int result;
enum markers match1;
struct stat ustat;
- if (!(ufp = Iopen(ufname, FOPEN_R_WORK, &ustat))) {
- efaterror(ufname);
+ if (!(ufp = Iopen(uname, FOPEN_R_WORK, &ustat))) {
+ efaterror(uname);
}
xeof = ueof = false;
- if (Expand==OLD_EXPAND) {
+ if (MIN_UNEXPAND <= Expand) {
if (!(result = xstatp->st_size!=ustat.st_size)) {
-# if has_mmap && large_memory
+# if large_memory && maps_memory
result = !!memcmp(xfp->base,ufp->base,(size_t)xstatp->st_size);
# else
for (;;) {
/* get the next characters */
- Igeteof(xfp, xc, xeof=true;);
- Igeteof(ufp, uc, ueof=true;);
+ Igeteof_(xfp, xc, xeof=true;)
+ Igeteof_(ufp, uc, ueof=true;)
if (xeof | ueof)
goto eof;
if (xc != uc)
@@ -172,21 +192,22 @@ rcsfcmp(xfp, xstatp, ufname, delta)
} else {
xc = 0;
uc = 0; /* Keep lint happy. */
+ leaderlen = 0;
result = 0;
for (;;) {
if (xc != KDELIM) {
/* get the next characters */
- Igeteof(xfp, xc, xeof=true;);
- Igeteof(ufp, uc, ueof=true;);
+ Igeteof_(xfp, xc, xeof=true;)
+ Igeteof_(ufp, uc, ueof=true;)
if (xeof | ueof)
goto eof;
} else {
/* try to get both keywords */
tp = xkeyword;
for (;;) {
- Igeteof(xfp, xc, xeof=true;);
- Igeteof(ufp, uc, ueof=true;);
+ Igeteof_(xfp, xc, xeof=true;)
+ Igeteof_(ufp, uc, ueof=true;)
if (xeof | ueof)
goto eof;
if (xc != uc)
@@ -221,8 +242,8 @@ rcsfcmp(xfp, xstatp, ufname, delta)
}
switch (xc) {
default:
- Igeteof(xfp, xc, xeof=true;);
- Igeteof(ufp, uc, ueof=true;);
+ Igeteof_(xfp, xc, xeof=true;)
+ Igeteof_(ufp, uc, ueof=true;)
if (xeof | ueof)
goto eof;
continue;
@@ -237,38 +258,47 @@ rcsfcmp(xfp, xstatp, ufname, delta)
goto return1;
if (xc==KDELIM) {
/* Skip closing KDELIM. */
- Igeteof(xfp, xc, xeof=true;);
- Igeteof(ufp, uc, ueof=true;);
+ Igeteof_(xfp, xc, xeof=true;)
+ Igeteof_(ufp, uc, ueof=true;)
if (xeof | ueof)
goto eof;
/* if the keyword is LOG, also skip the log message in xfp*/
if (match1==Log) {
/* first, compute the number of line feeds in log msg */
- unsigned lncnt;
+ int lncnt;
size_t ls, ccnt;
sp = delta->log.string;
ls = delta->log.size;
if (ls<sizeof(ciklog)-1 || memcmp(sp,ciklog,sizeof(ciklog)-1)) {
- /* This log message was inserted. */
- lncnt = 3;
- while (ls--) if (*sp++=='\n') lncnt++;
+ /*
+ * This log message was inserted. Skip its header.
+ * The number of newlines to skip is
+ * 1 + (C+1)*(1+L+1), where C is the number of newlines
+ * in the comment leader, and L is the number of
+ * newlines in the log string.
+ */
+ int c1 = 1;
+ for (ccnt=Comment.size; ccnt--; )
+ c1 += Comment.string[ccnt] == '\n';
+ lncnt = 2*c1 + 1;
+ while (ls--) if (*sp++=='\n') lncnt += c1;
for (;;) {
if (xc=='\n')
if(--lncnt==0) break;
- Igeteof(xfp, xc, goto returnresult;);
+ Igeteof_(xfp, xc, goto returnresult;)
}
/* skip last comment leader */
/* Can't just skip another line here, because there may be */
/* additional characters on the line (after the Log....$) */
- for (ccnt=Comment.size; ccnt--; ) {
- Igeteof(xfp, xc, goto returnresult;);
- if(xc=='\n') break;
+ ccnt = RCSversion<VERSION(5) ? Comment.size : leaderlen;
+ do {
+ Igeteof_(xfp, xc, goto returnresult;)
/*
* Read to the end of the comment leader or '\n',
- * whatever comes first. Some editors strip
- * trailing white space from a leader like " * ".
+ * whatever comes first, because the leader's
+ * trailing white space was probably stripped.
*/
- }
+ } while (ccnt-- && (xc!='\n' || --c1));
}
}
} else {
@@ -284,6 +314,10 @@ rcsfcmp(xfp, xstatp, ufname, delta)
}
if (xc != uc)
goto return1;
+ if (xc == '\n')
+ leaderlen = 0;
+ else
+ leaderlen++;
}
}
diff --git a/gnu/usr.bin/rcs/lib/rcsfnms.c b/gnu/usr.bin/rcs/lib/rcsfnms.c
index 02562f0..e3b4f71 100644
--- a/gnu/usr.bin/rcs/lib/rcsfnms.c
+++ b/gnu/usr.bin/rcs/lib/rcsfnms.c
@@ -1,15 +1,14 @@
-/*
- * RCS file name handling
- */
+/* RCS filename and pathname handling */
+
/****************************************************************************
* creation and deletion of /tmp temporaries
- * pairing of RCS file names and working file names.
+ * pairing of RCS pathnames and working pathnames.
* Testprogram: define PAIRTEST
****************************************************************************
*/
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -25,8 +24,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -37,7 +37,45 @@ Report problems and direct all questions to:
-/* $Log: rcsfnms.c,v $
+/*
+ * $Log: rcsfnms.c,v $
+ * Revision 5.16 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.15 1995/06/01 16:23:43 eggert
+ * (basefilename): Renamed from basename to avoid collisions.
+ * (dirlen): Remove (for similar reasons).
+ * (rcsreadopen): Open with FOPEN_RB.
+ * (SLASHSLASH_is_SLASH): Default is 0.
+ * (getcwd): Work around bad_wait_if_SIGCHLD_ignored bug.
+ *
+ * Revision 5.14 1994/03/17 14:05:48 eggert
+ * Strip trailing SLASHes from TMPDIR; some systems need this. Remove lint.
+ *
+ * Revision 5.13 1993/11/03 17:42:27 eggert
+ * Determine whether a file name is too long indirectly,
+ * by examining inode numbers, instead of trying to use operating system
+ * primitives like pathconf, which are not trustworthy in general.
+ * File names may now hold white space or $.
+ * Do not flatten ../X in pathnames; that may yield wrong answer for symlinks.
+ * Add getabsname hook. Improve quality of diagnostics.
+ *
+ * Revision 5.12 1992/07/28 16:12:44 eggert
+ * Add .sty. .pl now implies Perl, not Prolog. Fix fdlock initialization bug.
+ * Check that $PWD is really ".". Be consistent about pathnames vs filenames.
+ *
+ * Revision 5.11 1992/02/17 23:02:25 eggert
+ * `a/RCS/b/c' is now an RCS file with an empty extension, not just `a/b/RCS/c'.
+ *
+ * Revision 5.10 1992/01/24 18:44:19 eggert
+ * Fix bug: Expand and Ignored weren't reinitialized.
+ * Avoid `char const c=ch;' compiler bug.
+ * Add support for bad_creat0.
+ *
+ * Revision 5.9 1992/01/06 02:42:34 eggert
+ * Shorten long (>31 chars) name.
+ * while (E) ; -> while (E) continue;
+ *
* Revision 5.8 1991/09/24 00:28:40 eggert
* Don't export bindex().
*
@@ -66,8 +104,8 @@ Report problems and direct all questions to:
*
* Revision 5.0 1990/08/22 08:12:50 eggert
* Ignore signals when manipulating the semaphore file.
- * Modernize list of file name extensions.
- * Permit paths of arbitrary length. Beware file names beginning with "-".
+ * Modernize list of filename extensions.
+ * Permit paths of arbitrary length. Beware filenames beginning with "-".
* Remove compile-time limits; use malloc instead.
* Permit dates past 1999/12/31. Make lock and temp files faster and safer.
* Ansify and Posixate.
@@ -94,10 +132,10 @@ Report problems and direct all questions to:
* Comment leader '% ' for '*.tex' files added.
*
* Revision 4.3 83/12/15 12:26:48 wft
- * Added check for KDELIM in file names to pairfilenames().
+ * Added check for KDELIM in filenames to pairfilenames().
*
* Revision 4.2 83/12/02 22:47:45 wft
- * Added csh, red, and sl file name suffixes.
+ * Added csh, red, and sl filename suffixes.
*
* Revision 4.1 83/05/11 16:23:39 wft
* Added initialization of Dbranch to InitAdmin(). Canged pairfilenames():
@@ -106,7 +144,7 @@ Report problems and direct all questions to:
* 3. added ignoring of directories.
*
* Revision 3.7 83/05/11 15:01:58 wft
- * Added comtable[] which pairs file name suffixes with comment leaders;
+ * Added comtable[] which pairs filename suffixes with comment leaders;
* updated InitAdmin() accordingly.
*
* Revision 3.6 83/04/05 14:47:36 wft
@@ -121,7 +159,7 @@ Report problems and direct all questions to:
* removed unused variable.
*
* Revision 3.3 82/11/28 20:31:37 wft
- * Changed mktempfile() to store the generated file names.
+ * Changed mktempfile() to store the generated filenames.
* Changed getfullRCSname() to store the file and pathname, and to
* delete leading "../" and "./".
*
@@ -140,72 +178,87 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(fnmsId, "$Id: rcsfnms.c,v 5.8 1991/09/24 00:28:40 eggert Exp $")
+libId(fnmsId, "$Id: rcsfnms.c,v 5.16 1995/06/16 06:19:24 eggert Exp $")
+
+static char const *bindex P((char const*,int));
+static int fin2open P((char const*, size_t, char const*, size_t, char const*, size_t, RILE*(*)P((struct buf*,struct stat*,int)), int));
+static int finopen P((RILE*(*)P((struct buf*,struct stat*,int)), int));
+static int suffix_matches P((char const*,char const*));
+static size_t dir_useful_len P((char const*));
+static size_t suffixlen P((char const*));
+static void InitAdmin P((void));
-char const *RCSfilename;
-char *workfilename;
+char const *RCSname;
+char *workname;
+int fdlock;
FILE *workstdout;
struct stat RCSstat;
char const *suffixes;
static char const rcsdir[] = "RCS";
-#define rcsdirlen (sizeof(rcsdir)-1)
+#define rcslen (sizeof(rcsdir)-1)
static struct buf RCSbuf, RCSb;
static int RCSerrno;
-/* Temp file names to be unlinked when done, if they are not nil. */
+/* Temp names to be unlinked when done, if they are not 0. */
#define TEMPNAMES 5 /* must be at least DIRTEMPNAMES (see rcsedit.c) */
-static char *volatile tfnames[TEMPNAMES];
+static char *volatile tpnames[TEMPNAMES];
struct compair {
char const *suffix, *comlead;
};
+/*
+* This table is present only for backwards compatibility.
+* Normally we ignore this table, and use the prefix of the `$Log' line instead.
+*/
static struct compair const comtable[] = {
-/* comtable pairs each filename suffix with a comment leader. The comment */
-/* leader is placed before each line generated by the $Log keyword. This */
-/* table is used to guess the proper comment leader from the working file's */
-/* suffix during initial ci (see InitAdmin()). Comment leaders are needed */
-/* for languages without multiline comments; for others they are optional. */
- "a", "-- ", /* Ada */
- "ada", "-- ",
- "asm", ";; ", /* assembler (MS-DOS) */
- "bat", ":: ", /* batch (MS-DOS) */
- "c", " * ", /* C */
- "c++", "// ", /* C++ in all its infinite guises */
- "cc", "// ",
- "cpp", "// ",
- "cxx", "// ",
- "cl", ";;; ", /* Common Lisp */
- "cmd", ":: ", /* command (OS/2) */
- "cmf", "c ", /* CM Fortran */
- "cs", " * ", /* C* */
- "el", "; ", /* Emacs Lisp */
- "f", "c ", /* Fortran */
- "for", "c ",
- "h", " * ", /* C-header */
- "hpp", "// ", /* C++ header */
- "hxx", "// ",
- "l", " * ", /* lex NOTE: conflict between lex and franzlisp */
- "lisp",";;; ", /* Lucid Lisp */
- "lsp", ";; ", /* Microsoft Lisp */
- "mac", ";; ", /* macro (DEC-10, MS-DOS, PDP-11, VMS, etc) */
- "me", ".\\\" ",/* me-macros t/nroff*/
- "ml", "; ", /* mocklisp */
- "mm", ".\\\" ",/* mm-macros t/nroff*/
- "ms", ".\\\" ",/* ms-macros t/nroff*/
- "p", " * ", /* Pascal */
- "pas", " * ",
- "pl", "% ", /* Prolog */
- "tex", "% ", /* TeX */
- "y", " * ", /* yacc */
- nil, "# " /* default for unknown suffix; must always be last */
+ { "a" , "-- " }, /* Ada */
+ { "ada" , "-- " },
+ { "adb" , "-- " },
+ { "ads" , "-- " },
+ { "asm" , ";; " }, /* assembler (MS-DOS) */
+ { "bat" , ":: " }, /* batch (MS-DOS) */
+ { "body", "-- " }, /* Ada */
+ { "c" , " * " }, /* C */
+ { "c++" , "// " }, /* C++ in all its infinite guises */
+ { "cc" , "// " },
+ { "cpp" , "// " },
+ { "cxx" , "// " },
+ { "cl" , ";;; "}, /* Common Lisp */
+ { "cmd" , ":: " }, /* command (OS/2) */
+ { "cmf" , "c " }, /* CM Fortran */
+ { "cs" , " * " }, /* C* */
+ { "el" , "; " }, /* Emacs Lisp */
+ { "f" , "c " }, /* Fortran */
+ { "for" , "c " },
+ { "h" , " * " }, /* C-header */
+ { "hpp" , "// " }, /* C++ header */
+ { "hxx" , "// " },
+ { "l" , " * " }, /* lex (NOTE: franzlisp disagrees) */
+ { "lisp", ";;; "}, /* Lucid Lisp */
+ { "lsp" , ";; " }, /* Microsoft Lisp */
+ { "m" , "// " }, /* Objective C */
+ { "mac" , ";; " }, /* macro (DEC-10, MS-DOS, PDP-11, VMS, etc) */
+ { "me" , ".\\\" "}, /* troff -me */
+ { "ml" , "; " }, /* mocklisp */
+ { "mm" , ".\\\" "}, /* troff -mm */
+ { "ms" , ".\\\" "}, /* troff -ms */
+ { "p" , " * " }, /* Pascal */
+ { "pas" , " * " },
+ { "ps" , "% " }, /* PostScript */
+ { "spec", "-- " }, /* Ada */
+ { "sty" , "% " }, /* LaTeX style */
+ { "tex" , "% " }, /* TeX */
+ { "y" , " * " }, /* yacc */
+ { 0 , "# " } /* default for unknown suffix; must be last */
};
#if has_mktemp
+ static char const *tmp P((void));
static char const *
tmp()
/* Yield the name of the tmp directory. */
@@ -224,14 +277,14 @@ tmp()
char const *
maketemp(n)
int n;
-/* Create a unique filename using n and the process id and store it
- * into the nth slot in tfnames.
- * Because of storage in tfnames, tempunlink() can unlink the file later.
- * Returns a pointer to the filename created.
+/* Create a unique pathname using n and the process id and store it
+ * into the nth slot in tpnames.
+ * Because of storage in tpnames, tempunlink() can unlink the file later.
+ * Return a pointer to the pathname created.
*/
{
char *p;
- char const *t = tfnames[n];
+ char const *t = tpnames[n];
if (t)
return t;
@@ -240,25 +293,26 @@ maketemp(n)
{
# if has_mktemp
char const *tp = tmp();
- p = testalloc(strlen(tp) + 10);
- VOID sprintf(p, "%s%cT%cXXXXXX", tp, SLASH, '0'+n);
+ size_t tplen = dir_useful_len(tp);
+ p = testalloc(tplen + 10);
+ VOID sprintf(p, "%.*s%cT%cXXXXXX", (int)tplen, tp, SLASH, '0'+n);
if (!mktemp(p) || !*p)
- faterror("can't make temporary file name `%s%cT%cXXXXXX'",
- tp, SLASH, '0'+n
+ faterror("can't make temporary pathname `%.*s%cT%cXXXXXX'",
+ (int)tplen, tp, SLASH, '0'+n
);
# else
- static char tfnamebuf[TEMPNAMES][L_tmpnam];
- p = tfnamebuf[n];
+ static char tpnamebuf[TEMPNAMES][L_tmpnam];
+ p = tpnamebuf[n];
if (!tmpnam(p) || !*p)
# ifdef P_tmpdir
- faterror("can't make temporary file name `%s...'",P_tmpdir);
+ faterror("can't make temporary pathname `%s...'",P_tmpdir);
# else
- faterror("can't make temporary file name");
+ faterror("can't make temporary pathname");
# endif
# endif
}
- tfnames[n] = p;
+ tpnames[n] = p;
return p;
}
@@ -271,28 +325,28 @@ tempunlink()
register char *p;
for (i = TEMPNAMES; 0 <= --i; )
- if ((p = tfnames[i])) {
+ if ((p = tpnames[i])) {
VOID unlink(p);
/*
* We would tfree(p) here,
* but this might dump core if we're handing a signal.
* We're about to exit anyway, so we won't bother.
*/
- tfnames[i] = 0;
+ tpnames[i] = 0;
}
}
static char const *
-bindex(sp,ch)
+bindex(sp, c)
register char const *sp;
- int ch;
+ register int c;
/* Function: Finds the last occurrence of character c in string sp
* and returns a pointer to the character just beyond it. If the
* character doesn't occur in the string, sp is returned.
*/
{
- register char const c=ch, *r;
+ register char const *r;
r = sp;
while (*sp) {
if (*sp++ == c) r=sp;
@@ -333,64 +387,22 @@ InitAdmin()
register char const *Suffix;
register int i;
- Head=nil; Dbranch=nil; AccessList=nil; Symbols=nil; Locks=nil;
+ Head=0; Dbranch=0; AccessList=0; Symbols=0; Locks=0;
StrictLocks=STRICT_LOCKING;
/* guess the comment leader from the suffix*/
- Suffix=bindex(workfilename, '.');
- if (Suffix==workfilename) Suffix= ""; /* empty suffix; will get default*/
+ Suffix = bindex(workname, '.');
+ if (Suffix==workname) Suffix= ""; /* empty suffix; will get default*/
for (i=0; !suffix_matches(Suffix,comtable[i].suffix); i++)
- ;
+ continue;
Comment.string = comtable[i].comlead;
Comment.size = strlen(comtable[i].comlead);
+ Expand = KEYVAL_EXPAND;
+ clear_buf(&Ignored);
Lexinit(); /* note: if !finptr, reads nothing; only initializes */
}
-/* 'cpp' does not like this line. It seems to be the leading '_' in the */
-/* second occurence of '_POSIX_NO_TRUNC'. It evaluates correctly with */
-/* just the first term so lets just do that for now. */
-/*#if defined(_POSIX_NO_TRUNC) && _POSIX_NO_TRUNC!=-1*/
-#if defined(_POSIX_NO_TRUNC)
-# define LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED 0
-#else
-# define LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED 1
-#endif
-
-#if LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED
-#ifdef NAME_MAX
-# define filenametoolong(path) (NAME_MAX < strlen(basename(path)))
-#else
- static int
-filenametoolong(path)
- char *path;
-/* Yield true if the last file name in PATH is too long. */
-{
- static unsigned long dot_namemax;
-
- register size_t namelen;
- register char *base;
- register unsigned long namemax;
-
- base = path + dirlen(path);
- namelen = strlen(base);
- if (namelen <= _POSIX_NAME_MAX) /* fast check for shorties */
- return false;
- if (base != path) {
- *--base = 0;
- namemax = pathconf(path, _PC_NAME_MAX);
- *base = SLASH;
- } else {
- /* Cache the results for the working directory, for speed. */
- if (!dot_namemax)
- dot_namemax = pathconf(".", _PC_NAME_MAX);
- namemax = dot_namemax;
- }
- /* If pathconf() yielded -1, namemax is now ULONG_MAX. */
- return namemax<namelen;
-}
-#endif
-#endif
void
bufalloc(b, size)
@@ -422,7 +434,7 @@ bufrealloc(b, size)
bufalloc(b, size);
else {
while ((b->size <<= 1) < size)
- ;
+ continue;
b->string = trealloc(char, b->string, b->size);
}
}
@@ -495,7 +507,7 @@ bufscpy(b, s)
char const *
-basename(p)
+basefilename(p)
char const *p;
/* Yield the address of the base filename of the pathname P. */
{
@@ -507,19 +519,11 @@ basename(p)
}
}
- size_t
-dirlen(p)
- char const *p;
-/* Yield the length of P's directory, including its trailing SLASH. */
-{
- return basename(p) - p;
-}
-
static size_t
suffixlen(x)
char const *x;
-/* Yield the length of X, an RCS filename suffix. */
+/* Yield the length of X, an RCS pathname suffix. */
{
register char const *p;
@@ -538,10 +542,10 @@ suffixlen(x)
char const *
rcssuffix(name)
char const *name;
-/* Yield the suffix of NAME if it is an RCS filename, 0 otherwise. */
+/* Yield the suffix of NAME if it is an RCS pathname, 0 otherwise. */
{
char const *x, *p, *nz;
- size_t dl, nl, xl;
+ size_t nl, xl;
nl = strlen(name);
nz = name + nl;
@@ -550,30 +554,29 @@ rcssuffix(name)
if ((xl = suffixlen(x))) {
if (xl <= nl && memcmp(p = nz-xl, x, xl) == 0)
return p;
- } else {
- dl = dirlen(name);
- if (
- rcsdirlen < dl &&
- !memcmp(p = name+(dl-=rcsdirlen+1), rcsdir, rcsdirlen) &&
- (!dl || isSLASH(*--p))
- )
- return nz;
- }
+ } else
+ for (p = name; p < nz - rcslen; p++)
+ if (
+ isSLASH(p[rcslen])
+ && (p==name || isSLASH(p[-1]))
+ && memcmp(p, rcsdir, rcslen) == 0
+ )
+ return nz;
x += xl;
} while (*x++);
return 0;
}
/*ARGSUSED*/ RILE *
-rcsreadopen(RCSname, status, mustread)
- struct buf *RCSname;
+rcsreadopen(RCSpath, status, mustread)
+ struct buf *RCSpath;
struct stat *status;
int mustread;
-/* Open RCSNAME for reading and yield its FILE* descriptor.
+/* Open RCSPATH for reading and yield its FILE* descriptor.
* If successful, set *STATUS to its status.
- * Pass this routine to pairfilenames() for read-only access to the file. */
+ * Pass this routine to pairnames() for read-only access to the file. */
{
- return Iopen(RCSname->string, FOPEN_R, status);
+ return Iopen(RCSpath->string, FOPEN_RB, status);
}
static int
@@ -594,7 +597,7 @@ finopen(rcsopen, mustread)
* We prefer an old name to that of a nonexisting new RCS file,
* unless we tried locking the old name and failed.
*/
- preferold = RCSbuf.string[0] && (mustread||frewrite);
+ preferold = RCSbuf.string[0] && (mustread||0<=fdlock);
finptr = (*rcsopen)(&RCSb, &RCSstat, mustread);
interesting = finptr || errno!=ENOENT;
@@ -615,7 +618,7 @@ fin2open(d, dlen, base, baselen, x, xlen, rcsopen, mustread)
/*
* D is a directory name with length DLEN (including trailing slash).
* BASE is a filename with length BASELEN.
- * X is an RCS filename suffix with length XLEN.
+ * X is an RCS pathname suffix with length XLEN.
* Use RCSOPEN to open an RCS file; MUSTREAD is set if the file must be read.
* Yield true if successful.
* Try dRCS/basex first; if that fails and x is nonempty, try dbasex.
@@ -626,12 +629,12 @@ fin2open(d, dlen, base, baselen, x, xlen, rcsopen, mustread)
{
register char *p;
- bufalloc(&RCSb, dlen + rcsdirlen + 1 + baselen + xlen + 1);
+ bufalloc(&RCSb, dlen + rcslen + 1 + baselen + xlen + 1);
/* Try dRCS/basex. */
VOID memcpy(p = RCSb.string, d, dlen);
- VOID memcpy(p += dlen, rcsdir, rcsdirlen);
- p += rcsdirlen;
+ VOID memcpy(p += dlen, rcsdir, rcslen);
+ p += rcslen;
*p++ = SLASH;
VOID memcpy(p, base, baselen);
VOID memcpy(p += baselen, x, xlen);
@@ -651,16 +654,17 @@ fin2open(d, dlen, base, baselen, x, xlen, rcsopen, mustread)
}
int
-pairfilenames(argc, argv, rcsopen, mustread, quiet)
+pairnames(argc, argv, rcsopen, mustread, quiet)
int argc;
char **argv;
RILE *(*rcsopen)P((struct buf*,struct stat*,int));
int mustread, quiet;
-/* Function: Pairs the filenames pointed to by argv; argc indicates
+/*
+ * Pair the pathnames pointed to by argv; argc indicates
* how many there are.
- * Places a pointer to the RCS filename into RCSfilename,
- * and a pointer to the name of the working file into workfilename.
- * If both the workfilename and the RCS filename are given, and workstdout
+ * Place a pointer to the RCS pathname into RCSname,
+ * and a pointer to the pathname of the working file into workname.
+ * If both are given, and workstdout
* is set, a warning is printed.
*
* If the RCS file exists, places its status into RCSstat.
@@ -677,80 +681,62 @@ pairfilenames(argc, argv, rcsopen, mustread, quiet)
static struct buf tempbuf;
register char *p, *arg, *RCS1;
- char const *purefname, *pureRCSname, *x;
+ char const *base, *RCSbase, *x;
int paired;
size_t arglen, dlen, baselen, xlen;
- if (!(arg = *argv)) return 0; /* already paired filename */
+ fdlock = -1;
+
+ if (!(arg = *argv)) return 0; /* already paired pathname */
if (*arg == '-') {
- error("%s option is ignored after file names", arg);
+ error("%s option is ignored after pathnames", arg);
return 0;
}
- purefname = basename(arg);
-
- /* Allocate buffer temporary to hold the default paired file name. */
- p = arg;
- for (;;) {
- switch (*p++) {
- /* Beware characters that cause havoc with ci -k. */
- case KDELIM:
- error("RCS file name `%s' contains %c", arg, KDELIM);
- return 0;
- case ' ': case '\n': case '\t':
- error("RCS file name `%s' contains white space", arg);
- return 0;
- default:
- continue;
- case 0:
- break;
- }
- break;
- }
-
+ base = basefilename(arg);
paired = false;
/* first check suffix to see whether it is an RCS file or not */
if ((x = rcssuffix(arg)))
{
- /* RCS file name given*/
+ /* RCS pathname given */
RCS1 = arg;
- pureRCSname = purefname;
- baselen = x - purefname;
+ RCSbase = base;
+ baselen = x - base;
if (
1 < argc &&
- !rcssuffix(workfilename = p = argv[1]) &&
+ !rcssuffix(workname = p = argv[1]) &&
baselen <= (arglen = strlen(p)) &&
- ((p+=arglen-baselen) == workfilename || isSLASH(p[-1])) &&
- memcmp(purefname, p, baselen) == 0
+ ((p+=arglen-baselen) == workname || isSLASH(p[-1])) &&
+ memcmp(base, p, baselen) == 0
) {
argv[1] = 0;
paired = true;
} else {
- bufscpy(&tempbuf, purefname);
- workfilename = p = tempbuf.string;
+ bufscpy(&tempbuf, base);
+ workname = p = tempbuf.string;
p[baselen] = 0;
}
} else {
/* working file given; now try to find RCS file */
- workfilename = arg;
- baselen = p - purefname - 1;
- /* derive RCS file name*/
+ workname = arg;
+ baselen = strlen(base);
+ /* Derive RCS pathname. */
if (
1 < argc &&
(x = rcssuffix(RCS1 = argv[1])) &&
baselen <= x - RCS1 &&
- ((pureRCSname=x-baselen)==RCS1 || isSLASH(pureRCSname[-1])) &&
- memcmp(purefname, pureRCSname, baselen) == 0
+ ((RCSbase=x-baselen)==RCS1 || isSLASH(RCSbase[-1])) &&
+ memcmp(base, RCSbase, baselen) == 0
) {
argv[1] = 0;
paired = true;
} else
- pureRCSname = RCS1 = 0;
+ RCSbase = RCS1 = 0;
}
- /* now we have a (tentative) RCS filename in RCS1 and workfilename */
+ /* Now we have a (tentative) RCS pathname in RCS1 and workname. */
/* Second, try to find the right RCS file */
- if (pureRCSname!=RCS1) {
+ if (RCSbase!=RCS1) {
/* a path for RCSfile is given; single RCS file to look for */
bufscpy(&RCSbuf, RCS1);
finptr = (*rcsopen)(&RCSbuf, &RCSstat, mustread);
@@ -758,16 +744,16 @@ pairfilenames(argc, argv, rcsopen, mustread, quiet)
} else {
bufscpy(&RCSbuf, "");
if (RCS1)
- /* RCS file name was given without path. */
- VOID fin2open(arg, (size_t)0, pureRCSname, baselen,
+ /* RCS filename was given without path. */
+ VOID fin2open(arg, (size_t)0, RCSbase, baselen,
x, strlen(x), rcsopen, mustread
);
else {
- /* No RCS file name was given. */
+ /* No RCS pathname was given. */
/* Try each suffix in turn. */
- dlen = purefname-arg;
+ dlen = base-arg;
x = suffixes;
- while (! fin2open(arg, dlen, purefname, baselen,
+ while (! fin2open(arg, dlen, base, baselen,
x, xlen=suffixlen(x), rcsopen, mustread
)) {
x += xlen;
@@ -776,7 +762,7 @@ pairfilenames(argc, argv, rcsopen, mustread, quiet)
}
}
}
- RCSfilename = p = RCSbuf.string;
+ RCSname = p = RCSbuf.string;
if (finptr) {
if (!S_ISREG(RCSstat.st_mode)) {
error("%s isn't a regular file -- ignored", p);
@@ -784,7 +770,7 @@ pairfilenames(argc, argv, rcsopen, mustread, quiet)
}
Lexinit(); getadmin();
} else {
- if (RCSerrno!=ENOENT || mustread || !frewrite) {
+ if (RCSerrno!=ENOENT || mustread || fdlock<0) {
if (RCSerrno == EEXIST)
error("RCS file %s is in use", p);
else if (!quiet || RCSerrno!=ENOENT)
@@ -793,25 +779,9 @@ pairfilenames(argc, argv, rcsopen, mustread, quiet)
}
InitAdmin();
};
-# if LONG_NAMES_MAY_BE_SILENTLY_TRUNCATED
- if (filenametoolong(p)) {
- error("RCS file name %s is too long", p);
- return 0;
- }
-# ifndef NAME_MAX
- /*
- * Check workfilename too, even though it cannot be longer,
- * because it may reside on a different filesystem.
- */
- if (filenametoolong(workfilename)) {
- error("working file name %s is too long", workfilename);
- return 0;
- }
-# endif
-# endif
if (paired && workstdout)
- warn("Option -p is set; ignoring output file %s",workfilename);
+ workwarn("Working file ignored due to -p option");
prevkeys = false;
return finptr ? 1 : -1;
@@ -820,83 +790,106 @@ pairfilenames(argc, argv, rcsopen, mustread, quiet)
char const *
getfullRCSname()
-/* Function: returns a pointer to the full path name of the RCS file.
- * Gets the working directory's name at most once.
- * Removes leading "../" and "./".
+/*
+ * Return a pointer to the full pathname of the RCS file.
+ * Remove leading `./'.
*/
{
- static char const *wdptr;
- static struct buf rcsbuf, wdbuf;
- static size_t pathlength;
-
- register char const *realname;
- register size_t parentdirlength;
- register unsigned dotdotcounter;
- register char *d;
- register char const *wd;
-
- if (ROOTPATH(RCSfilename)) {
- return(RCSfilename);
- } else {
+ if (ROOTPATH(RCSname)) {
+ return RCSname;
+ } else {
+ static struct buf rcsbuf;
+# if needs_getabsname
+ bufalloc(&rcsbuf, SIZEABLE_PATH + 1);
+ while (getabsname(RCSname, rcsbuf.string, rcsbuf.size) != 0)
+ if (errno == ERANGE)
+ bufalloc(&rcsbuf, rcsbuf.size<<1);
+ else
+ efaterror("getabsname");
+# else
+ static char const *wdptr;
+ static struct buf wdbuf;
+ static size_t wdlen;
+
+ register char const *r;
+ register size_t dlen;
+ register char *d;
+ register char const *wd;
+
if (!(wd = wdptr)) {
/* Get working directory for the first time. */
- if (!(d = cgetenv("PWD"))) {
+ char *PWD = cgetenv("PWD");
+ struct stat PWDstat, dotstat;
+ if (! (
+ (d = PWD) &&
+ ROOTPATH(PWD) &&
+ stat(PWD, &PWDstat) == 0 &&
+ stat(".", &dotstat) == 0 &&
+ same_file(PWDstat, dotstat, 1)
+ )) {
bufalloc(&wdbuf, SIZEABLE_PATH + 1);
-# if !has_getcwd && has_getwd
- d = getwd(wdbuf.string);
+# if has_getcwd || !has_getwd
+ while (!(d = getcwd(wdbuf.string, wdbuf.size)))
+ if (errno == ERANGE)
+ bufalloc(&wdbuf, wdbuf.size<<1);
+ else if ((d = PWD))
+ break;
+ else
+ efaterror("getcwd");
# else
- while (
- !(d = getcwd(wdbuf.string, wdbuf.size))
- && errno==ERANGE
- )
- bufalloc(&wdbuf, wdbuf.size<<1);
+ d = getwd(wdbuf.string);
+ if (!d && !(d = PWD))
+ efaterror("getwd");
# endif
- if (!d)
- efaterror("working directory");
}
- parentdirlength = strlen(d);
- while (parentdirlength && isSLASH(d[parentdirlength-1])) {
- d[--parentdirlength] = 0;
- /* Check needed because some getwd implementations */
- /* generate "/" for the root. */
- }
+ wdlen = dir_useful_len(d);
+ d[wdlen] = 0;
wdptr = wd = d;
- pathlength = parentdirlength;
- }
- /*the following must be redone since RCSfilename may change*/
- /* Find how many `../'s to remove from RCSfilename. */
- dotdotcounter =0;
- realname = RCSfilename;
- while (realname[0]=='.') {
- if (isSLASH(realname[1])) {
- /* drop leading ./ */
- realname += 2;
- } else if (realname[1]=='.' && isSLASH(realname[2])) {
- /* drop leading ../ and remember */
- dotdotcounter++;
- realname += 3;
- } else
- break;
}
- /* Now remove dotdotcounter trailing directories from wd. */
- parentdirlength = pathlength;
- while (dotdotcounter && parentdirlength) {
- /* move pointer backwards over trailing directory */
- if (isSLASH(wd[--parentdirlength])) {
- dotdotcounter--;
- }
- }
- /* build full path name */
- bufalloc(&rcsbuf, parentdirlength+strlen(realname)+2);
+ /*
+ * Remove leading `./'s from RCSname.
+ * Do not try to handle `../', since removing it may yield
+ * the wrong answer in the presence of symbolic links.
+ */
+ for (r = RCSname; r[0]=='.' && isSLASH(r[1]); r += 2)
+ /* `.////' is equivalent to `./'. */
+ while (isSLASH(r[2]))
+ r++;
+ /* Build full pathname. */
+ dlen = wdlen;
+ bufalloc(&rcsbuf, dlen + strlen(r) + 2);
d = rcsbuf.string;
- VOID memcpy(d, wd, parentdirlength);
- d += parentdirlength;
+ VOID memcpy(d, wd, dlen);
+ d += dlen;
*d++ = SLASH;
- VOID strcpy(d, realname);
- return rcsbuf.string;
+ VOID strcpy(d, r);
+# endif
+ return rcsbuf.string;
}
}
+ static size_t
+dir_useful_len(d)
+ char const *d;
+/*
+* D names a directory; yield the number of characters of D's useful part.
+* To create a file in D, append a SLASH and a file name to D's useful part.
+* Ignore trailing slashes if possible; not only are they ugly,
+* but some non-Posix systems misbehave unless the slashes are omitted.
+*/
+{
+# ifndef SLASHSLASH_is_SLASH
+# define SLASHSLASH_is_SLASH 0
+# endif
+ size_t dlen = strlen(d);
+ if (!SLASHSLASH_is_SLASH && dlen==2 && isSLASH(d[0]) && isSLASH(d[1]))
+ --dlen;
+ else
+ while (dlen && isSLASH(d[dlen-1]))
+ --dlen;
+ return dlen;
+}
+
#ifndef isSLASH
int
isSLASH(c)
@@ -927,9 +920,6 @@ getcwd(path, size)
register char *p, *lim;
int closeerrno, closeerror, e, fd[2], readerror, toolong, wstatus;
pid_t child;
-# if !has_waitpid
- pid_t w;
-# endif
if (!size) {
errno = EINVAL;
@@ -937,6 +927,12 @@ getcwd(path, size)
}
if (pipe(fd) != 0)
return 0;
+# if bad_wait_if_SIGCHLD_ignored
+# ifndef SIGCHLD
+# define SIGCHLD SIGCLD
+# endif
+ VOID signal(SIGCHLD, SIG_DFL);
+# endif
if (!(child = vfork())) {
if (
close(fd[0]) == 0 &&
@@ -988,12 +984,15 @@ getcwd(path, size)
if (waitpid(child, &wstatus, 0) < 0)
wstatus = 1;
# else
- do {
- if ((w = wait(&wstatus)) < 0) {
- wstatus = 1;
- break;
- }
- } while (w != child);
+ {
+ pid_t w;
+ do {
+ if ((w = wait(&wstatus)) < 0) {
+ wstatus = 1;
+ break;
+ }
+ } while (w != child);
+ }
# endif
}
if (!fp) {
@@ -1026,7 +1025,7 @@ getcwd(path, size)
#ifdef PAIRTEST
-/* test program for pairfilenames() and getfullRCSname() */
+/* test program for pairnames() and getfullRCSname() */
char const cmdid[] = "pair";
@@ -1052,20 +1051,20 @@ int argc; char *argv[];
}
do {
- RCSfilename=workfilename=nil;
- result = pairfilenames(argc,argv,rcsreadopen,!initflag,quietflag);
+ RCSname = workname = 0;
+ result = pairnames(argc,argv,rcsreadopen,!initflag,quietflag);
if (result!=0) {
- diagnose("RCS file: %s; working file: %s\nFull RCS file name: %s\n",
- RCSfilename,workfilename,getfullRCSname()
+ diagnose("RCS pathname: %s; working pathname: %s\nFull RCS pathname: %s\n",
+ RCSname, workname, getfullRCSname()
);
}
switch (result) {
case 0: continue; /* already paired file */
case 1: if (initflag) {
- error("RCS file %s exists already",RCSfilename);
+ rcserror("already exists");
} else {
- diagnose("RCS file %s exists\n",RCSfilename);
+ diagnose("RCS file %s exists\n", RCSname);
}
Ifclose(finptr);
break;
@@ -1078,7 +1077,7 @@ int argc; char *argv[];
}
- exiting void
+ void
exiterr()
{
dirtempunlink();
diff --git a/gnu/usr.bin/rcs/lib/rcsgen.c b/gnu/usr.bin/rcs/lib/rcsgen.c
index 9a6072e..a87257e 100644
--- a/gnu/usr.bin/rcs/lib/rcsgen.c
+++ b/gnu/usr.bin/rcs/lib/rcsgen.c
@@ -1,9 +1,7 @@
-/*
- * RCS revision generation
- */
+/* Generate RCS revisions. */
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -19,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -28,9 +27,29 @@ Report problems and direct all questions to:
*/
-
-
-/* $Log: rcsgen.c,v $
+/*
+ * $Log: rcsgen.c,v $
+ * Revision 5.16 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.15 1995/06/01 16:23:43 eggert
+ * (putadmin): Open RCS file with FOPEN_WB.
+ *
+ * Revision 5.14 1994/03/17 14:05:48 eggert
+ * Work around SVR4 stdio performance bug.
+ * Flush stderr after prompt. Remove lint.
+ *
+ * Revision 5.13 1993/11/03 17:42:27 eggert
+ * Don't discard ignored phrases. Improve quality of diagnostics.
+ *
+ * Revision 5.12 1992/07/28 16:12:44 eggert
+ * Statement macro names now end in _.
+ * Be consistent about pathnames vs filenames.
+ *
+ * Revision 5.11 1992/01/24 18:44:19 eggert
+ * Move put routines here from rcssyn.c.
+ * Add support for bad_creat0.
+ *
* Revision 5.10 1991/10/07 17:32:46 eggert
* Fix log bugs, e.g. ci -t/dev/null when has_mmap.
*
@@ -122,12 +141,14 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(genId, "$Id: rcsgen.c,v 5.10 1991/10/07 17:32:46 eggert Exp $")
+libId(genId, "$Id: rcsgen.c,v 5.16 1995/06/16 06:19:24 eggert Exp $")
int interactiveflag; /* Should we act as if stdin is a tty? */
struct buf curlogbuf; /* buffer for current log message */
enum stringwork { enter, copy, edit, expand, edit_expand };
+
+static void putdelta P((struct hshentry const*,FILE*));
static void scandeltatext P((struct hshentry*,enum stringwork,int));
@@ -145,11 +166,11 @@ buildrevision(deltas, target, outfile, expandflag)
* otherwise written into a temporary file.
* Temporary files are allocated by maketemp().
* if expandflag is set, keyword expansion is performed.
- * Return nil if outfile is set, the name of the temporary file otherwise.
+ * Return 0 if outfile is set, the name of the temporary file otherwise.
*
* Algorithm: Copy initial revision unchanged. Then edit all revisions but
- * the last one into it, alternating input and output files (resultfile and
- * editfile). The last revision is then edited in, performing simultaneous
+ * the last one into it, alternating input and output files (resultname and
+ * editname). The last revision is then edited in, performing simultaneous
* keyword substitution (this saves one extra pass).
* All this simplifies if only one revision needs to be generated,
* or no keyword expansion is necessary, or if output goes to stdout.
@@ -163,7 +184,7 @@ buildrevision(deltas, target, outfile, expandflag)
return 0;
else {
Ozclose(&fcopy);
- return(resultfile);
+ return resultname;
}
} else {
/* several revisions to generate */
@@ -175,17 +196,17 @@ buildrevision(deltas, target, outfile, expandflag)
}
if (expandflag || outfile) {
/* first, get to beginning of file*/
- finishedit((struct hshentry *)nil, outfile, false);
+ finishedit((struct hshentry*)0, outfile, false);
}
- scandeltatext(deltas->first, expandflag?edit_expand:edit, true);
+ scandeltatext(target, expandflag?edit_expand:edit, true);
finishedit(
- expandflag ? deltas->first : (struct hshentry*)nil,
+ expandflag ? target : (struct hshentry*)0,
outfile, true
);
if (outfile)
return 0;
Ozclose(&fcopy);
- return resultfile;
+ return resultname;
}
}
@@ -193,12 +214,13 @@ buildrevision(deltas, target, outfile, expandflag)
static void
scandeltatext(delta, func, needlog)
- struct hshentry * delta;
+ struct hshentry *delta;
enum stringwork func;
int needlog;
/* Function: Scans delta text nodes up to and including the one given
* by delta. For the one given by delta, the log message is saved into
* delta->log if needlog is set; func specifies how to handle the text.
+ * Similarly, if needlog, delta->igtext is set to the ignored phrases.
* Assumes the initial lexeme must be read in first.
* Does not advance nexttok after it is finished.
*/
@@ -217,11 +239,11 @@ scandeltatext(delta, func, needlog)
if (needlog && delta==nextdelta) {
cb = savestring(&curlogbuf);
delta->log = cleanlogmsg(curlogbuf.string, cb.size);
+ nextlex();
+ delta->igtext = getphrases(Ktext);
} else {readstring();
+ ignorephrases(Ktext);
}
- nextlex();
- while (nexttok==ID && strcmp(NextString,Ktext)!=0)
- ignorephrase();
getkeystring(Ktext);
if (delta==nextdelta)
@@ -233,7 +255,7 @@ scandeltatext(delta, func, needlog)
case enter: enterstring(); break;
case copy: copystring(); break;
case expand: xpandstring(delta); break;
- case edit: editstring((struct hshentry *)nil); break;
+ case edit: editstring((struct hshentry *)0); break;
case edit_expand: editstring(delta); break;
}
}
@@ -284,7 +306,7 @@ getcstdin()
if (feof(in) && ttystdin())
clearerr(in);
c = getc(in);
- if (c < 0) {
+ if (c == EOF) {
testIerror(in);
if (feof(in) && ttystdin())
afputc('\n',stderr);
@@ -327,9 +349,9 @@ putdesc(textflag, textfile)
char *textfile;
/* Function: puts the descriptive text into file frewrite.
* if finptr && !textflag, the text is copied from the old description.
- * Otherwise, if the textfile!=nil, the text is read from that
- * file, or from stdin, if textfile==nil.
- * A textfile with a leading '-' is treated as a string, not a file name.
+ * Otherwise, if textfile, the text is read from that
+ * file, or from stdin, if !textfile.
+ * A textfile with a leading '-' is treated as a string, not a pathname.
* If finptr, the old descriptive text is discarded.
* Always clears foutptr.
*/
@@ -369,13 +391,13 @@ putdesc(textflag, textfile)
p = textfile + 1;
s = strlen(p);
} else {
- if (!(txt = fopen(textfile, "r")))
+ if (!(txt = fopenSafer(textfile, "r")))
efaterror(textfile);
bufalloc(&desc, 1);
p = desc.string;
plim = p + desc.size;
for (;;) {
- if ((c=getc(txt)) < 0) {
+ if ((c=getc(txt)) == EOF) {
testIerror(txt);
if (feof(txt))
break;
@@ -392,7 +414,7 @@ putdesc(textflag, textfile)
desclean = cleanlogmsg(p, s);
}
putstring(frew, false, desclean, true);
- aputc('\n', frew);
+ aputc_('\n', frew)
}
}
@@ -406,13 +428,14 @@ getsstdin(option, name, note, buf)
register size_t i;
register int tty = ttystdin();
- if (tty)
+ if (tty) {
aprintf(stderr,
"enter %s, terminated with single '.' or end of file:\n%s>> ",
name, note
);
- else if (feof(stdin))
- faterror("can't reread redirected stdin for %s; use -%s<%s>",
+ eflush();
+ } else if (feof(stdin))
+ rcsfaterror("can't reread redirected stdin for %s; use -%s<%s>",
name, option, name
);
@@ -426,7 +449,234 @@ getsstdin(option, name, note, buf)
/* Remove trailing '.'. */
--i;
break;
- } else if (tty)
+ } else if (tty) {
aputs(">> ", stderr);
+ eflush();
+ }
return cleanlogmsg(p, i);
}
+
+
+ void
+putadmin()
+/* Output the admin node. */
+{
+ register FILE *fout;
+ struct assoc const *curassoc;
+ struct rcslock const *curlock;
+ struct access const *curaccess;
+
+ if (!(fout = frewrite)) {
+# if bad_creat0
+ ORCSclose();
+ fout = fopenSafer(makedirtemp(0), FOPEN_WB);
+# else
+ int fo = fdlock;
+ fdlock = -1;
+ fout = fdopen(fo, FOPEN_WB);
+# endif
+
+ if (!(frewrite = fout))
+ efaterror(RCSname);
+ }
+
+ /*
+ * Output the first character with putc, not printf.
+ * Otherwise, an SVR4 stdio bug buffers output inefficiently.
+ */
+ aputc_(*Khead, fout)
+ aprintf(fout, "%s\t%s;\n", Khead + 1, Head?Head->num:"");
+ if (Dbranch && VERSION(4)<=RCSversion)
+ aprintf(fout, "%s\t%s;\n", Kbranch, Dbranch);
+
+ aputs(Kaccess, fout);
+ curaccess = AccessList;
+ while (curaccess) {
+ aprintf(fout, "\n\t%s", curaccess->login);
+ curaccess = curaccess->nextaccess;
+ }
+ aprintf(fout, ";\n%s", Ksymbols);
+ curassoc = Symbols;
+ while (curassoc) {
+ aprintf(fout, "\n\t%s:%s", curassoc->symbol, curassoc->num);
+ curassoc = curassoc->nextassoc;
+ }
+ aprintf(fout, ";\n%s", Klocks);
+ curlock = Locks;
+ while (curlock) {
+ aprintf(fout, "\n\t%s:%s", curlock->login, curlock->delta->num);
+ curlock = curlock->nextlock;
+ }
+ if (StrictLocks) aprintf(fout, "; %s", Kstrict);
+ aprintf(fout, ";\n");
+ if (Comment.size) {
+ aprintf(fout, "%s\t", Kcomment);
+ putstring(fout, true, Comment, false);
+ aprintf(fout, ";\n");
+ }
+ if (Expand != KEYVAL_EXPAND)
+ aprintf(fout, "%s\t%c%s%c;\n",
+ Kexpand, SDELIM, expand_names[Expand], SDELIM
+ );
+ awrite(Ignored.string, Ignored.size, fout);
+ aputc_('\n', fout)
+}
+
+
+ static void
+putdelta(node, fout)
+ register struct hshentry const *node;
+ register FILE * fout;
+/* Output the delta NODE to FOUT. */
+{
+ struct branchhead const *nextbranch;
+
+ if (!node) return;
+
+ aprintf(fout, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches",
+ node->num,
+ Kdate, node->date,
+ Kauthor, node->author,
+ Kstate, node->state?node->state:""
+ );
+ nextbranch = node->branches;
+ while (nextbranch) {
+ aprintf(fout, "\n\t%s", nextbranch->hsh->num);
+ nextbranch = nextbranch->nextbranch;
+ }
+
+ aprintf(fout, ";\n%s\t%s;\n", Knext, node->next?node->next->num:"");
+ awrite(node->ig.string, node->ig.size, fout);
+}
+
+
+ void
+puttree(root, fout)
+ struct hshentry const *root;
+ register FILE *fout;
+/* Output the delta tree with base ROOT in preorder to FOUT. */
+{
+ struct branchhead const *nextbranch;
+
+ if (!root) return;
+
+ if (root->selector)
+ putdelta(root, fout);
+
+ puttree(root->next, fout);
+
+ nextbranch = root->branches;
+ while (nextbranch) {
+ puttree(nextbranch->hsh, fout);
+ nextbranch = nextbranch->nextbranch;
+ }
+}
+
+
+ int
+putdtext(delta, srcname, fout, diffmt)
+ struct hshentry const *delta;
+ char const *srcname;
+ FILE *fout;
+ int diffmt;
+/*
+ * Output a deltatext node with delta number DELTA->num, log message DELTA->log,
+ * ignored phrases DELTA->igtext and text SRCNAME to FOUT.
+ * Double up all SDELIMs in both the log and the text.
+ * Make sure the log message ends in \n.
+ * Return false on error.
+ * If DIFFMT, also check that the text is valid diff -n output.
+ */
+{
+ RILE *fin;
+ if (!(fin = Iopen(srcname, "r", (struct stat*)0))) {
+ eerror(srcname);
+ return false;
+ }
+ putdftext(delta, fin, fout, diffmt);
+ Ifclose(fin);
+ return true;
+}
+
+ void
+putstring(out, delim, s, log)
+ register FILE *out;
+ struct cbuf s;
+ int delim, log;
+/*
+ * Output to OUT one SDELIM if DELIM, then the string S with SDELIMs doubled.
+ * If LOG is set then S is a log string; append a newline if S is nonempty.
+ */
+{
+ register char const *sp;
+ register size_t ss;
+
+ if (delim)
+ aputc_(SDELIM, out)
+ sp = s.string;
+ for (ss = s.size; ss; --ss) {
+ if (*sp == SDELIM)
+ aputc_(SDELIM, out)
+ aputc_(*sp++, out)
+ }
+ if (s.size && log)
+ aputc_('\n', out)
+ aputc_(SDELIM, out)
+}
+
+ void
+putdftext(delta, finfile, foutfile, diffmt)
+ struct hshentry const *delta;
+ RILE *finfile;
+ FILE *foutfile;
+ int diffmt;
+/* like putdtext(), except the source file is already open */
+{
+ declarecache;
+ register FILE *fout;
+ register int c;
+ register RILE *fin;
+ int ed;
+ struct diffcmd dc;
+
+ fout = foutfile;
+ aprintf(fout, DELNUMFORM, delta->num, Klog);
+
+ /* put log */
+ putstring(fout, true, delta->log, true);
+ aputc_('\n', fout)
+
+ /* put ignored phrases */
+ awrite(delta->igtext.string, delta->igtext.size, fout);
+
+ /* put text */
+ aprintf(fout, "%s\n%c", Ktext, SDELIM);
+
+ fin = finfile;
+ setupcache(fin);
+ if (!diffmt) {
+ /* Copy the file */
+ cache(fin);
+ for (;;) {
+ cachegeteof_(c, break;)
+ if (c==SDELIM) aputc_(SDELIM, fout) /*double up SDELIM*/
+ aputc_(c, fout)
+ }
+ } else {
+ initdiffcmd(&dc);
+ while (0 <= (ed = getdiffcmd(fin, false, fout, &dc)))
+ if (ed) {
+ cache(fin);
+ while (dc.nlines--)
+ do {
+ cachegeteof_(c, { if (!dc.nlines) goto OK_EOF; unexpected_EOF(); })
+ if (c == SDELIM)
+ aputc_(SDELIM, fout)
+ aputc_(c, fout)
+ } while (c != '\n');
+ uncache(fin);
+ }
+ }
+ OK_EOF:
+ aprintf(fout, "%c\n", SDELIM);
+}
diff --git a/gnu/usr.bin/rcs/lib/rcskeep.c b/gnu/usr.bin/rcs/lib/rcskeep.c
index 1a0c78f..31f2f9b 100644
--- a/gnu/usr.bin/rcs/lib/rcskeep.c
+++ b/gnu/usr.bin/rcs/lib/rcskeep.c
@@ -1,14 +1,7 @@
-/*
- * RCS keyword extraction
- */
-/*****************************************************************************
- * main routine: getoldkeys()
- * Testprogram: define KEEPTEST
- *****************************************************************************
- */
+/* Extract RCS keyword string values from working files. */
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -24,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -33,9 +27,26 @@ Report problems and direct all questions to:
*/
-
-
-/* $Log: rcskeep.c,v $
+/*
+ * $Log: rcskeep.c,v $
+ * Revision 5.10 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.9 1995/06/01 16:23:43 eggert
+ * (getoldkeys): Don't panic if a Name: is empty.
+ *
+ * Revision 5.8 1994/03/17 14:05:48 eggert
+ * Remove lint.
+ *
+ * Revision 5.7 1993/11/09 17:40:15 eggert
+ * Use simpler timezone parsing strategy now that we're using ISO 8601 format.
+ *
+ * Revision 5.6 1993/11/03 17:42:27 eggert
+ * Scan for Name keyword. Improve quality of diagnostics.
+ *
+ * Revision 5.5 1992/07/28 16:12:44 eggert
+ * Statement macro names now end in _.
+ *
* Revision 5.4 1991/08/19 03:13:55 eggert
* Tune.
*
@@ -86,33 +97,29 @@ Report problems and direct all questions to:
*
*/
-/*
-#define KEEPTEST
-*/
-/* Testprogram; prints out the keyword values found. */
-
#include "rcsbase.h"
-libId(keepId, "$Id: rcskeep.c,v 5.4 1991/08/19 03:13:55 eggert Exp $")
+libId(keepId, "$Id: rcskeep.c,v 5.10 1995/06/16 06:19:24 eggert Exp $")
-static int checknum P((char const*,int));
-static int getval P((RILE*,struct buf*,int));
+static int badly_terminated P((void));
+static int checknum P((char const*));
static int get0val P((int,RILE*,struct buf*,int));
+static int getval P((RILE*,struct buf*,int));
static int keepdate P((RILE*));
static int keepid P((int,RILE*,struct buf*));
static int keeprev P((RILE*));
int prevkeys;
-struct buf prevauthor, prevdate, prevrev, prevstate;
+struct buf prevauthor, prevdate, prevname, prevrev, prevstate;
int
getoldkeys(fp)
register RILE *fp;
/* Function: Tries to read keyword values for author, date,
* revision number, and state out of the file fp.
- * If FNAME is nonnull, it is opened and closed instead of using FP.
+ * If fp is null, workname is opened and closed instead of using fp.
* The results are placed into
- * prevauthor, prevdate, prevrev, prevstate.
+ * prevauthor, prevdate, prevname, prevrev, prevstate.
* Aborts immediately if it finds an error and returns false.
* If it returns true, it doesn't mean that any of the
* values were found; instead, check to see whether the corresponding arrays
@@ -123,14 +130,15 @@ getoldkeys(fp)
char keyword[keylength+1];
register char * tp;
int needs_closing;
+ int prevname_found;
if (prevkeys)
return true;
needs_closing = false;
if (!fp) {
- if (!(fp = Iopen(workfilename, FOPEN_R_WORK, (struct stat*)0))) {
- eerror(workfilename);
+ if (!(fp = Iopen(workname, FOPEN_R_WORK, (struct stat*)0))) {
+ eerror(workname);
return false;
}
needs_closing = true;
@@ -139,6 +147,7 @@ getoldkeys(fp)
/* initialize to empty */
bufscpy(&prevauthor, "");
bufscpy(&prevdate, "");
+ bufscpy(&prevname, ""); prevname_found = 0;
bufscpy(&prevrev, "");
bufscpy(&prevstate, "");
@@ -149,7 +158,7 @@ getoldkeys(fp)
/* try to get keyword */
tp = keyword;
for (;;) {
- Igeteof(fp, c, goto ok;);
+ Igeteof_(fp, c, goto ok;)
switch (c) {
default:
if (keyword+keylength <= tp)
@@ -165,7 +174,7 @@ getoldkeys(fp)
} while (c==KDELIM);
if (c!=VDELIM) continue;
*tp = c;
- Igeteof(fp, c, break;);
+ Igeteof_(fp, c, break;)
switch (c) {
case ' ': case '\t': break;
default: continue;
@@ -184,7 +193,7 @@ getoldkeys(fp)
case Header:
case Id:
if (!(
- getval(fp, (struct buf*)nil, false) &&
+ getval(fp, (struct buf*)0, false) &&
keeprev(fp) &&
(c = keepdate(fp)) &&
keepid(c, fp, &prevauthor) &&
@@ -192,8 +201,8 @@ getoldkeys(fp)
))
return false;
/* Skip either ``who'' (new form) or ``Locker: who'' (old). */
- if (getval(fp, (struct buf*)nil, true) &&
- getval(fp, (struct buf*)nil, true))
+ if (getval(fp, (struct buf*)0, true) &&
+ getval(fp, (struct buf*)0, true))
c = 0;
else if (nerror)
return false;
@@ -201,13 +210,24 @@ getoldkeys(fp)
c = KDELIM;
break;
case Locker:
+ (void) getval(fp, (struct buf*)0, false);
+ c = 0;
+ break;
case Log:
case RCSfile:
case Source:
- if (!getval(fp, (struct buf*)nil, false))
+ if (!getval(fp, (struct buf*)0, false))
return false;
c = 0;
break;
+ case Name:
+ if (getval(fp, &prevname, false)) {
+ if (*prevname.string)
+ checkssym(prevname.string);
+ prevname_found = 1;
+ }
+ c = 0;
+ break;
case Revision:
if (!keeprev(fp))
return false;
@@ -222,16 +242,18 @@ getoldkeys(fp)
continue;
}
if (!c)
- Igeteof(fp, c, c=0;);
+ Igeteof_(fp, c, c=0;)
if (c != KDELIM) {
- error("closing %c missing on keyword", KDELIM);
+ workerror("closing %c missing on keyword", KDELIM);
return false;
}
- if (*prevauthor.string && *prevdate.string && *prevrev.string && *prevstate.string) {
+ if (prevname_found &&
+ *prevauthor.string && *prevdate.string &&
+ *prevrev.string && *prevstate.string
+ )
break;
- }
}
- Igeteof(fp, c, break;);
+ Igeteof_(fp, c, break;)
}
ok:
@@ -246,7 +268,7 @@ getoldkeys(fp)
static int
badly_terminated()
{
- error("badly terminated keyword value");
+ workerror("badly terminated keyword value");
return false;
}
@@ -257,12 +279,12 @@ getval(fp, target, optional)
int optional;
/* Reads a keyword value from FP into TARGET.
* Returns true if one is found, false otherwise.
- * Does not modify target if it is nil.
+ * Does not modify target if it is 0.
* Do not report an error if OPTIONAL is set and KDELIM is found instead.
*/
{
int c;
- Igeteof(fp, c, return badly_terminated(););
+ Igeteof_(fp, c, return badly_terminated();)
return get0val(c, fp, target, optional);
}
@@ -305,8 +327,6 @@ get0val(c, fp, target, optional)
VOID printf("getval: %s\n", target);
# endif
}
- if (!got1)
- error("too much white space in keyword value");
return got1;
case KDELIM:
@@ -317,7 +337,7 @@ get0val(c, fp, target, optional)
case 0:
return badly_terminated();
}
- Igeteof(fp, c, return badly_terminated(););
+ Igeteof_(fp, c, return badly_terminated();)
}
}
@@ -329,8 +349,7 @@ keepdate(fp)
* Return 0 on error, lookahead character otherwise.
*/
{
- struct buf prevday, prevtime, prevzone;
- register char const *p;
+ struct buf prevday, prevtime;
register int c;
c = 0;
@@ -338,24 +357,18 @@ keepdate(fp)
if (getval(fp,&prevday,false)) {
bufautobegin(&prevtime);
if (getval(fp,&prevtime,false)) {
- bufautobegin(&prevzone);
- bufscpy(&prevzone, "");
- Igeteof(fp, c, c=0;);
- if (c=='-' || c=='+')
- if (!get0val(c,fp,&prevzone,false))
- c = 0;
- else
- Igeteof(fp, c, c=0;);
+ Igeteof_(fp, c, c=0;)
if (c) {
- p = prevday.string;
- bufalloc(&prevdate, strlen(p) + strlen(prevtime.string) + strlen(prevzone.string) + 5);
- VOID sprintf(prevdate.string, "%s%s %s %s",
+ register char const *d = prevday.string, *t = prevtime.string;
+ bufalloc(&prevdate, strlen(d) + strlen(t) + 9);
+ VOID sprintf(prevdate.string, "%s%s %s%s",
/* Parse dates put out by old versions of RCS. */
- isdigit(p[0]) && isdigit(p[1]) && p[2]=='/' ? "19" : "",
- p, prevtime.string, prevzone.string
+ isdigit(d[0]) && isdigit(d[1]) && !isdigit(d[2])
+ ? "19" : "",
+ d, t,
+ strchr(t,'-') || strchr(t,'+') ? "" : "+0000"
);
}
- bufautoend(&prevzone);
}
bufautoend(&prevtime);
}
@@ -371,11 +384,11 @@ keepid(c, fp, b)
/* Get previous identifier from C+FP into B. */
{
if (!c)
- Igeteof(fp, c, return false;);
+ Igeteof_(fp, c, return false;)
if (!get0val(c, fp, b, false))
return false;
checksid(b->string);
- return true;
+ return !nerror;
}
static int
@@ -383,28 +396,45 @@ keeprev(fp)
RILE *fp;
/* Get previous revision from FP into prevrev. */
{
- return getval(fp,&prevrev,false) && checknum(prevrev.string,-1);
+ return getval(fp,&prevrev,false) && checknum(prevrev.string);
}
static int
-checknum(sp,fields)
- register char const *sp;
- int fields;
-{ register int dotcount;
- dotcount=0;
- while(*sp) {
- if (*sp=='.') dotcount++;
- else if (!isdigit(*sp)) return false;
- sp++;
- }
- return fields<0 ? dotcount&1 : dotcount==fields;
+checknum(s)
+ char const *s;
+{
+ register char const *sp;
+ register int dotcount = 0;
+ for (sp=s; ; sp++) {
+ switch (*sp) {
+ case 0:
+ if (dotcount & 1)
+ return true;
+ else
+ break;
+
+ case '.':
+ dotcount++;
+ continue;
+
+ default:
+ if (isdigit(*sp))
+ continue;
+ break;
+ }
+ break;
+ }
+ workerror("%s is not a revision number", s);
+ return false;
}
#ifdef KEEPTEST
+/* Print the keyword values found. */
+
char const cmdid[] ="keeptest";
int
@@ -412,10 +442,10 @@ main(argc, argv)
int argc; char *argv[];
{
while (*(++argv)) {
- workfilename = *argv;
+ workname = *argv;
getoldkeys((RILE*)0);
- VOID printf("%s: revision: %s, date: %s, author: %s, state: %s\n",
- *argv, prevrev.string, prevdate.string, prevauthor.string, prevstate.string);
+ VOID printf("%s: revision: %s, date: %s, author: %s, name: %s, state: %s\n",
+ *argv, prevrev.string, prevdate.string, prevauthor.string, prevname.string, prevstate.string);
}
exitmain(EXIT_SUCCESS);
}
diff --git a/gnu/usr.bin/rcs/lib/rcskeys.c b/gnu/usr.bin/rcs/lib/rcskeys.c
index 82850a7..2afdd07 100644
--- a/gnu/usr.bin/rcs/lib/rcskeys.c
+++ b/gnu/usr.bin/rcs/lib/rcskeys.c
@@ -1,9 +1,7 @@
-/*
- * RCS keyword table and match operation
- */
+/* RCS keyword table and match operation */
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -19,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -28,9 +27,14 @@ Report problems and direct all questions to:
*/
-
-
-/* $Log: rcskeys.c,v $
+/*
+ * $Log: rcskeys.c,v $
+ * Revision 5.4 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.3 1993/11/03 17:42:27 eggert
+ * Add Name keyword.
+ *
* Revision 5.2 1991/08/19 03:13:55 eggert
* Say `T const' instead of `const T'; it's less confusing for pointer types.
* (This change was made in other source files too.)
@@ -60,14 +64,14 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(keysId, "$Id: rcskeys.c,v 5.2 1991/08/19 03:13:55 eggert Exp $")
+libId(keysId, "$Id: rcskeys.c,v 5.4 1995/06/16 06:19:24 eggert Exp $")
char const *const Keyword[] = {
/* This must be in the same order as rcsbase.h's enum markers type. */
- nil,
+ 0,
AUTHOR, DATE, HEADER, IDH,
- LOCKER, LOG, RCSFILE, REVISION, SOURCE, STATE
+ LOCKER, LOG, NAME, RCSFILE, REVISION, SOURCE, STATE
};
diff --git a/gnu/usr.bin/rcs/lib/rcslex.c b/gnu/usr.bin/rcs/lib/rcslex.c
index 51e31f3..da57c03 100644
--- a/gnu/usr.bin/rcs/lib/rcslex.c
+++ b/gnu/usr.bin/rcs/lib/rcslex.c
@@ -1,17 +1,16 @@
-/*
- * RCS file input
- */
-/*********************************************************************************
+/* lexical analysis of RCS files */
+
+/******************************************************************************
* Lexical Analysis.
* hashtable, Lexinit, nextlex, getlex, getkey,
* getid, getnum, readstring, printstring, savestring,
* checkid, fatserror, error, faterror, warn, diagnose
* Testprogram: define LEXDB
- *********************************************************************************
+ ******************************************************************************
*/
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -27,8 +26,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -38,7 +38,44 @@ Report problems and direct all questions to:
-/* $Log: rcslex.c,v $
+/*
+ * $Log: rcslex.c,v $
+ * Revision 5.19 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.18 1995/06/01 16:23:43 eggert
+ * (map_fd_deallocate,mmap_deallocate,read_deallocate,nothing_to_deallocate):
+ * New functions.
+ * (Iclose): If large_memory and maps_memory, use them to deallocate mapping.
+ * (fd2RILE): Use map_fd if available.
+ * If one mapping method fails, try the next instead of giving up;
+ * if they all fail, fall back on ordinary read.
+ * Work around bug: root mmap over NFS succeeds, but accessing dumps core.
+ * Use MAP_FAILED macro for mmap failure, and `char *' instead of caddr_t.
+ * (advise_access): Use madvise only if this instance used mmap.
+ * (Iopen): Use fdSafer to get safer file descriptor.
+ * (aflush): Moved here from rcsedit.c.
+ *
+ * Revision 5.17 1994/03/20 04:52:58 eggert
+ * Don't worry if madvise fails. Add Orewind. Remove lint.
+ *
+ * Revision 5.16 1993/11/09 17:55:29 eggert
+ * Fix `label: }' typo.
+ *
+ * Revision 5.15 1993/11/03 17:42:27 eggert
+ * Improve quality of diagnostics by putting file names in them more often.
+ * Don't discard ignored phrases.
+ *
+ * Revision 5.14 1992/07/28 16:12:44 eggert
+ * Identifiers may now start with a digit and (unless they are symbolic names)
+ * may contain `.'. Avoid `unsigned'. Statement macro names now end in _.
+ *
+ * Revision 5.13 1992/02/17 23:02:27 eggert
+ * Work around NFS mmap SIGBUS problem.
+ *
+ * Revision 5.12 1992/01/06 02:42:34 eggert
+ * Use OPEN_O_BINARY if mode contains 'b'.
+ *
* Revision 5.11 1991/11/03 03:30:44 eggert
* Fix porting bug to ancient hosts lacking vfprintf.
*
@@ -132,7 +169,14 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(lexId, "$Id: rcslex.c,v 5.11 1991/11/03 03:30:44 eggert Exp $")
+libId(lexId, "$Id: rcslex.c,v 5.19 1995/06/16 06:19:24 eggert Exp $")
+
+static char *checkidentifier P((char*,int,int));
+static void errsay P((char const*));
+static void fatsay P((char const*));
+static void lookup P((char const*));
+static void startsay P((const char*,const char*));
+static void warnsay P((char const*));
static struct hshentry *nexthsh; /*pointer to next hash entry, set by lookup*/
@@ -142,7 +186,7 @@ int hshenter; /*if true, next suitable lexeme will be entered */
/*into the symbol table. Handle with care. */
int nextc; /*next input character, initialized by Lexinit */
-unsigned long rcsline; /*current line-number of input */
+long rcsline; /*current line-number of input */
int nerror; /*counter for errors */
int quietflag; /*indicates quiet mode */
RILE * finptr; /*input file descriptor */
@@ -172,9 +216,9 @@ static int ignored_phrases; /* have we ignored phrases in this RCS file? */
void
warnignore()
{
- if (! (ignored_phrases|quietflag)) {
+ if (!ignored_phrases) {
ignored_phrases = true;
- warn("Unknown phrases like `%s ...;' are in the RCS file.", NextString);
+ rcswarn("Unknown phrases like `%s ...;' are present.", NextString);
}
}
@@ -205,7 +249,7 @@ lookup(str)
/* empty slot found */
*p = n = ftalloc(struct hshentry);
n->num = fstr_save(str);
- n->nexthsh = nil;
+ n->nexthsh = 0;
# ifdef LEXDB
VOID printf("\nEntered: %s at %u ", str, ihash);
# endif
@@ -231,7 +275,7 @@ Lexinit()
{ register int c;
for (c = hshsize; 0 <= --c; ) {
- hshtab[c] = nil;
+ hshtab[c] = 0;
}
nerror = 0;
@@ -241,7 +285,7 @@ Lexinit()
ignored_phrases = false;
rcsline = 1;
bufrealloc(&tokbuf, 2);
- Iget(finptr, nextc);
+ Iget_(finptr, nextc)
nextlex(); /*initial token*/
}
}
@@ -288,46 +332,48 @@ nextlex()
/* Note: falls into next case */
case SPACE:
- GETC(frew, c);
+ GETC_(frew, c)
continue;
- case DIGIT:
- sp = tokbuf.string;
- limit = sp + tokbuf.size;
- *sp++ = c;
- for (;;) {
- GETC(frew, c);
- if ((d=ctab[c])!=DIGIT && d!=PERIOD)
- break;
- *sp++ = c; /* 1.2. and 1.2 are different */
- if (limit <= sp)
- sp = bufenlarge(&tokbuf, &limit);
- }
- *sp = 0;
- if (hshenter)
- lookup(tokbuf.string);
- else
- NextString = fstr_save(tokbuf.string);
- d = NUM;
- break;
-
-
- case LETTER:
+ case IDCHAR:
+ case LETTER:
case Letter:
+ d = ID;
+ /* fall into */
+ case DIGIT:
+ case PERIOD:
sp = tokbuf.string;
limit = sp + tokbuf.size;
*sp++ = c;
for (;;) {
- GETC(frew, c);
- if ((d=ctab[c])!=LETTER && d!=Letter && d!=DIGIT && d!=IDCHAR)
+ GETC_(frew, c)
+ switch (ctab[c]) {
+ case IDCHAR:
+ case LETTER:
+ case Letter:
+ d = ID;
+ /* fall into */
+ case DIGIT:
+ case PERIOD:
+ *sp++ = c;
+ if (limit <= sp)
+ sp = bufenlarge(&tokbuf, &limit);
+ continue;
+
+ default:
break;
- *sp++ = c;
- if (limit <= sp)
- sp = bufenlarge(&tokbuf, &limit);
+ }
+ break;
}
*sp = 0;
+ if (d == DIGIT || d == PERIOD) {
+ d = NUM;
+ if (hshenter) {
+ lookup(tokbuf.string);
+ break;
+ }
+ }
NextString = fstr_save(tokbuf.string);
- d = ID; /* may be ID or keyword */
break;
case SBEGIN: /* long string */
@@ -338,7 +384,7 @@ nextlex()
case COLON:
case SEMI:
- GETC(frew, c);
+ GETC_(frew, c)
break;
} break; }
nextc = c;
@@ -374,11 +420,11 @@ eoflex()
++rcsline;
/* fall into */
case SPACE:
- cachegeteof(c, {uncache(fin);return true;});
+ cachegeteof_(c, {uncache(fin);return true;})
break;
}
if (fout)
- aputc(c, fout);
+ aputc_(c, fout)
}
}
@@ -442,7 +488,7 @@ getkeystring(key)
getid()
/* Function: Checks if nexttok is an identifier. If so,
* advances the input by calling nextlex and returns a pointer
- * to the identifier; otherwise returns nil.
+ * to the identifier; otherwise returns 0.
* Treats keywords as identifiers.
*/
{
@@ -451,14 +497,15 @@ getid()
name = NextString;
nextlex();
return name;
- } else return nil;
+ } else
+ return 0;
}
struct hshentry * getnum()
/* Function: Checks if nexttok is a number. If so,
* advances the input by calling nextlex and returns a pointer
- * to the hashtable entry. Otherwise returns nil.
+ * to the hashtable entry. Otherwise returns 0.
* Doesn't work if hshenter is false.
*/
{
@@ -467,46 +514,55 @@ struct hshentry * getnum()
num=nexthsh;
nextlex();
return num;
- } else return nil;
+ } else
+ return 0;
}
struct cbuf
getphrases(key)
char const *key;
-/* Get a series of phrases that do not start with KEY, yield resulting buffer.
- * Stop when the next phrase starts with a token that is not an identifier,
- * or is KEY.
- * Assume !foutptr.
- */
+/*
+* Get a series of phrases that do not start with KEY. Yield resulting buffer.
+* Stop when the next phrase starts with a token that is not an identifier,
+* or is KEY. Copy input to foutptr if it is set. Unlike ignorephrases(),
+* this routine assumes nextlex() has already been invoked before we start.
+*/
{
declarecache;
register int c;
- register char *p;
- char const *limit;
- register char const *ki, *kn;
+ register char const *kn;
struct cbuf r;
- struct buf b;
register RILE *fin;
+ register FILE *frew;
+# if large_memory
+# define savech_(c) ;
+# else
+ register char *p;
+ char const *limit;
+ struct buf b;
+# define savech_(c) {if (limit<=p)p=bufenlarge(&b,&limit); *p++ =(c);}
+# endif
- if (nexttok!=ID || strcmp(NextString,key) == 0) {
- r.string = 0;
- r.size = 0;
- return r;
- } else {
+ if (nexttok!=ID || strcmp(NextString,key) == 0)
+ clear_buf(&r);
+ else {
warnignore();
fin = finptr;
+ frew = foutptr;
setupcache(fin); cache(fin);
- bufautobegin(&b);
- bufscpy(&b, NextString);
+# if large_memory
+ r.string = (char const*)cacheptr() - strlen(NextString) - 1;
+# else
+ bufautobegin(&b);
+ bufscpy(&b, NextString);
+ p = b.string + strlen(b.string);
+ limit = b.string + b.size;
+# endif
ffree1(NextString);
- p = b.string + strlen(b.string);
- limit = b.string + b.size;
c = nextc;
for (;;) {
for (;;) {
- if (limit <= p)
- p = bufenlarge(&b, &limit);
- *p++ = c;
+ savech_(c)
switch (ctab[c]) {
default:
fatserror("unknown character `%c'", c);
@@ -516,15 +572,13 @@ getphrases(key)
/* fall into */
case COLON: case DIGIT: case LETTER: case Letter:
case PERIOD: case SPACE:
- cacheget(c);
+ GETC_(frew, c)
continue;
case SBEGIN: /* long string */
for (;;) {
for (;;) {
- if (limit <= p)
- p = bufenlarge(&b, &limit);
- cacheget(c);
- *p++ = c;
+ GETC_(frew, c)
+ savech_(c)
switch (c) {
case '\n':
++rcsline;
@@ -537,48 +591,50 @@ getphrases(key)
}
break;
}
- cacheget(c);
+ GETC_(frew, c)
if (c != SDELIM)
break;
- if (limit <= p)
- p = bufenlarge(&b, &limit);
- *p++ = c;
+ savech_(c)
}
continue;
case SEMI:
- cacheget(c);
+ cacheget_(c)
if (ctab[c] == NEWLN) {
+ if (frew)
+ aputc_(c, frew)
++rcsline;
- if (limit <= p)
- p = bufenlarge(&b, &limit);
- *p++ = c;
- cacheget(c);
+ savech_(c)
+ cacheget_(c)
}
+# if large_memory
+ r.size = (char const*)cacheptr() - 1 - r.string;
+# endif
for (;;) {
switch (ctab[c]) {
case NEWLN:
++rcsline;
/* fall into */
case SPACE:
- cacheget(c);
+ cacheget_(c)
continue;
default: break;
}
break;
}
+ if (frew)
+ aputc_(c, frew)
break;
}
break;
}
- switch (ctab[c]) {
- case LETTER:
- case Letter:
+ if (ctab[c] == Letter) {
for (kn = key; c && *kn==c; kn++)
- cacheget(c);
+ GETC_(frew, c)
if (!*kn)
switch (ctab[c]) {
case DIGIT: case LETTER: case Letter:
+ case IDCHAR: case PERIOD:
break;
default:
nextc = c;
@@ -587,23 +643,26 @@ getphrases(key)
uncache(fin);
goto returnit;
}
- for (ki=key; ki<kn; ) {
- if (limit <= p)
- p = bufenlarge(&b, &limit);
- *p++ = *ki++;
- }
- break;
-
- default:
+# if !large_memory
+ {
+ register char const *ki;
+ for (ki=key; ki<kn; )
+ savech_(*ki++)
+ }
+# endif
+ } else {
nextc = c;
uncache(fin);
nextlex();
- goto returnit;
+ break;
}
}
- returnit:
- return bufremember(&b, (size_t)(p - b.string));
+ returnit:;
+# if !large_memory
+ return bufremember(&b, (size_t)(p - b.string));
+# endif
}
+ return r;
}
@@ -619,14 +678,14 @@ readstring()
fin=finptr; frew=foutptr;
setupcache(fin); cache(fin);
for (;;) {
- GETC(frew, c);
+ GETC_(frew, c)
switch (c) {
case '\n':
++rcsline;
break;
case SDELIM:
- GETC(frew, c);
+ GETC_(frew, c)
if (c != SDELIM) {
/* end of string */
nextc = c;
@@ -653,13 +712,13 @@ printstring()
fout = stdout;
setupcache(fin); cache(fin);
for (;;) {
- cacheget(c);
+ cacheget_(c)
switch (c) {
case '\n':
++rcsline;
break;
case SDELIM:
- cacheget(c);
+ cacheget_(c)
if (c != SDELIM) {
nextc=c;
uncache(fin);
@@ -667,7 +726,7 @@ printstring()
}
break;
}
- aputc(c,fout);
+ aputc_(c,fout)
}
}
@@ -695,13 +754,13 @@ savestring(target)
setupcache(fin); cache(fin);
tp = target->string; limit = tp + target->size;
for (;;) {
- GETC(frew, c);
+ GETC_(frew, c)
switch (c) {
case '\n':
++rcsline;
break;
case SDELIM:
- GETC(frew, c);
+ GETC_(frew, c)
if (c != SDELIM) {
/* end of string */
nextc=c;
@@ -719,44 +778,76 @@ savestring(target)
}
- char *
-checkid(id, delimiter)
+ static char *
+checkidentifier(id, delimiter, dotok)
register char *id;
int delimiter;
+ register int dotok;
/* Function: check whether the string starting at id is an */
/* identifier and return a pointer to the delimiter*/
/* after the identifier. White space, delim and 0 */
/* are legal delimiters. Aborts the program if not*/
/* a legal identifier. Useful for checking commands*/
/* If !delim, the only delimiter is 0. */
+/* Allow '.' in identifier only if DOTOK is set. */
{
- register enum tokens d;
register char *temp;
- register char c,tc;
+ register char c;
register char delim = delimiter;
+ int isid = false;
temp = id;
- if ((d = ctab[(unsigned char)(c = *id)])==LETTER || d==Letter) {
- while ((d = ctab[(unsigned char)(c = *++id)])==LETTER
- || d==Letter || d==DIGIT || d==IDCHAR
- )
- ;
- if (c && (!delim || c!=delim && c!=' ' && c!='\t' && c!='\n')) {
+ for (;; id++) {
+ switch (ctab[(unsigned char)(c = *id)]) {
+ case IDCHAR:
+ case LETTER:
+ case Letter:
+ isid = true;
+ continue;
+
+ case DIGIT:
+ continue;
+
+ case PERIOD:
+ if (dotok)
+ continue;
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+ if ( ! isid
+ || (c && (!delim || (c!=delim && c!=' ' && c!='\t' && c!='\n')))
+ ) {
/* append \0 to end of id before error message */
- tc = c;
- while( (c=(*++id))!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) ;
+ while ((c = *id) && c!=' ' && c!='\t' && c!='\n' && c!=delim)
+ id++;
*id = '\0';
- faterror("invalid character %c in identifier `%s'",tc,temp);
- }
- } else {
- /* append \0 to end of id before error message */
- while( (c=(*++id))!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) ;
- *id = '\0';
- faterror("identifier `%s' doesn't start with letter", temp);
- }
+ faterror("invalid %s `%s'",
+ dotok ? "identifier" : "symbol", temp
+ );
+ }
return id;
}
+ char *
+checkid(id, delimiter)
+ char *id;
+ int delimiter;
+{
+ return checkidentifier(id, delimiter, true);
+}
+
+ char *
+checksym(sym, delimiter)
+ char *sym;
+ int delimiter;
+{
+ return checkidentifier(sym, delimiter, false);
+}
+
void
checksid(id)
char *id;
@@ -765,16 +856,92 @@ checksid(id)
VOID checkid(id, 0);
}
+ void
+checkssym(sym)
+ char *sym;
+{
+ VOID checksym(sym, 0);
+}
+
+
+#if !large_memory
+# define Iclose(f) fclose(f)
+#else
+# if !maps_memory
+ static int Iclose P((RILE *));
+ static int
+ Iclose(f)
+ register RILE *f;
+ {
+ tfree(f->base);
+ f->base = 0;
+ return fclose(f->stream);
+ }
+# else
+ static int Iclose P((RILE *));
+ static int
+ Iclose(f)
+ register RILE *f;
+ {
+ (* f->deallocate) (f);
+ f->base = 0;
+ return close(f->fd);
+ }
+# if has_map_fd
+ static void map_fd_deallocate P((RILE *));
+ static void
+ map_fd_deallocate(f)
+ register RILE *f;
+ {
+ if (vm_deallocate(
+ task_self(),
+ (vm_address_t) f->base,
+ (vm_size_t) (f->lim - f->base)
+ ) != KERN_SUCCESS)
+ efaterror("vm_deallocate");
+ }
+# endif
+# if has_mmap
+ static void mmap_deallocate P((RILE *));
+ static void
+ mmap_deallocate(f)
+ register RILE *f;
+ {
+ if (munmap((char *) f->base, (size_t) (f->lim - f->base)) != 0)
+ efaterror("munmap");
+ }
+# endif
+ static void read_deallocate P((RILE *));
+ static void
+ read_deallocate(f)
+ RILE *f;
+ {
+ tfree(f->base);
+ }
+
+ static void nothing_to_deallocate P((RILE *));
+ static void
+ nothing_to_deallocate(f)
+ RILE *f;
+ {
+ }
+# endif
+#endif
+
+
+#if large_memory && maps_memory
+ static RILE *fd2_RILE P((int,char const*,struct stat*));
static RILE *
-#if has_mmap && large_memory
-fd2_RILE(fd, filename, status)
+fd2_RILE(fd, name, status)
#else
-fd2RILE(fd, filename, mode, status)
- char const *mode;
+ static RILE *fd2RILE P((int,char const*,char const*,struct stat*));
+ static RILE *
+fd2RILE(fd, name, type, status)
+ char const *type;
#endif
int fd;
- char const *filename;
+ char const *name;
register struct stat *status;
{
struct stat st;
@@ -782,67 +949,127 @@ fd2RILE(fd, filename, mode, status)
if (!status)
status = &st;
if (fstat(fd, status) != 0)
- efaterror(filename);
+ efaterror(name);
if (!S_ISREG(status->st_mode)) {
- error("`%s' is not a regular file", filename);
+ error("`%s' is not a regular file", name);
VOID close(fd);
errno = EINVAL;
return 0;
} else {
-# if ! (has_mmap && large_memory)
+# if !(large_memory && maps_memory)
FILE *stream;
- if (!(stream = fdopen(fd, mode)))
- efaterror(filename);
+ if (!(stream = fdopen(fd, type)))
+ efaterror(name);
# endif
# if !large_memory
return stream;
# else
# define RILES 3
- {
- static RILE rilebuf[RILES];
-
- register RILE *f;
- size_t s = status->st_size;
-
- if (s != status->st_size)
- faterror("`%s' is enormous", filename);
- for (f = rilebuf; f->base; f++)
- if (f == rilebuf+RILES)
- faterror("too many RILEs");
- if (!s) {
- static unsigned char dummy;
- f->base = &dummy;
- } else {
-# if has_mmap
- if (
- (f->base = (unsigned char *)mmap(
- (caddr_t)0, s, PROT_READ, MAP_SHARED,
- fd, (off_t)0
- )) == (unsigned char *)-1
- )
- efaterror("mmap");
-# else
- f->base = tnalloc(unsigned char, s);
+ {
+ static RILE rilebuf[RILES];
+
+ register RILE *f;
+ size_t s = status->st_size;
+
+ if (s != status->st_size)
+ faterror("%s: too large", name);
+ for (f = rilebuf; f->base; f++)
+ if (f == rilebuf+RILES)
+ faterror("too many RILEs");
+# if maps_memory
+ f->deallocate = nothing_to_deallocate;
+# endif
+ if (!s) {
+ static unsigned char nothing;
+ f->base = &nothing; /* Any nonzero address will do. */
+ } else {
+ f->base = 0;
+# if has_map_fd
+ map_fd(
+ fd, (vm_offset_t)0, (vm_address_t*) &f->base,
+ TRUE, (vm_size_t)s
+ );
+ f->deallocate = map_fd_deallocate;
+# endif
+# if has_mmap
+ if (!f->base) {
+ catchmmapints();
+ f->base = (unsigned char *) mmap(
+ (char *)0, s, PROT_READ, MAP_SHARED,
+ fd, (off_t)0
+ );
+# ifndef MAP_FAILED
+# define MAP_FAILED (-1)
# endif
+ if (f->base == (unsigned char *) MAP_FAILED)
+ f->base = 0;
+ else {
+# if has_NFS && mmap_signal
+ /*
+ * On many hosts, the superuser
+ * can mmap an NFS file it can't read.
+ * So access the first page now, and print
+ * a nice message if a bus error occurs.
+ */
+ readAccessFilenameBuffer(name, f->base);
+# endif
+ }
+ f->deallocate = mmap_deallocate;
+ }
+# endif
+ if (!f->base) {
+ f->base = tnalloc(unsigned char, s);
+# if maps_memory
+ {
+ /*
+ * We can't map the file into memory for some reason.
+ * Read it into main memory all at once; this is
+ * the simplest substitute for memory mapping.
+ */
+ char *bufptr = (char *) f->base;
+ size_t bufsiz = s;
+ do {
+ ssize_t r = read(fd, bufptr, bufsiz);
+ switch (r) {
+ case -1:
+ efaterror(name);
+
+ case 0:
+ /* The file must have shrunk! */
+ status->st_size = s -= bufsiz;
+ bufsiz = 0;
+ break;
+
+ default:
+ bufptr += r;
+ bufsiz -= r;
+ break;
+ }
+ } while (bufsiz);
+ if (lseek(fd, (off_t)0, SEEK_SET) == -1)
+ efaterror(name);
+ f->deallocate = read_deallocate;
}
- f->ptr = f->base;
- f->lim = f->base + s;
-# if has_mmap
- f->fd = fd;
-# else
- f->readlim = f->base;
- f->stream = stream;
# endif
- if_advise_access(s, f, MADV_SEQUENTIAL);
- return f;
+ }
}
+ f->ptr = f->base;
+ f->lim = f->base + s;
+ f->fd = fd;
+# if !maps_memory
+ f->readlim = f->base;
+ f->stream = stream;
+# endif
+ if_advise_access(s, f, MADV_SEQUENTIAL);
+ return f;
+ }
# endif
}
}
-#if !has_mmap && large_memory
+#if !maps_memory && large_memory
int
Igetmore(f)
register RILE *f;
@@ -868,59 +1095,42 @@ advise_access(f, advice)
register RILE *f;
int advice;
{
- if (madvise((caddr_t)f->base, (size_t)(f->lim - f->base), advice) != 0)
- efaterror("madvise");
+ if (f->deallocate == mmap_deallocate)
+ VOID madvise((char *)f->base, (size_t)(f->lim - f->base), advice);
+ /* Don't worry if madvise fails; it's only advisory. */
}
#endif
RILE *
-#if has_mmap && large_memory
-I_open(filename, status)
+#if large_memory && maps_memory
+I_open(name, status)
#else
-Iopen(filename, mode, status)
- char const *mode;
+Iopen(name, type, status)
+ char const *type;
#endif
- char const *filename;
+ char const *name;
struct stat *status;
-/* Open FILENAME for reading, yield its descriptor, and set *STATUS. */
+/* Open NAME for reading, yield its descriptor, and set *STATUS. */
{
- int fd;
+ int fd = fdSafer(open(name, O_RDONLY
+# if OPEN_O_BINARY
+ | (strchr(type,'b') ? OPEN_O_BINARY : 0)
+# endif
+ ));
- if ((fd = open(filename,O_RDONLY|O_BINARY)) < 0)
+ if (fd < 0)
return 0;
-# if has_mmap && large_memory
- return fd2_RILE(fd, filename, status);
+# if large_memory && maps_memory
+ return fd2_RILE(fd, name, status);
# else
- return fd2RILE(fd, filename, mode, status);
+ return fd2RILE(fd, name, type, status);
# endif
}
-#if !large_memory
-# define Iclose(f) fclose(f)
-#else
- static int
- Iclose(f)
- register RILE *f;
- {
-# if has_mmap
- size_t s = f->lim - f->base;
- if (s && munmap((caddr_t)f->base, s) != 0)
- return -1;
- f->base = 0;
- return close(f->fd);
-# else
- tfree(f->base);
- f->base = 0;
- return fclose(f->stream);
-# endif
- }
-#endif
-
-
static int Oerrloop;
- exiting void
+ void
Oerror()
{
if (Oerrloop)
@@ -929,8 +1139,8 @@ Oerror()
efaterror("output error");
}
-exiting void Ieof() { fatserror("unexpected end of file"); }
-exiting void Ierror() { efaterror("input error"); }
+void Ieof() { fatserror("unexpected end of file"); }
+void Ierror() { efaterror("input error"); }
void testIerror(f) FILE *f; { if (ferror(f)) Ierror(); }
void testOerror(o) FILE *o; { if (ferror(o)) Oerror(); }
@@ -951,19 +1161,17 @@ testIeof(f)
void Irewind(f) FILE *f; { if (fseek(f,0L,SEEK_SET) != 0) Ierror(); }
#endif
-void eflush()
-{
- if (fflush(stderr) != 0 && !Oerrloop)
- Oerror();
-}
+void Orewind(f) FILE *f; { if (fseek(f,0L,SEEK_SET) != 0) Oerror(); }
+void aflush(f) FILE *f; { if (fflush(f) != 0) Oerror(); }
+void eflush() { if (fflush(stderr)!=0 && !Oerrloop) Oerror(); }
void oflush()
{
if (fflush(workstdout ? workstdout : stdout) != 0 && !Oerrloop)
Oerror();
}
- static exiting void
+ void
fatcleanup(already_newline)
int already_newline;
{
@@ -971,8 +1179,38 @@ fatcleanup(already_newline)
exiterr();
}
-static void errsay() { oflush(); aprintf(stderr,"%s error: ",cmdid); nerror++; }
-static void fatsay() { oflush(); VOID fprintf(stderr,"%s error: ",cmdid); }
+ static void
+startsay(s, t)
+ const char *s, *t;
+{
+ oflush();
+ if (s)
+ aprintf(stderr, "%s: %s: %s", cmdid, s, t);
+ else
+ aprintf(stderr, "%s: %s", cmdid, t);
+}
+
+ static void
+fatsay(s)
+ char const *s;
+{
+ startsay(s, "");
+}
+
+ static void
+errsay(s)
+ char const *s;
+{
+ fatsay(s);
+ nerror++;
+}
+
+ static void
+warnsay(s)
+ char const *s;
+{
+ startsay(s, "warning: ");
+}
void eerror(s) char const *s; { enerror(errno,s); }
@@ -981,20 +1219,20 @@ enerror(e,s)
int e;
char const *s;
{
- errsay();
+ errsay((char const*)0);
errno = e;
perror(s);
eflush();
}
-exiting void efaterror(s) char const *s; { enfaterror(errno,s); }
+void efaterror(s) char const *s; { enfaterror(errno,s); }
- exiting void
+ void
enfaterror(e,s)
int e;
char const *s;
{
- fatsay();
+ fatsay((char const*)0);
errno = e;
perror(s);
fatcleanup(true);
@@ -1009,7 +1247,24 @@ error(char const *format,...)
/* non-fatal error */
{
va_list args;
- errsay();
+ errsay((char const*)0);
+ vararg_start(args, format);
+ fvfprintf(stderr, format, args);
+ va_end(args);
+ afputc('\n',stderr);
+ eflush();
+}
+
+#if has_prototypes
+ void
+rcserror(char const *format,...)
+#else
+ /*VARARGS1*/ void rcserror(format, va_alist) char const *format; va_dcl
+#endif
+/* non-fatal RCS file error */
+{
+ va_list args;
+ errsay(RCSname);
vararg_start(args, format);
fvfprintf(stderr, format, args);
va_end(args);
@@ -1018,17 +1273,34 @@ error(char const *format,...)
}
#if has_prototypes
- exiting void
+ void
+workerror(char const *format,...)
+#else
+ /*VARARGS1*/ void workerror(format, va_alist) char const *format; va_dcl
+#endif
+/* non-fatal working file error */
+{
+ va_list args;
+ errsay(workname);
+ vararg_start(args, format);
+ fvfprintf(stderr, format, args);
+ va_end(args);
+ afputc('\n',stderr);
+ eflush();
+}
+
+#if has_prototypes
+ void
fatserror(char const *format,...)
#else
- /*VARARGS1*/ exiting void
+ /*VARARGS1*/ void
fatserror(format, va_alist) char const *format; va_dcl
#endif
-/* fatal syntax error */
+/* fatal RCS file syntax error */
{
va_list args;
oflush();
- VOID fprintf(stderr, "%s: %s:%lu: ", cmdid, RCSfilename, rcsline);
+ VOID fprintf(stderr, "%s: %s:%ld: ", cmdid, RCSname, rcsline);
vararg_start(args, format);
fvfprintf(stderr, format, args);
va_end(args);
@@ -1036,16 +1308,16 @@ fatserror(char const *format,...)
}
#if has_prototypes
- exiting void
+ void
faterror(char const *format,...)
#else
- /*VARARGS1*/ exiting void faterror(format, va_alist)
+ /*VARARGS1*/ void faterror(format, va_alist)
char const *format; va_dcl
#endif
/* fatal error, terminates program after cleanup */
{
va_list args;
- fatsay();
+ fatsay((char const*)0);
vararg_start(args, format);
fvfprintf(stderr, format, args);
va_end(args);
@@ -1054,20 +1326,76 @@ faterror(char const *format,...)
#if has_prototypes
void
-warn(char const *format,...)
+rcsfaterror(char const *format,...)
#else
- /*VARARGS1*/ void warn(format, va_alist) char const *format; va_dcl
+ /*VARARGS1*/ void rcsfaterror(format, va_alist)
+ char const *format; va_dcl
#endif
-/* prints a warning message */
+/* fatal RCS file error, terminates program after cleanup */
{
va_list args;
- oflush();
- aprintf(stderr,"%s warning: ",cmdid);
+ fatsay(RCSname);
vararg_start(args, format);
fvfprintf(stderr, format, args);
va_end(args);
- afputc('\n',stderr);
- eflush();
+ fatcleanup(false);
+}
+
+#if has_prototypes
+ void
+warn(char const *format,...)
+#else
+ /*VARARGS1*/ void warn(format, va_alist) char const *format; va_dcl
+#endif
+/* warning */
+{
+ va_list args;
+ if (!quietflag) {
+ warnsay((char *)0);
+ vararg_start(args, format);
+ fvfprintf(stderr, format, args);
+ va_end(args);
+ afputc('\n', stderr);
+ eflush();
+ }
+}
+
+#if has_prototypes
+ void
+rcswarn(char const *format,...)
+#else
+ /*VARARGS1*/ void rcswarn(format, va_alist) char const *format; va_dcl
+#endif
+/* RCS file warning */
+{
+ va_list args;
+ if (!quietflag) {
+ warnsay(RCSname);
+ vararg_start(args, format);
+ fvfprintf(stderr, format, args);
+ va_end(args);
+ afputc('\n', stderr);
+ eflush();
+ }
+}
+
+#if has_prototypes
+ void
+workwarn(char const *format,...)
+#else
+ /*VARARGS1*/ void workwarn(format, va_alist) char const *format; va_dcl
+#endif
+/* working file warning */
+{
+ va_list args;
+ if (!quietflag) {
+ warnsay(workname);
+ vararg_start(args, format);
+ fvfprintf(stderr, format, args);
+ va_end(args);
+ afputc('\n', stderr);
+ eflush();
+ }
}
void
@@ -1102,12 +1430,11 @@ diagnose(char const *format,...)
void
afputc(c, f)
-/* Function: afputc(c,f) acts like aputc(c,f), but is smaller and slower.
- */
+/* afputc(c,f); acts like aputc_(c,f) but is smaller and slower. */
int c;
register FILE *f;
{
- aputc(c,f);
+ aputc_(c,f)
}
@@ -1138,6 +1465,7 @@ fvfprintf(FILE *stream, char const *format, va_list args)
{
#if has_vfprintf
if (vfprintf(stream, format, args) < 0)
+ Oerror();
#else
# if has__doprintf
_doprintf(stream, format, args);
@@ -1153,8 +1481,8 @@ fvfprintf(FILE *stream, char const *format, va_list args)
# endif
# endif
if (ferror(stream))
-#endif
Oerror();
+#endif
}
#if has_prototypes
@@ -1235,7 +1563,7 @@ int argc; char * argv[];
exitmain(EXIT_SUCCESS);
}
-exiting void exiterr() { _exit(EXIT_FAILURE); }
+void exiterr() { _exit(EXIT_FAILURE); }
#endif
diff --git a/gnu/usr.bin/rcs/lib/rcsmap.c b/gnu/usr.bin/rcs/lib/rcsmap.c
index 0e7b23c..0345ef8 100644
--- a/gnu/usr.bin/rcs/lib/rcsmap.c
+++ b/gnu/usr.bin/rcs/lib/rcsmap.c
@@ -1,7 +1,7 @@
/* RCS map of character types */
/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+ Copyright 1990, 1991, 1995 by Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -17,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -28,7 +29,7 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(mapId, "$Id: rcsmap.c,v 5.2 1991/08/19 03:13:55 eggert Exp $")
+libId(mapId, "$Id: rcsmap.c,v 5.3 1995/06/16 06:19:24 eggert Exp $")
/* map of character types */
/* ISO 8859/1 (Latin-1) */
diff --git a/gnu/usr.bin/rcs/lib/rcsrev.c b/gnu/usr.bin/rcs/lib/rcsrev.c
index ce11f54..27b1747 100644
--- a/gnu/usr.bin/rcs/lib/rcsrev.c
+++ b/gnu/usr.bin/rcs/lib/rcsrev.c
@@ -1,9 +1,7 @@
-/*
- * RCS revision number handling
- */
+/* Handle RCS revision numbers. */
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -19,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -28,10 +27,32 @@ Report problems and direct all questions to:
*/
-
-
-
-/* $Log: rcsrev.c,v $
+/*
+ * $Log: rcsrev.c,v $
+ * Revision 5.10 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.9 1995/06/01 16:23:43 eggert
+ * (cmpdate, normalizeyear): New functions work around MKS RCS incompatibility.
+ * (cmpnum, compartial): s[d] -> *(s+d) to work around Cray compiler bug.
+ * (genrevs, genbranch): cmpnum -> cmpdate
+ *
+ * Revision 5.8 1994/03/17 14:05:48 eggert
+ * Remove lint.
+ *
+ * Revision 5.7 1993/11/09 17:40:15 eggert
+ * Fix format string typos.
+ *
+ * Revision 5.6 1993/11/03 17:42:27 eggert
+ * Revision number `.N' now stands for `D.N', where D is the default branch.
+ * Add -z. Improve quality of diagnostics. Add `namedrev' for Name support.
+ *
+ * Revision 5.5 1992/07/28 16:12:44 eggert
+ * Identifiers may now start with a digit. Avoid `unsigned'.
+ *
+ * Revision 5.4 1992/01/06 02:42:34 eggert
+ * while (E) ; -> while (E) continue;
+ *
* Revision 5.3 1991/08/19 03:13:55 eggert
* Add `-r$', `-rB.'. Remove botches like `<now>' from messages. Tune.
*
@@ -83,25 +104,21 @@ Report problems and direct all questions to:
* in that case.
*/
-
-
-/*
-#define REVTEST
-*/
-/* version REVTEST is for testing the routines that generate a sequence
- * of delta numbers needed to regenerate a given delta.
- */
-
#include "rcsbase.h"
-libId(revId, "$Id: rcsrev.c,v 5.3 1991/08/19 03:13:55 eggert Exp $")
+libId(revId, "$Id: rcsrev.c,v 5.10 1995/06/16 06:19:24 eggert Exp $")
static char const *branchtip P((char const*));
-static struct hshentry *genbranch P((struct hshentry const*,char const*,unsigned,char const*,char const*,char const*,struct hshentries**));
+static char const *lookupsym P((char const*));
+static char const *normalizeyear P((char const*,char[5]));
+static struct hshentry *genbranch P((struct hshentry const*,char const*,int,char const*,char const*,char const*,struct hshentries**));
+static void absent P((char const*,int));
+static void cantfindbranch P((char const*,char const[datesize],char const*,char const*));
+static void store1 P((struct hshentries***,struct hshentry*));
- unsigned
+ int
countnumflds(s)
char const *s;
/* Given a pointer s to a dotted number (date or revision number),
@@ -109,9 +126,9 @@ countnumflds(s)
*/
{
register char const *sp;
- register unsigned count;
- if ((sp=s)==nil) return(0);
- if (*sp == '\0') return(0);
+ register int count;
+ if (!(sp=s) || !*sp)
+ return 0;
count = 1;
do {
if (*sp++ == '.') count++;
@@ -123,12 +140,12 @@ countnumflds(s)
getbranchno(revno,branchno)
char const *revno;
struct buf *branchno;
-/* Given a non-nil revision number revno, getbranchno copies the number of the branch
+/* Given a revision number revno, getbranchno copies the number of the branch
* on which revno is into branchno. If revno itself is a branch number,
* it is copied unchanged.
*/
{
- register unsigned numflds;
+ register int numflds;
register char *tp;
bufscpy(branchno, revno);
@@ -137,7 +154,7 @@ getbranchno(revno,branchno)
tp = branchno->string;
while (--numflds)
while (*tp++ != '.')
- ;
+ continue;
*(tp-1)='\0';
}
}
@@ -156,8 +173,8 @@ int cmpnum(num1, num2)
register size_t d1, d2;
register int r;
- s1=num1==nil?"":num1;
- s2=num2==nil?"":num2;
+ s1 = num1 ? num1 : "";
+ s2 = num2 ? num2 : "";
for (;;) {
/* Give precedence to shorter one. */
@@ -167,8 +184,10 @@ int cmpnum(num1, num2)
return -1;
/* Strip leading zeros, then find number of digits. */
- while (*s1=='0') ++s1; for (d1=0; isdigit(s1[d1]); d1++) ;
- while (*s2=='0') ++s2; for (d2=0; isdigit(s2[d2]); d2++) ;
+ while (*s1=='0') ++s1;
+ while (*s2=='0') ++s2;
+ for (d1=0; isdigit(*(s1+d1)); d1++) continue;
+ for (d2=0; isdigit(*(s2+d2)); d2++) continue;
/* Do not convert to integer; it might overflow! */
if (d1 != d2)
@@ -188,7 +207,7 @@ int cmpnum(num1, num2)
int cmpnumfld(num1, num2, fld)
char const *num1, *num2;
- unsigned fld;
+ int fld;
/* Compare the two dotted numbers at field fld.
* num1 and num2 must have at least fld fields.
* fld must be positive.
@@ -202,25 +221,63 @@ int cmpnumfld(num1, num2, fld)
/* skip fld-1 fields */
while (--fld) {
while (*s1++ != '.')
- ;
+ continue;
while (*s2++ != '.')
- ;
+ continue;
}
/* Now s1 and s2 point to the beginning of the respective fields */
- while (*s1=='0') ++s1; for (d1=0; isdigit(s1[d1]); d1++) ;
- while (*s2=='0') ++s2; for (d2=0; isdigit(s2[d2]); d2++) ;
+ while (*s1=='0') ++s1; for (d1=0; isdigit(*(s1+d1)); d1++) continue;
+ while (*s2=='0') ++s2; for (d2=0; isdigit(*(s2+d2)); d2++) continue;
return d1<d2 ? -1 : d1==d2 ? memcmp(s1,s2,d1) : 1;
}
+ int
+cmpdate(d1, d2)
+ char const *d1, *d2;
+/*
+* Compare the two dates. This is just like cmpnum,
+* except that for compatibility with old versions of RCS,
+* 1900 is added to dates with two-digit years.
+*/
+{
+ char year1[5], year2[5];
+ int r = cmpnumfld(normalizeyear(d1,year1), normalizeyear(d2,year2), 1);
+
+ if (r)
+ return r;
+ else {
+ while (isdigit(*d1)) d1++; d1 += *d1=='.';
+ while (isdigit(*d2)) d2++; d2 += *d2=='.';
+ return cmpnum(d1, d2);
+ }
+}
+
+ static char const *
+normalizeyear(date, year)
+ char const *date;
+ char year[5];
+{
+ if (isdigit(date[0]) && isdigit(date[1]) && !isdigit(date[2])) {
+ year[0] = '1';
+ year[1] = '9';
+ year[2] = date[0];
+ year[3] = date[1];
+ year[4] = 0;
+ return year;
+ } else
+ return date;
+}
+
+
static void
cantfindbranch(revno, date, author, state)
char const *revno, date[datesize], *author, *state;
{
- char datebuf[datesize];
+ char datebuf[datesize + zonelenmax];
- error("No revision on branch %s has%s%s%s%s%s%s.",
+ rcserror("No revision on branch %s has%s%s%s%s%s%s.",
revno,
date ? " a date before " : "",
date ? date2str(date,datebuf) : "",
@@ -234,11 +291,11 @@ cantfindbranch(revno, date, author, state)
static void
absent(revno, field)
char const *revno;
- unsigned field;
+ int field;
{
struct buf t;
bufautobegin(&t);
- error("%s %s absent", field&1?"revision":"branch",
+ rcserror("%s %s absent", field&1?"revision":"branch",
partialno(&t,revno,field)
);
bufautoend(&t);
@@ -248,7 +305,7 @@ absent(revno, field)
int
compartial(num1, num2, length)
char const *num1, *num2;
- unsigned length;
+ int length;
/* compare the first "length" fields of two dot numbers;
the omitted field is considered to be larger than any number */
@@ -267,20 +324,21 @@ compartial(num1, num2, length)
if (!*s1) return 1;
if (!*s2) return -1;
- while (*s1=='0') ++s1; for (d1=0; isdigit(s1[d1]); d1++) ;
- while (*s2=='0') ++s2; for (d2=0; isdigit(s2[d2]); d2++) ;
+ while (*s1=='0') ++s1; for (d1=0; isdigit(*(s1+d1)); d1++) continue;
+ while (*s2=='0') ++s2; for (d2=0; isdigit(*(s2+d2)); d2++) continue;
if (d1 != d2)
return d1<d2 ? -1 : 1;
if ((r = memcmp(s1, s2, d1)))
return r;
+ if (!--length)
+ return 0;
+
s1 += d1;
s2 += d1;
if (*s1 == '.') s1++;
if (*s2 == '.') s2++;
-
- if ( --length == 0 ) return 0;
}
}
@@ -288,7 +346,7 @@ compartial(num1, num2, length)
char * partialno(rev1,rev2,length)
struct buf *rev1;
char const *rev2;
- register unsigned length;
+ register int length;
/* Function: Copies length fields of revision number rev2 into rev1.
* Return rev1's string.
*/
@@ -335,20 +393,20 @@ struct hshentry * genrevs(revno,date,author,state,store)
* revision given by revno, date, author, and state, and stores pointers
* to these deltas into a list whose starting address is given by store.
* The last delta (target delta) is returned.
- * If the proper delta could not be found, nil is returned.
+ * If the proper delta could not be found, 0 is returned.
*/
{
- unsigned length;
+ int length;
register struct hshentry * next;
int result;
char const *branchnum;
struct buf t;
- char datebuf[datesize];
+ char datebuf[datesize + zonelenmax];
bufautobegin(&t);
if (!(next = Head)) {
- error("RCS file empty");
+ rcserror("RCS file empty");
goto norev;
}
@@ -360,7 +418,7 @@ struct hshentry * genrevs(revno,date,author,state,store)
store1(&store, next);
next = next->next;
if (!next) {
- error("branch number %s too low", partialno(&t,revno,1));
+ rcserror("branch number %s too low", partialno(&t,revno,1));
goto norev;
}
}
@@ -373,19 +431,19 @@ struct hshentry * genrevs(revno,date,author,state,store)
if (length<=1){
/* pick latest one on given branch */
branchnum = next->num; /* works even for empty revno*/
- while ((next!=nil) &&
- (cmpnumfld(branchnum,next->num,1)==0) &&
- !(
- (date==nil?1:(cmpnum(date,next->date)>=0)) &&
- (author==nil?1:(strcmp(author,next->author)==0)) &&
- (state ==nil?1:(strcmp(state, next->state) ==0))
- )
- )
+ while (next &&
+ cmpnumfld(branchnum,next->num,1) == 0 &&
+ (
+ (date && cmpdate(date,next->date) < 0) ||
+ (author && strcmp(author,next->author) != 0) ||
+ (state && strcmp(state,next->state) != 0)
+ )
+ )
{
store1(&store, next);
next=next->next;
}
- if ((next==nil) ||
+ if (!next ||
(cmpnumfld(branchnum,next->num,1)!=0))/*overshot*/ {
cantfindbranch(
length ? revno : partialno(&t,branchnum,1),
@@ -395,7 +453,7 @@ struct hshentry * genrevs(revno,date,author,state,store)
} else {
store1(&store, next);
}
- *store = nil;
+ *store = 0;
return next;
}
@@ -409,8 +467,8 @@ struct hshentry * genrevs(revno,date,author,state,store)
break;
}
- if ((next==nil) || (cmpnumfld(revno,next->num,1)!=0)) {
- error("revision number %s too low", partialno(&t,revno,2));
+ if (!next || cmpnumfld(revno,next->num,1) != 0) {
+ rcserror("revision number %s too low", partialno(&t,revno,2));
goto norev;
}
if ((length>2) && (result!=0)) {
@@ -424,29 +482,33 @@ struct hshentry * genrevs(revno,date,author,state,store)
if (length>2)
return genbranch(next,revno,length,date,author,state,store);
else { /* length == 2*/
- if ((date!=nil) && (cmpnum(date,next->date)<0)){
- error("Revision %s has date %s.",
+ if (date && cmpdate(date,next->date)<0) {
+ rcserror("Revision %s has date %s.",
next->num,
date2str(next->date, datebuf)
);
- return nil;
- }
- if ((author!=nil)&&(strcmp(author,next->author)!=0)) {
- error("Revision %s has author %s.",next->num,next->author);
- return nil;
+ return 0;
+ }
+ if (author && strcmp(author,next->author)!=0) {
+ rcserror("Revision %s has author %s.",
+ next->num, next->author
+ );
+ return 0;
}
- if ((state!=nil)&&(strcmp(state,next->state)!=0)) {
- error("Revision %s has state %s.",next->num,
- next->state==nil?"<empty>":next->state);
- return nil;
+ if (state && strcmp(state,next->state)!=0) {
+ rcserror("Revision %s has state %s.",
+ next->num,
+ next->state ? next->state : "<empty>"
+ );
+ return 0;
}
- *store=nil;
+ *store = 0;
return next;
}
norev:
bufautoend(&t);
- return nil;
+ return 0;
}
@@ -456,7 +518,7 @@ struct hshentry * genrevs(revno,date,author,state,store)
genbranch(bpoint, revno, length, date, author, state, store)
struct hshentry const *bpoint;
char const *revno;
- unsigned length;
+ int length;
char const *date, *author, *state;
struct hshentries **store;
/* Function: given a branchpoint, a revision number, date, author, and state,
@@ -464,15 +526,15 @@ genbranch(bpoint, revno, length, date, author, state, store)
* from the branch point on.
* Pointers to the found deltas are stored in a list beginning with store.
* revno must be on a side branch.
- * return nil on error
+ * Return 0 on error.
*/
{
- unsigned field;
+ int field;
register struct hshentry * next, * trail;
register struct branchhead const *bhead;
int result;
struct buf t;
- char datebuf[datesize];
+ char datebuf[datesize + zonelenmax];
field = 3;
bhead = bpoint->branches;
@@ -480,9 +542,11 @@ genbranch(bpoint, revno, length, date, author, state, store)
do {
if (!bhead) {
bufautobegin(&t);
- error("no side branches present for %s", partialno(&t,revno,field-1));
+ rcserror("no side branches present for %s",
+ partialno(&t,revno,field-1)
+ );
bufautoend(&t);
- return nil;
+ return 0;
}
/*find branch head*/
@@ -491,31 +555,33 @@ genbranch(bpoint, revno, length, date, author, state, store)
bhead = bhead->nextbranch;
if (!bhead) {
bufautobegin(&t);
- error("branch number %s too high",partialno(&t,revno,field));
+ rcserror("branch number %s too high",
+ partialno(&t,revno,field)
+ );
bufautoend(&t);
- return nil;
+ return 0;
}
}
if (result<0) {
absent(revno, field);
- return nil;
+ return 0;
}
next = bhead->hsh;
if (length==field) {
/* pick latest one on that branch */
- trail=nil;
- do { if ((date==nil?1:(cmpnum(date,next->date)>=0)) &&
- (author==nil?1:(strcmp(author,next->author)==0)) &&
- (state ==nil?1:(strcmp(state, next->state) ==0))
+ trail = 0;
+ do { if ((!date || cmpdate(date,next->date)>=0) &&
+ (!author || strcmp(author,next->author)==0) &&
+ (!state || strcmp(state,next->state)==0)
) trail = next;
next=next->next;
- } while (next!=nil);
+ } while (next);
- if (trail==nil) {
+ if (!trail) {
cantfindbranch(revno, date, author, state);
- return nil;
+ return 0;
} else { /* print up to last one suitable */
next = bhead->hsh;
while (next!=trail) {
@@ -524,7 +590,7 @@ genbranch(bpoint, revno, length, date, author, state, store)
}
store1(&store, next);
}
- *store = nil;
+ *store = 0;
return next;
}
@@ -533,44 +599,49 @@ genbranch(bpoint, revno, length, date, author, state, store)
/* check low */
if (cmpnumfld(revno,next->num,field+1)<0) {
bufautobegin(&t);
- error("revision number %s too low", partialno(&t,revno,field+1));
+ rcserror("revision number %s too low",
+ partialno(&t,revno,field+1)
+ );
bufautoend(&t);
- return(nil);
+ return 0;
}
do {
store1(&store, next);
trail = next;
next = next->next;
- } while ((next!=nil) &&
- (cmpnumfld(revno,next->num,field+1) >=0));
+ } while (next && cmpnumfld(revno,next->num,field+1)>=0);
if ((length>field+1) && /*need exact hit */
(cmpnumfld(revno,trail->num,field+1) !=0)){
absent(revno, field+1);
- return(nil);
+ return 0;
}
if (length == field+1) {
- if ((date!=nil) && (cmpnum(date,trail->date)<0)){
- error("Revision %s has date %s.",
+ if (date && cmpdate(date,trail->date)<0) {
+ rcserror("Revision %s has date %s.",
trail->num,
date2str(trail->date, datebuf)
);
- return nil;
+ return 0;
}
- if ((author!=nil)&&(strcmp(author,trail->author)!=0)) {
- error("Revision %s has author %s.",trail->num,trail->author);
- return nil;
+ if (author && strcmp(author,trail->author)!=0) {
+ rcserror("Revision %s has author %s.",
+ trail->num, trail->author
+ );
+ return 0;
}
- if ((state!=nil)&&(strcmp(state,trail->state)!=0)) {
- error("Revision %s has state %s.",trail->num,
- trail->state==nil?"<empty>":trail->state);
- return nil;
+ if (state && strcmp(state,trail->state)!=0) {
+ rcserror("Revision %s has state %s.",
+ trail->num,
+ trail->state ? trail->state : "<empty>"
+ );
+ return 0;
}
}
bhead = trail->branches;
} while ((field+=2) <= length);
- * store = nil;
+ *store = 0;
return trail;
}
@@ -580,17 +651,14 @@ lookupsym(id)
char const *id;
/* Function: looks up id in the list of symbolic names starting
* with pointer SYMBOLS, and returns a pointer to the corresponding
- * revision number. Returns nil if not present.
+ * revision number. Return 0 if not present.
*/
{
register struct assoc const *next;
- next = Symbols;
- while (next!=nil) {
+ for (next = Symbols; next; next = next->nextassoc)
if (strcmp(id, next->symbol)==0)
return next->num;
- else next=next->nextassoc;
- }
- return nil;
+ return 0;
}
int expandsym(source, target)
@@ -617,13 +685,12 @@ fexpandsym(source, target, fp)
register char const *sp, *bp;
register char *tp;
char const *tlim;
- register enum tokens d;
- unsigned dots;
+ int dots;
sp = source;
bufalloc(target, 1);
tp = target->string;
- if (!sp || !*sp) { /*accept nil pointer as a legal value*/
+ if (!sp || !*sp) { /* Accept 0 pointer as a legal value. */
*tp='\0';
return true;
}
@@ -631,7 +698,7 @@ fexpandsym(source, target, fp)
if (!getoldkeys(fp))
return false;
if (!*prevrev.string) {
- error("working file lacks revision number");
+ workerror("working file lacks revision number");
return false;
}
bufscpy(target, prevrev.string);
@@ -641,72 +708,122 @@ fexpandsym(source, target, fp)
dots = 0;
for (;;) {
- switch (ctab[(unsigned char)*sp]) {
- case DIGIT:
- while (*sp=='0' && isdigit(sp[1]))
- /* skip leading zeroes */
- sp++;
- do {
- if (tlim <= tp)
- tp = bufenlarge(target, &tlim);
- } while (isdigit(*tp++ = *sp++));
- --sp;
- tp[-1] = '\0';
- break;
+ register char *p = tp;
+ size_t s = tp - target->string;
+ int id = false;
+ for (;;) {
+ switch (ctab[(unsigned char)*sp]) {
+ case IDCHAR:
+ case LETTER:
+ case Letter:
+ id = true;
+ /* fall into */
+ case DIGIT:
+ if (tlim <= p)
+ p = bufenlarge(target, &tlim);
+ *p++ = *sp++;
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ if (tlim <= p)
+ p = bufenlarge(target, &tlim);
+ *p = 0;
+ tp = target->string + s;
- case LETTER:
- case Letter:
- {
- register char *p = tp;
- register size_t s = tp - target->string;
- do {
- if (tlim <= p)
- p = bufenlarge(target, &tlim);
- *p++ = *sp++;
- } while ((d=ctab[(unsigned char)*sp])==LETTER ||
- d==Letter || d==DIGIT ||
- (d==IDCHAR));
- if (tlim <= p)
- p = bufenlarge(target, &tlim);
- *p = 0;
- tp = target->string + s;
- }
+ if (id) {
bp = lookupsym(tp);
- if (bp==nil) {
- error("Symbolic number %s is undefined.", tp);
+ if (!bp) {
+ rcserror("Symbolic name `%s' is undefined.",tp);
return false;
}
- do {
- if (tlim <= tp)
- tp = bufenlarge(target, &tlim);
- } while ((*tp++ = *bp++));
- break;
+ } else {
+ /* skip leading zeros */
+ for (bp = tp; *bp=='0' && isdigit(bp[1]); bp++)
+ continue;
+
+ if (!*bp)
+ if (s || *sp!='.')
+ break;
+ else {
+ /* Insert default branch before initial `.'. */
+ char const *b;
+ if (Dbranch)
+ b = Dbranch;
+ else if (Head)
+ b = Head->num;
+ else
+ break;
+ getbranchno(b, target);
+ bp = tp = target->string;
+ tlim = tp + target->size;
+ }
+ }
+
+ while ((*tp++ = *bp++))
+ if (tlim <= tp)
+ tp = bufenlarge(target, &tlim);
- default:
- goto improper;
- }
switch (*sp++) {
- case '\0': return true;
- case '.': break;
- default: goto improper;
- }
- if (!*sp) {
- if (dots & 1)
- goto improper;
- if (!(bp = branchtip(target->string)))
- return false;
- bufscpy(target, bp);
+ case '\0':
return true;
+
+ case '.':
+ if (!*sp) {
+ if (dots & 1)
+ break;
+ if (!(bp = branchtip(target->string)))
+ return false;
+ bufscpy(target, bp);
+ return true;
+ }
+ ++dots;
+ tp[-1] = '.';
+ continue;
}
- ++dots;
- tp[-1] = '.';
+ break;
}
- improper:
- error("improper revision number: %s", source);
+ rcserror("improper revision number: %s", source);
return false;
}
+ char const *
+namedrev(name, delta)
+ char const *name;
+ struct hshentry *delta;
+/* Yield NAME if it names DELTA, 0 otherwise. */
+{
+ if (name) {
+ char const *id = 0, *p, *val;
+ for (p = name; ; p++)
+ switch (ctab[(unsigned char)*p]) {
+ case IDCHAR:
+ case LETTER:
+ case Letter:
+ id = name;
+ break;
+
+ case DIGIT:
+ break;
+
+ case UNKN:
+ if (!*p && id &&
+ (val = lookupsym(id)) &&
+ strcmp(val, delta->num) == 0
+ )
+ return id;
+ /* fall into */
+ default:
+ return 0;
+ }
+ }
+ return 0;
+}
+
static char const *
branchtip(branch)
char const *branch;
@@ -728,6 +845,11 @@ tiprev()
#ifdef REVTEST
+/*
+* Test the routines that generate a sequence of delta numbers
+* needed to regenerate a given delta.
+*/
+
char const cmdid[] = "revtest";
int
@@ -772,9 +894,9 @@ int argc; char * argv[];
gets(author); aprintf(stderr,"%s; ",author);
aprintf(stderr,"State: ");
gets(state); aprintf(stderr, "%s;\n", state);
- target = genrevs(numricrevno.string, *date?date:(char *)nil, *author?author:(char *)nil,
- *state?state:(char*)nil, &gendeltas);
- if (target!=nil) {
+ target = genrevs(numricrevno.string, *date?date:(char *)0, *author?author:(char *)0,
+ *state?state:(char*)0, &gendeltas);
+ if (target) {
while (gendeltas) {
aprintf(stderr,"%s\n",gendeltas->first->num);
gendeltas = gendeltas->next;
@@ -785,6 +907,6 @@ int argc; char * argv[];
exitmain(EXIT_SUCCESS);
}
-exiting void exiterr() { _exit(EXIT_FAILURE); }
+void exiterr() { _exit(EXIT_FAILURE); }
#endif
diff --git a/gnu/usr.bin/rcs/lib/rcssyn.c b/gnu/usr.bin/rcs/lib/rcssyn.c
index 31086c2..f254bf7 100644
--- a/gnu/usr.bin/rcs/lib/rcssyn.c
+++ b/gnu/usr.bin/rcs/lib/rcssyn.c
@@ -1,16 +1,15 @@
-/*
- * RCS file input
- */
-/*********************************************************************************
+/* RCS file syntactic analysis */
+
+/******************************************************************************
* Syntax Analysis.
* Keyword table
* Testprogram: define SYNTEST
* Compatibility with Release 2: define COMPAT2=1
- *********************************************************************************
+ ******************************************************************************
*/
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -26,8 +25,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -35,8 +35,32 @@ Report problems and direct all questions to:
*/
-
-/* $Log: rcssyn.c,v $
+/*
+ * $Log: rcssyn.c,v $
+ * Revision 5.15 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.14 1995/06/01 16:23:43 eggert
+ * (expand_names): Add "b" for -kb.
+ * (getdelta): Don't strip leading "19" from MKS RCS dates; see cmpdate.
+ *
+ * Revision 5.13 1994/03/20 04:52:58 eggert
+ * Remove lint.
+ *
+ * Revision 5.12 1993/11/03 17:42:27 eggert
+ * Parse MKS RCS dates; ignore \r in diff control lines.
+ * Don't discard ignored phrases. Improve quality of diagnostics.
+ *
+ * Revision 5.11 1992/07/28 16:12:44 eggert
+ * Avoid `unsigned'. Statement macro names now end in _.
+ *
+ * Revision 5.10 1992/01/24 18:44:19 eggert
+ * Move put routines to rcsgen.c.
+ *
+ * Revision 5.9 1992/01/06 02:42:34 eggert
+ * ULONG_MAX/10 -> ULONG_MAX_OVER_10
+ * while (E) ; -> while (E) continue;
+ *
* Revision 5.8 1991/08/19 03:13:55 eggert
* Tune.
*
@@ -127,54 +151,55 @@ Report problems and direct all questions to:
* generates files of release 3 format. Need not be defined if no
* old RCS files generated with release 2 exist.
*/
-/* version SYNTEST inputs a RCS file and then prints out its internal
- * data structures.
-*/
#include "rcsbase.h"
-libId(synId, "$Id: rcssyn.c,v 5.8 1991/08/19 03:13:55 eggert Exp $")
+libId(synId, "$Id: rcssyn.c,v 5.15 1995/06/16 06:19:24 eggert Exp $")
-/* forward */
static char const *getkeyval P((char const*,enum tokens,int));
+static int getdelta P((void));
static int strn2expmode P((char const*,size_t));
+static struct hshentry *getdnum P((void));
+static void badDiffOutput P((char const*)) exiting;
+static void diffLineNumberTooLarge P((char const*)) exiting;
+static void getsemi P((char const*));
/* keyword table */
char const
- Kdesc[] = "desc",
- Klog[] = "log",
- Ktext[] = "text";
-
-static char const
Kaccess[] = "access",
Kauthor[] = "author",
Kbranch[] = "branch",
- K_branches[]= "branches",
Kcomment[] = "comment",
Kdate[] = "date",
+ Kdesc[] = "desc",
Kexpand[] = "expand",
Khead[] = "head",
Klocks[] = "locks",
+ Klog[] = "log",
Knext[] = "next",
Kstate[] = "state",
Kstrict[] = "strict",
+ Ksymbols[] = "symbols",
+ Ktext[] = "text";
+
+static char const
#if COMPAT2
Ksuffix[] = "suffix",
#endif
- Ksymbols[] = "symbols";
+ K_branches[]= "branches";
static struct buf Commleader;
-static struct cbuf Ignored;
struct cbuf Comment;
+struct cbuf Ignored;
struct access * AccessList;
struct assoc * Symbols;
-struct lock * Locks;
+struct rcslock *Locks;
int Expand;
int StrictLocks;
struct hshentry * Head;
char const * Dbranch;
-unsigned TotalDeltas;
+int TotalDeltas;
static void
@@ -204,11 +229,11 @@ getadmin()
register char const *id;
struct access * newaccess;
struct assoc * newassoc;
- struct lock * newlock;
+ struct rcslock *newlock;
struct hshentry * delta;
struct access **LastAccess;
struct assoc **LastSymbol;
- struct lock **LastLock;
+ struct rcslock **LastLock;
struct buf b;
struct cbuf cb;
@@ -218,7 +243,7 @@ getadmin()
Head = getdnum();
getsemi(Khead);
- Dbranch = nil;
+ Dbranch = 0;
if (getkeyopt(Kbranch)) {
if ((delta = getnum()))
Dbranch = delta->num;
@@ -240,18 +265,18 @@ getadmin()
getkey(Kaccess);
LastAccess = &AccessList;
- while (id=getid()) {
+ while ((id = getid())) {
newaccess = ftalloc(struct access);
newaccess->login = id;
*LastAccess = newaccess;
LastAccess = &newaccess->nextaccess;
}
- *LastAccess = nil;
+ *LastAccess = 0;
getsemi(Kaccess);
getkey(Ksymbols);
LastSymbol = &Symbols;
- while (id = getid()) {
+ while ((id = getid())) {
if (!getlex(COLON))
fatserror("missing ':' in symbolic name definition");
if (!(delta=getnum())) {
@@ -264,31 +289,31 @@ getadmin()
LastSymbol = &newassoc->nextassoc;
}
}
- *LastSymbol = nil;
+ *LastSymbol = 0;
getsemi(Ksymbols);
getkey(Klocks);
LastLock = &Locks;
- while (id = getid()) {
+ while ((id = getid())) {
if (!getlex(COLON))
fatserror("missing ':' in lock");
if (!(delta=getdnum())) {
fatserror("missing number in lock");
} else { /*add new pair to lock list*/
- newlock = ftalloc(struct lock);
+ newlock = ftalloc(struct rcslock);
newlock->login=id;
newlock->delta=delta;
*LastLock = newlock;
LastLock = &newlock->nextlock;
}
}
- *LastLock = nil;
+ *LastLock = 0;
getsemi(Klocks);
if ((StrictLocks = getkeyopt(Kstrict)))
getsemi(Kstrict);
- Comment.size = 0;
+ clear_buf(&Comment);
if (getkeyopt(Kcomment)) {
if (nexttok==STRING) {
Comment = savestring(&Commleader);
@@ -316,7 +341,7 @@ getadmin()
char const *const expand_names[] = {
/* These must agree with *_EXPAND in rcsbase.h. */
- "kv","kvl","k","v","o",
+ "kv", "kvl", "k", "v", "o", "b",
0
};
@@ -343,20 +368,30 @@ strn2expmode(s, n)
void
-ignorephrase()
-/* Ignore a phrase introduced by a later version of RCS. */
+ignorephrases(key)
+ const char *key;
+/*
+* Ignore a series of phrases that do not start with KEY.
+* Stop when the next phrase starts with a token that is not an identifier,
+* or is KEY.
+*/
{
- warnignore();
- hshenter=false;
for (;;) {
- switch (nexttok) {
- case SEMI: hshenter=true; nextlex(); return;
- case ID:
- case NUM: ffree1(NextString); break;
- case STRING: readstring(); break;
- default: break;
- }
- nextlex();
+ nextlex();
+ if (nexttok != ID || strcmp(NextString,key) == 0)
+ break;
+ warnignore();
+ hshenter=false;
+ for (;; nextlex()) {
+ switch (nexttok) {
+ case SEMI: hshenter=true; break;
+ case ID:
+ case NUM: ffree1(NextString); continue;
+ case STRING: readstring(); continue;
+ default: continue;
+ }
+ break;
+ }
}
}
@@ -374,7 +409,7 @@ getdelta()
return false;
hshenter = false; /*Don't enter dates into hashtable*/
- Delta->date = getkeyval(Kdate, NUM, false);
+ Delta->date = getkeyval(Kdate, NUM, false);
hshenter=true; /*reset hshenter for revision numbers.*/
Delta->author = getkeyval(Kauthor, ID, false);
@@ -389,13 +424,13 @@ getdelta()
*LastBranch = NewBranch;
LastBranch = &NewBranch->nextbranch;
}
- *LastBranch = nil;
+ *LastBranch = 0;
getsemi(K_branches);
getkey(Knext);
Delta->next = num = getdnum();
getsemi(Knext);
- Delta->lockedby = nil;
+ Delta->lockedby = 0;
Delta->log.string = 0;
Delta->selector = true;
Delta->ig = getphrases(Kdesc);
@@ -410,9 +445,10 @@ gettree()
* updates the lockedby fields.
*/
{
- struct lock const *currlock;
+ struct rcslock const *currlock;
- while (getdelta());
+ while (getdelta())
+ continue;
currlock=Locks;
while (currlock) {
currlock->delta->lockedby = currlock->login;
@@ -453,7 +489,7 @@ getkeyval(keyword, token, optional)
* the actual character string of <id> or <num> is returned.
*/
{
- register char const *val = nil;
+ register char const *val = 0;
getkey(keyword);
if (nexttok==token) {
@@ -468,220 +504,10 @@ getkeyval(keyword, token, optional)
}
-
-
- void
-putadmin(fout)
-register FILE * fout;
-/* Function: Print the <admin> node read with getadmin() to file fout.
- * Assumption: Variables AccessList, Symbols, Locks, StrictLocks,
- * and Head have been set.
- */
-{
- struct assoc const *curassoc;
- struct lock const *curlock;
- struct access const *curaccess;
-
- aprintf(fout, "%s\t%s;\n", Khead, Head?Head->num:"");
- if (Dbranch && VERSION(4)<=RCSversion)
- aprintf(fout, "%s\t%s;\n", Kbranch, Dbranch);
-
- aputs(Kaccess, fout);
- curaccess = AccessList;
- while (curaccess) {
- aprintf(fout, "\n\t%s", curaccess->login);
- curaccess = curaccess->nextaccess;
- }
- aprintf(fout, ";\n%s", Ksymbols);
- curassoc = Symbols;
- while (curassoc) {
- aprintf(fout, "\n\t%s:%s", curassoc->symbol, curassoc->num);
- curassoc = curassoc->nextassoc;
- }
- aprintf(fout, ";\n%s", Klocks);
- curlock = Locks;
- while (curlock) {
- aprintf(fout, "\n\t%s:%s", curlock->login, curlock->delta->num);
- curlock = curlock->nextlock;
- }
- if (StrictLocks) aprintf(fout, "; %s", Kstrict);
- aprintf(fout, ";\n");
- if (Comment.size) {
- aprintf(fout, "%s\t", Kcomment);
- putstring(fout, true, Comment, false);
- aprintf(fout, ";\n");
- }
- if (Expand != KEYVAL_EXPAND)
- aprintf(fout, "%s\t%c%s%c;\n",
- Kexpand, SDELIM, expand_names[Expand], SDELIM
- );
- awrite(Ignored.string, Ignored.size, fout);
- aputc('\n', fout);
-}
-
-
-
-
- static void
-putdelta(node,fout)
-register struct hshentry const *node;
-register FILE * fout;
-/* Function: prints a <delta> node to fout;
- */
-{
- struct branchhead const *nextbranch;
-
- if (node == nil) return;
-
- aprintf(fout, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches",
- node->num,
- Kdate, node->date,
- Kauthor, node->author,
- Kstate, node->state?node->state:""
- );
- nextbranch = node->branches;
- while (nextbranch) {
- aprintf(fout, "\n\t%s", nextbranch->hsh->num);
- nextbranch = nextbranch->nextbranch;
- }
-
- aprintf(fout, ";\n%s\t%s;\n", Knext, node->next?node->next->num:"");
- awrite(node->ig.string, node->ig.size, fout);
-}
-
-
-
-
void
-puttree(root,fout)
-struct hshentry const *root;
-register FILE * fout;
-/* Function: prints the delta tree in preorder to fout, starting with root.
- */
-{
- struct branchhead const *nextbranch;
-
- if (root==nil) return;
-
- if (root->selector)
- putdelta(root,fout);
-
- puttree(root->next,fout);
-
- nextbranch = root->branches;
- while (nextbranch) {
- puttree(nextbranch->hsh,fout);
- nextbranch = nextbranch->nextbranch;
- }
-}
-
-
- static exiting void
unexpected_EOF()
{
- faterror("unexpected EOF in diff output");
-}
-
-int putdtext(num,log,srcfilename,fout,diffmt)
- char const *num, *srcfilename;
- struct cbuf log;
- FILE *fout;
- int diffmt;
-/* Function: write a deltatext-node to fout.
- * num points to the deltanumber, log to the logmessage, and
- * sourcefile contains the text. Doubles up all SDELIMs in both the
- * log and the text; Makes sure the log message ends in \n.
- * returns false on error.
- * If diffmt is true, also checks that text is valid diff -n output.
- */
-{
- RILE *fin;
- int result;
- if (!(fin = Iopen(srcfilename, "r", (struct stat*)0))) {
- eerror(srcfilename);
- return false;
- }
- result = putdftext(num,log,fin,fout,diffmt);
- Ifclose(fin);
- return result;
-}
-
- void
-putstring(out, delim, s, log)
- register FILE *out;
- struct cbuf s;
- int delim, log;
-/*
- * Output to OUT one SDELIM if DELIM, then the string S with SDELIMs doubled.
- * If LOG is set then S is a log string; append a newline if S is nonempty.
- */
-{
- register char const *sp;
- register size_t ss;
-
- if (delim)
- aputc(SDELIM, out);
- sp = s.string;
- for (ss = s.size; ss; --ss) {
- if (*sp == SDELIM)
- aputc(SDELIM, out);
- aputc(*sp++, out);
- }
- if (s.size && log)
- aputc('\n', out);
- aputc(SDELIM, out);
-}
-
- int
-putdftext(num,log,finfile,foutfile,diffmt)
- char const *num;
- struct cbuf log;
- RILE *finfile;
- FILE *foutfile;
- int diffmt;
-/* like putdtext(), except the source file is already open */
-{
- declarecache;
- register FILE *fout;
- register int c;
- register RILE *fin;
- int ed;
- struct diffcmd dc;
-
- fout = foutfile;
- aprintf(fout,DELNUMFORM,num,Klog);
- /* put log */
- putstring(fout, true, log, true);
- /* put text */
- aprintf(fout, "\n%s\n%c", Ktext, SDELIM);
- fin = finfile;
- setupcache(fin);
- if (!diffmt) {
- /* Copy the file */
- cache(fin);
- for (;;) {
- cachegeteof(c, break;);
- if (c==SDELIM) aputc(SDELIM,fout); /*double up SDELIM*/
- aputc(c,fout);
- }
- } else {
- initdiffcmd(&dc);
- while (0 <= (ed = getdiffcmd(fin,false,fout,&dc)))
- if (ed) {
- cache(fin);
- while (dc.nlines--)
- do {
- cachegeteof(c, { if (!dc.nlines) goto OK_EOF; unexpected_EOF(); });
- if (c == SDELIM)
- aputc(SDELIM,fout);
- aputc(c,fout);
- } while (c != '\n');
- uncache(fin);
- }
- }
- OK_EOF:
- aprintf(fout, "%c\n", SDELIM);
- return true;
+ rcsfaterror("unexpected EOF in diff output");
}
void
@@ -693,18 +519,18 @@ initdiffcmd(dc)
dc->dafter = 0;
}
- static exiting void
+ static void
badDiffOutput(buf)
char const *buf;
{
- faterror("bad diff output line: %s", buf);
+ rcsfaterror("bad diff output line: %s", buf);
}
- static exiting void
+ static void
diffLineNumberTooLarge(buf)
char const *buf;
{
- faterror("diff line number too large: %s", buf);
+ rcsfaterror("diff line number too large: %s", buf);
}
int
@@ -726,16 +552,16 @@ getdiffcmd(finfile, delimiter, foutfile, dc)
register FILE *fout;
register char *p;
register RILE *fin;
- unsigned long line1, nlines, t;
+ long line1, nlines, t;
char buf[BUFSIZ];
fin = finfile;
fout = foutfile;
setupcache(fin); cache(fin);
- cachegeteof(c, { if (delimiter) unexpected_EOF(); return -1; } );
+ cachegeteof_(c, { if (delimiter) unexpected_EOF(); return -1; } )
if (delimiter) {
if (c==SDELIM) {
- cacheget(c);
+ cacheget_(c)
if (c==SDELIM) {
buf[0] = c;
buf[1] = 0;
@@ -751,23 +577,22 @@ getdiffcmd(finfile, delimiter, foutfile, dc)
p = buf;
do {
if (buf+BUFSIZ-2 <= p) {
- faterror("diff output command line too long");
+ rcsfaterror("diff output command line too long");
}
*p++ = c;
- cachegeteof(c, unexpected_EOF();) ;
+ cachegeteof_(c, unexpected_EOF();)
} while (c != '\n');
uncache(fin);
if (delimiter)
++rcsline;
*p = '\0';
for (p = buf+1; (c = *p++) == ' '; )
- ;
+ continue;
line1 = 0;
while (isdigit(c)) {
- t = line1 * 10;
if (
- ULONG_MAX/10 < line1 ||
- (line1 = t + (c - '0')) < t
+ LONG_MAX/10 < line1 ||
+ (t = line1 * 10, (line1 = t + (c - '0')) < t)
)
diffLineNumberTooLarge(buf);
c = *p++;
@@ -776,14 +601,15 @@ getdiffcmd(finfile, delimiter, foutfile, dc)
c = *p++;
nlines = 0;
while (isdigit(c)) {
- t = nlines * 10;
if (
- ULONG_MAX/10 < nlines ||
- (nlines = t + (c - '0')) < t
+ LONG_MAX/10 < nlines ||
+ (t = nlines * 10, (nlines = t + (c - '0')) < t)
)
diffLineNumberTooLarge(buf);
c = *p++;
}
+ if (c == '\r')
+ c = *p++;
if (c || !nlines) {
badDiffOutput(buf);
}
@@ -792,13 +618,13 @@ getdiffcmd(finfile, delimiter, foutfile, dc)
switch (buf[0]) {
case 'a':
if (line1 < dc->adprev) {
- faterror("backward insertion in diff output: %s", buf);
+ rcsfaterror("backward insertion in diff output: %s", buf);
}
dc->adprev = line1 + 1;
break;
case 'd':
if (line1 < dc->adprev || line1 < dc->dafter) {
- faterror("backward deletion in diff output: %s", buf);
+ rcsfaterror("backward deletion in diff output: %s", buf);
}
dc->adprev = line1;
dc->dafter = line1 + nlines;
@@ -818,6 +644,8 @@ getdiffcmd(finfile, delimiter, foutfile, dc)
#ifdef SYNTEST
+/* Input an RCS file and print its internal data structures. */
+
char const cmdid[] = "syntest";
int
@@ -834,10 +662,10 @@ int argc; char * argv[];
}
Lexinit();
getadmin();
- putadmin(stdout);
+ fdlock = STDOUT_FILENO;
+ putadmin();
gettree();
- puttree(Head,stdout);
getdesc(true);
@@ -849,9 +677,6 @@ int argc; char * argv[];
exitmain(EXIT_SUCCESS);
}
-
-exiting void exiterr() { _exit(EXIT_FAILURE); }
-
+void exiterr() { _exit(EXIT_FAILURE); }
#endif
-
diff --git a/gnu/usr.bin/rcs/lib/rcstime.c b/gnu/usr.bin/rcs/lib/rcstime.c
new file mode 100644
index 0000000..a49a857
--- /dev/null
+++ b/gnu/usr.bin/rcs/lib/rcstime.c
@@ -0,0 +1,191 @@
+/* Convert between RCS time format and Posix and/or C formats. */
+
+/* Copyright 1992, 1993, 1994, 1995 Paul Eggert
+ Distributed under license by the Free Software Foundation, Inc.
+
+This file is part of RCS.
+
+RCS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+RCS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Report problems and direct all questions to:
+
+ rcs-bugs@cs.purdue.edu
+
+*/
+
+#include "rcsbase.h"
+#include "partime.h"
+#include "maketime.h"
+
+libId(rcstimeId, "$Id: rcstime.c,v 1.4 1995/06/16 06:19:24 eggert Exp $")
+
+static long zone_offset; /* seconds east of UTC, or TM_LOCAL_ZONE */
+static int use_zone_offset; /* if zero, use UTC without zone indication */
+
+/*
+* Convert Unix time to RCS format.
+* For compatibility with older versions of RCS,
+* dates from 1900 through 1999 are stored without the leading "19".
+*/
+ void
+time2date(unixtime,date)
+ time_t unixtime;
+ char date[datesize];
+{
+ register struct tm const *tm = time2tm(unixtime, RCSversion<VERSION(5));
+ VOID sprintf(date,
+# if has_printf_dot
+ "%.2d.%.2d.%.2d.%.2d.%.2d.%.2d",
+# else
+ "%02d.%02d.%02d.%02d.%02d.%02d",
+# endif
+ tm->tm_year + ((unsigned)tm->tm_year < 100 ? 0 : 1900),
+ tm->tm_mon+1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec
+ );
+}
+
+/* Like str2time, except die if an error was found. */
+static time_t str2time_checked P((char const*,time_t,long));
+ static time_t
+str2time_checked(source, default_time, default_zone)
+ char const *source;
+ time_t default_time;
+ long default_zone;
+{
+ time_t t = str2time(source, default_time, default_zone);
+ if (t == -1)
+ faterror("unknown date/time: %s", source);
+ return t;
+}
+
+/*
+* Parse a free-format date in SOURCE, convert it
+* into RCS internal format, and store the result into TARGET.
+*/
+ void
+str2date(source, target)
+ char const *source;
+ char target[datesize];
+{
+ time2date(
+ str2time_checked(source, now(),
+ use_zone_offset ? zone_offset
+ : RCSversion<VERSION(5) ? TM_LOCAL_ZONE
+ : 0
+ ),
+ target
+ );
+}
+
+/* Convert an RCS internal format date to time_t. */
+ time_t
+date2time(source)
+ char const source[datesize];
+{
+ char s[datesize + zonelenmax];
+ return str2time_checked(date2str(source, s), (time_t)0, 0);
+}
+
+
+/* Set the time zone for date2str output. */
+ void
+zone_set(s)
+ char const *s;
+{
+ if ((use_zone_offset = *s)) {
+ long zone;
+ char const *zonetail = parzone(s, &zone);
+ if (!zonetail || *zonetail)
+ error("%s: not a known time zone", s);
+ else
+ zone_offset = zone;
+ }
+}
+
+
+/*
+* Format a user-readable form of the RCS format DATE into the buffer DATEBUF.
+* Yield DATEBUF.
+*/
+ char const *
+date2str(date, datebuf)
+ char const date[datesize];
+ char datebuf[datesize + zonelenmax];
+{
+ register char const *p = date;
+
+ while (*p++ != '.')
+ continue;
+ if (!use_zone_offset)
+ VOID sprintf(datebuf,
+ "19%.*s/%.2s/%.2s %.2s:%.2s:%s"
+ + (date[2]=='.' && VERSION(5)<=RCSversion ? 0 : 2),
+ (int)(p-date-1), date,
+ p, p+3, p+6, p+9, p+12
+ );
+ else {
+ struct tm t;
+ struct tm const *z;
+ int non_hour;
+ long zone;
+ char c;
+
+ t.tm_year = atoi(date) - (date[2]=='.' ? 0 : 1900);
+ t.tm_mon = atoi(p) - 1;
+ t.tm_mday = atoi(p+3);
+ t.tm_hour = atoi(p+6);
+ t.tm_min = atoi(p+9);
+ t.tm_sec = atoi(p+12);
+ t.tm_wday = -1;
+ zone = zone_offset;
+ if (zone == TM_LOCAL_ZONE) {
+ time_t u = tm2time(&t, 0), d;
+ z = localtime(&u);
+ d = difftm(z, &t);
+ zone = (time_t)-1 < 0 || d < -d ? d : -(long)-d;
+ } else {
+ adjzone(&t, zone);
+ z = &t;
+ }
+ c = '+';
+ if (zone < 0) {
+ zone = -zone;
+ c = '-';
+ }
+ VOID sprintf(datebuf,
+# if has_printf_dot
+ "%.2d-%.2d-%.2d %.2d:%.2d:%.2d%c%.2d",
+# else
+ "%02d-%02d-%02d %02d:%02d:%02d%c%02d",
+# endif
+ z->tm_year + 1900,
+ z->tm_mon + 1, z->tm_mday, z->tm_hour, z->tm_min, z->tm_sec,
+ c, (int) (zone / (60*60))
+ );
+ if ((non_hour = zone % (60*60))) {
+# if has_printf_dot
+ static char const fmt[] = ":%.2d";
+# else
+ static char const fmt[] = ":%02d";
+# endif
+ VOID sprintf(datebuf + strlen(datebuf), fmt, non_hour / 60);
+ if ((non_hour %= 60))
+ VOID sprintf(datebuf + strlen(datebuf), fmt, non_hour);
+ }
+ }
+ return datebuf;
+}
diff --git a/gnu/usr.bin/rcs/lib/rcsutil.c b/gnu/usr.bin/rcs/lib/rcsutil.c
index c523ccf1..d226ff4 100644
--- a/gnu/usr.bin/rcs/lib/rcsutil.c
+++ b/gnu/usr.bin/rcs/lib/rcsutil.c
@@ -1,9 +1,7 @@
-/*
- * RCS utilities
- */
+/* RCS utility functions */
-/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- Copyright 1990, 1991 by Paul Eggert
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
@@ -19,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with RCS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+along with RCS; see the file COPYING.
+If not, write to the Free Software Foundation,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Report problems and direct all questions to:
@@ -31,7 +30,59 @@ Report problems and direct all questions to:
-/* $Log: rcsutil.c,v $
+/*
+ * $Log: rcsutil.c,v $
+ * Revision 5.20 1995/06/16 06:19:24 eggert
+ * (catchsig): Remove `return'.
+ * Update FSF address.
+ *
+ * Revision 5.19 1995/06/02 18:19:00 eggert
+ * (catchsigaction): New name for `catchsig', for sa_sigaction signature.
+ * Use nRCS even if !has_psiginfo, to remove unused variable warning.
+ * (setup_catchsig): Use sa_sigaction only if has_sa_sigaction.
+ * Use ENOTSUP only if defined.
+ *
+ * Revision 5.18 1995/06/01 16:23:43 eggert
+ * (catchsig, restoreints, setup_catchsig): Use SA_SIGINFO, not has_psiginfo,
+ * to determine whether to use SA_SIGINFO feature,
+ * but also check at runtime whether the feature works.
+ * (catchsig): If an mmap_signal occurs, report the affected file name.
+ * (unsupported_SA_SIGINFO, accessName): New variables.
+ * (setup_catchsig): If using SA_SIGINFO, use sa_sigaction, not sa_handler.
+ * If SA_SIGINFO fails, fall back on sa_handler method.
+ *
+ * (readAccessFilenameBuffer, dupSafer, fdSafer, fopenSafer): New functions.
+ * (concatenate): Remove.
+ *
+ * (runv): Work around bad_wait_if_SIGCHLD_ignored bug.
+ * Remove reference to OPEN_O_WORK.
+ *
+ * Revision 5.17 1994/03/20 04:52:58 eggert
+ * Specify subprocess input via file descriptor, not file name.
+ * Avoid messing with I/O buffers in the child process.
+ * Define dup in terms of F_DUPFD if it exists.
+ * Move setmtime to rcsedit.c. Remove lint.
+ *
+ * Revision 5.16 1993/11/09 17:40:15 eggert
+ * -V now prints version on stdout and exits.
+ *
+ * Revision 5.15 1993/11/03 17:42:27 eggert
+ * Use psiginfo and setreuid if available. Move date2str to maketime.c.
+ *
+ * Revision 5.14 1992/07/28 16:12:44 eggert
+ * Add -V. has_sigaction overrides sig_zaps_handler. Fix -M bug.
+ * Add mmap_signal, which minimizes signal handling for non-mmap hosts.
+ *
+ * Revision 5.13 1992/02/17 23:02:28 eggert
+ * Work around NFS mmap SIGBUS problem. Add -T support.
+ *
+ * Revision 5.12 1992/01/24 18:44:19 eggert
+ * Work around NFS mmap bug that leads to SIGBUS core dumps. lint -> RCS_lint
+ *
+ * Revision 5.11 1992/01/06 02:42:34 eggert
+ * O_BINARY -> OPEN_O_WORK
+ * while (E) ; -> while (E) continue;
+ *
* Revision 5.10 1991/10/07 17:32:46 eggert
* Support piece tables even if !has_mmap.
*
@@ -136,7 +187,7 @@ Report problems and direct all questions to:
#include "rcsbase.h"
-libId(utilId, "$Id: rcsutil.c,v 5.10 1991/10/07 17:32:46 eggert Exp $")
+libId(utilId, "$Id: rcsutil.c,v 5.20 1995/06/16 06:19:24 eggert Exp $")
#if !has_memcmp
int
@@ -170,7 +221,7 @@ memcpy(s1, s2, n)
}
#endif
-#if lint
+#if RCS_lint
malloc_type lintalloc;
#endif
@@ -187,6 +238,7 @@ struct alloclist {
static struct alloclist *alloced;
+ static malloc_type okalloc P((malloc_type));
static malloc_type
okalloc(p)
malloc_type p;
@@ -242,7 +294,7 @@ ffree()
tfree(p->alloc);
tfree(p);
}
- alloced = nil;
+ alloced = 0;
}
void
@@ -297,16 +349,18 @@ getusername(suspicious)
/* Prefer getenv() unless suspicious; it's much faster. */
# if getlogin_is_secure
(suspicious
- ||
- !(name = cgetenv("LOGNAME"))
- && !(name = cgetenv("USER")))
+ || (
+ !(name = cgetenv("LOGNAME"))
+ && !(name = cgetenv("USER"))
+ ))
&& !(name = getlogin())
# else
suspicious
- ||
+ || (
!(name = cgetenv("LOGNAME"))
&& !(name = cgetenv("USER"))
&& !(name = getlogin())
+ )
# endif
) {
#if has_getuid && has_getpwuid
@@ -320,7 +374,7 @@ getusername(suspicious)
#if has_setuid
faterror("setuid not supported");
#else
- faterror("Who are you? Please set LOGNAME.");
+ faterror("Who are you? Please setenv LOGNAME.");
#endif
#endif
}
@@ -343,65 +397,191 @@ getusername(suspicious)
*/
static sig_atomic_t volatile heldsignal, holdlevel;
+#ifdef SA_SIGINFO
+ static int unsupported_SA_SIGINFO;
+ static siginfo_t bufsiginfo;
+ static siginfo_t *volatile heldsiginfo;
+#endif
- static signal_type
-catchsig(s)
- int s;
-{
- char const *sname;
- char buf[BUFSIZ];
-#if sig_zaps_handler
- /* If a signal arrives before we reset the signal handler, we lose. */
- VOID signal(s, SIG_IGN);
-#endif
- if (holdlevel) {
- heldsignal = s;
- return;
- }
- ignoreints();
- setrid();
- if (!quietflag) {
- sname = nil;
-#if has_sys_siglist && defined(NSIG)
- if ((unsigned)s < NSIG) {
-# ifndef sys_siglist
- extern char const *sys_siglist[];
-# endif
- sname = sys_siglist[s];
- }
+#if has_NFS && has_mmap && large_memory && mmap_signal
+ static char const *accessName;
+
+ void
+ readAccessFilenameBuffer(filename, p)
+ char const *filename;
+ unsigned char const *p;
+ {
+ unsigned char volatile t;
+ accessName = filename;
+ t = *p;
+ accessName = 0;
+ }
#else
- switch (s) {
-#ifdef SIGHUP
- case SIGHUP: sname = "Hangup"; break;
+# define accessName ((char const *) 0)
#endif
-#ifdef SIGINT
+
+
+#if !has_psignal
+
+# define psignal my_psignal
+ static void my_psignal P((int,char const*));
+ static void
+my_psignal(sig, s)
+ int sig;
+ char const *s;
+{
+ char const *sname = "Unknown signal";
+# if has_sys_siglist && defined(NSIG)
+ if ((unsigned)sig < NSIG)
+ sname = sys_siglist[sig];
+# else
+ switch (sig) {
+# ifdef SIGHUP
+ case SIGHUP: sname = "Hangup"; break;
+# endif
+# ifdef SIGINT
case SIGINT: sname = "Interrupt"; break;
-#endif
-#ifdef SIGPIPE
+# endif
+# ifdef SIGPIPE
case SIGPIPE: sname = "Broken pipe"; break;
-#endif
-#ifdef SIGQUIT
+# endif
+# ifdef SIGQUIT
case SIGQUIT: sname = "Quit"; break;
-#endif
-#ifdef SIGTERM
+# endif
+# ifdef SIGTERM
case SIGTERM: sname = "Terminated"; break;
-#endif
-#ifdef SIGXCPU
+# endif
+# ifdef SIGXCPU
case SIGXCPU: sname = "Cputime limit exceeded"; break;
-#endif
-#ifdef SIGXFSZ
+# endif
+# ifdef SIGXFSZ
case SIGXFSZ: sname = "Filesize limit exceeded"; break;
-#endif
+# endif
+# if has_mmap && large_memory
+# if defined(SIGBUS) && mmap_signal==SIGBUS
+ case SIGBUS: sname = "Bus error"; break;
+# endif
+# if defined(SIGSEGV) && mmap_signal==SIGSEGV
+ case SIGSEGV: sname = "Segmentation fault"; break;
+# endif
+# endif
}
+# endif
+
+ /* Avoid calling sprintf etc., in case they're not reentrant. */
+ {
+ char const *p;
+ char buf[BUFSIZ], *b = buf;
+ for (p = s; *p; *b++ = *p++)
+ continue;
+ *b++ = ':';
+ *b++ = ' ';
+ for (p = sname; *p; *b++ = *p++)
+ continue;
+ *b++ = '\n';
+ VOID write(STDERR_FILENO, buf, b - buf);
+ }
+}
+#endif
+
+static signal_type catchsig P((int));
+#ifdef SA_SIGINFO
+ static signal_type catchsigaction P((int,siginfo_t*,void*));
#endif
- if (sname)
- VOID sprintf(buf, "\nRCS: %s. Cleaning up.\n", sname);
- else
- VOID sprintf(buf, "\nRCS: Signal %d. Cleaning up.\n", s);
- VOID write(STDERR_FILENO, buf, strlen(buf));
+
+ static signal_type
+catchsig(s)
+ int s;
+#ifdef SA_SIGINFO
+{
+ catchsigaction(s, (siginfo_t *)0, (void *)0);
+}
+ static signal_type
+catchsigaction(s, i, c)
+ int s;
+ siginfo_t *i;
+ void *c;
+#endif
+{
+# if sig_zaps_handler
+ /* If a signal arrives before we reset the handler, we lose. */
+ VOID signal(s, SIG_IGN);
+# endif
+
+# ifdef SA_SIGINFO
+ if (!unsupported_SA_SIGINFO)
+ i = 0;
+# endif
+
+ if (holdlevel) {
+ heldsignal = s;
+# ifdef SA_SIGINFO
+ if (i) {
+ bufsiginfo = *i;
+ heldsiginfo = &bufsiginfo;
+ }
+# endif
+ return;
+ }
+
+ ignoreints();
+ setrid();
+ if (!quietflag) {
+ /* Avoid calling sprintf etc., in case they're not reentrant. */
+ char const *p;
+ char buf[BUFSIZ], *b = buf;
+
+ if ( ! (
+# if has_mmap && large_memory && mmap_signal
+ /* Check whether this signal was planned. */
+ s == mmap_signal && accessName
+# else
+ 0
+# endif
+ )) {
+ char const *nRCS = "\nRCS";
+# if defined(SA_SIGINFO) && has_si_errno && has_mmap && large_memory && mmap_signal
+ if (s == mmap_signal && i && i->si_errno) {
+ errno = i->si_errno;
+ perror(nRCS++);
+ }
+# endif
+# if defined(SA_SIGINFO) && has_psiginfo
+ if (i)
+ psiginfo(i, nRCS);
+ else
+ psignal(s, nRCS);
+# else
+ psignal(s, nRCS);
+# endif
}
- exiterr();
+
+ for (p = "RCS: "; *p; *b++ = *p++)
+ continue;
+# if has_mmap && large_memory && mmap_signal
+ if (s == mmap_signal) {
+ p = accessName;
+ if (!p)
+ p = "Was a file changed by some other process? ";
+ else {
+ char const *p1;
+ for (p1 = p; *p1; p1++)
+ continue;
+ VOID write(STDERR_FILENO, buf, b - buf);
+ VOID write(STDERR_FILENO, p, p1 - p);
+ b = buf;
+ p = ": Permission denied. ";
+ }
+ while (*p)
+ *b++ = *p++;
+ }
+# endif
+ for (p = "Cleaning up.\n"; *p; *b++ = *p++)
+ continue;
+ VOID write(STDERR_FILENO, buf, b - buf);
+ }
+ exiterr();
}
void
@@ -414,62 +594,62 @@ ignoreints()
restoreints()
{
if (!--holdlevel && heldsignal)
+# ifdef SA_SIGINFO
+ VOID catchsigaction(heldsignal, heldsiginfo, (void *)0);
+# else
VOID catchsig(heldsignal);
+# endif
}
-static int const sig[] = {
-#ifdef SIGHUP
- SIGHUP,
-#endif
-#ifdef SIGINT
- SIGINT,
-#endif
-#ifdef SIGPIPE
- SIGPIPE,
-#endif
-#ifdef SIGQUIT
- SIGQUIT,
-#endif
-#ifdef SIGTERM
- SIGTERM,
-#endif
-#ifdef SIGXCPU
- SIGXCPU,
-#endif
-#ifdef SIGXFSZ
- SIGXFSZ,
-#endif
-};
-#define SIGS (sizeof(sig)/sizeof(*sig))
-
+static void setup_catchsig P((int const*,int));
#if has_sigaction
+ static void check_sig P((int));
static void
check_sig(r)
int r;
{
if (r != 0)
- efaterror("signal");
+ efaterror("signal handling");
}
static void
- setup_catchsig()
+ setup_catchsig(sig, sigs)
+ int const *sig;
+ int sigs;
{
- register int i;
- sigset_t blocked;
+ register int i, j;
struct sigaction act;
- check_sig(sigemptyset(&blocked));
- for (i=SIGS; 0<=--i; )
- check_sig(sigaddset(&blocked, sig[i]));
- for (i=SIGS; 0<=--i; ) {
- check_sig(sigaction(sig[i], (struct sigaction*)nil, &act));
+ for (i=sigs; 0<=--i; ) {
+ check_sig(sigaction(sig[i], (struct sigaction*)0, &act));
if (act.sa_handler != SIG_IGN) {
- act.sa_handler = catchsig;
- act.sa_mask = blocked;
- check_sig(sigaction(sig[i], &act, (struct sigaction*)nil));
+ act.sa_handler = catchsig;
+# ifdef SA_SIGINFO
+ if (!unsupported_SA_SIGINFO) {
+# if has_sa_sigaction
+ act.sa_sigaction = catchsigaction;
+# else
+ act.sa_handler = catchsigaction;
+# endif
+ act.sa_flags |= SA_SIGINFO;
+ }
+# endif
+ for (j=sigs; 0<=--j; )
+ check_sig(sigaddset(&act.sa_mask, sig[j]));
+ if (sigaction(sig[i], &act, (struct sigaction*)0) != 0) {
+# if defined(SA_SIGINFO) && defined(ENOTSUP)
+ if (errno == ENOTSUP && !unsupported_SA_SIGINFO) {
+ /* Turn off use of SA_SIGINFO and try again. */
+ unsupported_SA_SIGINFO = 1;
+ i++;
+ continue;
+ }
+# endif
+ check_sig(-1);
+ }
}
}
}
@@ -478,16 +658,18 @@ static int const sig[] = {
#if has_sigblock
static void
- setup_catchsig()
+ setup_catchsig(sig, sigs)
+ int const *sig;
+ int sigs;
{
register int i;
int mask;
mask = 0;
- for (i=SIGS; 0<=--i; )
+ for (i=sigs; 0<=--i; )
mask |= sigmask(sig[i]);
mask = sigblock(mask);
- for (i=SIGS; 0<=--i; )
+ for (i=sigs; 0<=--i; )
if (
signal(sig[i], catchsig) == SIG_IGN &&
signal(sig[i], SIG_IGN) != catchsig
@@ -499,11 +681,13 @@ static int const sig[] = {
#else
static void
- setup_catchsig()
+ setup_catchsig(sig, sigs)
+ int const *sig;
+ int sigs;
{
register i;
- for (i=SIGS; 0<=--i; )
+ for (i=sigs; 0<=--i; )
if (
signal(sig[i], SIG_IGN) != SIG_IGN &&
signal(sig[i], catchsig) != SIG_IGN
@@ -514,16 +698,68 @@ static int const sig[] = {
#endif
#endif
+
+static int const regsigs[] = {
+# ifdef SIGHUP
+ SIGHUP,
+# endif
+# ifdef SIGINT
+ SIGINT,
+# endif
+# ifdef SIGPIPE
+ SIGPIPE,
+# endif
+# ifdef SIGQUIT
+ SIGQUIT,
+# endif
+# ifdef SIGTERM
+ SIGTERM,
+# endif
+# ifdef SIGXCPU
+ SIGXCPU,
+# endif
+# ifdef SIGXFSZ
+ SIGXFSZ,
+# endif
+};
+
void
catchints()
{
static int catching_ints;
if (!catching_ints) {
- catching_ints = true;
- setup_catchsig();
+ catching_ints = true;
+ setup_catchsig(regsigs, (int) (sizeof(regsigs)/sizeof(*regsigs)));
}
}
+#if has_mmap && large_memory && mmap_signal
+
+ /*
+ * If you mmap an NFS file, and someone on another client removes the last
+ * link to that file, and you later reference an uncached part of that file,
+ * you'll get a SIGBUS or SIGSEGV (depending on the operating system).
+ * Catch the signal and report the problem to the user.
+ * Unfortunately, there's no portable way to differentiate between this
+ * problem and actual bugs in the program.
+ * This NFS problem is rare, thank goodness.
+ *
+ * This can also occur if someone truncates the file, even without NFS.
+ */
+
+ static int const mmapsigs[] = { mmap_signal };
+
+ void
+ catchmmapints()
+ {
+ static int catching_mmap_ints;
+ if (!catching_mmap_ints) {
+ catching_mmap_ints = true;
+ setup_catchsig(mmapsigs, (int)(sizeof(mmapsigs)/sizeof(*mmapsigs)));
+ }
+ }
+#endif
+
#endif /* has_signal */
@@ -535,7 +771,7 @@ fastcopy(inf,outf)
*/
{
#if large_memory
-# if has_mmap
+# if maps_memory
awrite((char const*)inf->ptr, (size_t)(inf->lim - inf->ptr), outf);
inf->ptr = inf->lim;
# else
@@ -586,10 +822,81 @@ awrite(buf, chars, f)
Oerror();
}
+/* dup a file descriptor; the result must not be stdin, stdout, or stderr. */
+ static int dupSafer P((int));
+ static int
+dupSafer(fd)
+ int fd;
+{
+# ifdef F_DUPFD
+ return fcntl(fd, F_DUPFD, STDERR_FILENO + 1);
+# else
+ int e, f, i, used = 0;
+ while (STDIN_FILENO <= (f = dup(fd)) && f <= STDERR_FILENO)
+ used |= 1<<f;
+ e = errno;
+ for (i = STDIN_FILENO; i <= STDERR_FILENO; i++)
+ if (used & (1<<i))
+ VOID close(i);
+ errno = e;
+ return f;
+# endif
+}
+/* Renumber a file descriptor so that it's not stdin, stdout, or stderr. */
+ int
+fdSafer(fd)
+ int fd;
+{
+ if (STDIN_FILENO <= fd && fd <= STDERR_FILENO) {
+ int f = dupSafer(fd);
+ int e = errno;
+ VOID close(fd);
+ errno = e;
+ fd = f;
+ }
+ return fd;
+}
+/* Like fopen, except the result is never stdin, stdout, or stderr. */
+ FILE *
+fopenSafer(filename, type)
+ char const *filename;
+ char const *type;
+{
+ FILE *stream = fopen(filename, type);
+ if (stream) {
+ int fd = fileno(stream);
+ if (STDIN_FILENO <= fd && fd <= STDERR_FILENO) {
+ int f = dupSafer(fd);
+ if (f < 0) {
+ int e = errno;
+ VOID fclose(stream);
+ errno = e;
+ return 0;
+ }
+ if (fclose(stream) != 0) {
+ int e = errno;
+ VOID close(f);
+ errno = e;
+ return 0;
+ }
+ stream = fdopen(f, type);
+ }
+ }
+ return stream;
+}
+#ifdef F_DUPFD
+# undef dup
+# define dup(fd) fcntl(fd, F_DUPFD, 0)
+#endif
+
+
+#if has_fork || has_spawn
+
+ static int movefd P((int,int));
static int
movefd(old, new)
int old, new;
@@ -604,6 +911,7 @@ movefd(old, new)
return close(old)==0 ? new : -1;
}
+ static int fdreopen P((int,char const*,int));
static int
fdreopen(fd, file, flags)
int fd;
@@ -620,38 +928,26 @@ fdreopen(fd, file, flags)
return movefd(newfd, fd);
}
-#if !has_spawn
- static void
-tryopen(fd,file,flags)
- int fd, flags;
- char const *file;
-{
- if (file && fdreopen(fd,file,flags) != fd)
- efaterror(file);
-}
-#else
- static int
-tryopen(fd,file,flags)
- int fd, flags;
- char const *file;
-{
- int newfd = -1;
- if (file && ((newfd=dup(fd)) < 0 || fdreopen(fd,file,flags) != fd))
- efaterror(file);
- return newfd;
-}
+#if has_spawn
+ static void redirect P((int,int));
static void
redirect(old, new)
int old, new;
+/*
+* Move file descriptor OLD to NEW.
+* If OLD is -1, do nothing.
+* If OLD is -2, just close NEW.
+*/
{
- if (0 <= old && (close(new) != 0 || movefd(old,new) < 0))
+ if ((old != -1 && close(new) != 0) || (0 <= old && movefd(old,new) < 0))
efaterror("spawn I/O redirection");
}
#endif
+#else /* !has_fork && !has_spawn */
-#if !has_fork && !has_spawn
+ static void bufargcat P((struct buf*,int,char const*));
static void
bufargcat(b, c, s)
register struct buf *b;
@@ -681,53 +977,145 @@ bufargcat(b, c, s)
*p++ = '\'';
*p = 0;
}
+
#endif
+#if !has_spawn && has_fork
/*
-* Run a command specified by the strings in 'inoutargs'.
-* inoutargs[0], if nonnil, is the name of the input file.
-* inoutargs[1], if nonnil, is the name of the output file.
-* inoutargs[2..] form the command to be run.
+* Output the string S to stderr, without touching any I/O buffers.
+* This is useful if you are a child process, whose buffers are usually wrong.
+* Exit immediately if the write does not completely succeed.
+*/
+static void write_stderr P((char const *));
+ static void
+write_stderr(s)
+ char const *s;
+{
+ size_t slen = strlen(s);
+ if (write(STDERR_FILENO, s, slen) != slen)
+ _exit(EXIT_TROUBLE);
+}
+#endif
+
+/*
+* Run a command.
+* infd, if not -1, is the input file descriptor.
+* outname, if nonzero, is the name of the output file.
+* args[1..] form the command to be run; args[0] might be modified.
*/
int
-runv(inoutargs)
- char const **inoutargs;
+runv(infd, outname, args)
+ int infd;
+ char const *outname, **args;
{
- register char const **p;
int wstatus;
+#if bad_wait_if_SIGCHLD_ignored
+ static int fixed_SIGCHLD;
+ if (!fixed_SIGCHLD) {
+ fixed_SIGCHLD = true;
+# ifndef SIGCHLD
+# define SIGCHLD SIGCLD
+# endif
+ VOID signal(SIGCHLD, SIG_DFL);
+ }
+#endif
+
oflush();
eflush();
{
#if has_spawn
int in, out;
- p = inoutargs;
- in = tryopen(STDIN_FILENO, *p++, O_BINARY|O_RDONLY);
- out = tryopen(STDOUT_FILENO, *p++, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY);
- wstatus = spawn_RCS(0, *p, (char*const*)p);
- if (wstatus == -1 && errno == ENOEXEC) {
- *--p = RCS_SHELL;
- wstatus = spawnv(0, *p, (char*const*)p);
+ char const *file;
+
+ in = -1;
+ if (infd != -1 && infd != STDIN_FILENO) {
+ if ((in = dup(STDIN_FILENO)) < 0) {
+ if (errno != EBADF)
+ efaterror("spawn input setup");
+ in = -2;
+ } else {
+# ifdef F_DUPFD
+ if (close(STDIN_FILENO) != 0)
+ efaterror("spawn input close");
+# endif
+ }
+ if (
+# ifdef F_DUPFD
+ fcntl(infd, F_DUPFD, STDIN_FILENO) != STDIN_FILENO
+# else
+ dup2(infd, STDIN_FILENO) != STDIN_FILENO
+# endif
+ )
+ efaterror("spawn input redirection");
}
+
+ out = -1;
+ if (outname) {
+ if ((out = dup(STDOUT_FILENO)) < 0) {
+ if (errno != EBADF)
+ efaterror("spawn output setup");
+ out = -2;
+ }
+ if (fdreopen(
+ STDOUT_FILENO, outname,
+ O_CREAT | O_TRUNC | O_WRONLY
+ ) < 0)
+ efaterror(outname);
+ }
+
+ wstatus = spawn_RCS(0, args[1], (char**)(args + 1));
+# ifdef RCS_SHELL
+ if (wstatus == -1 && errno == ENOEXEC) {
+ args[0] = RCS_SHELL;
+ wstatus = spawnv(0, args[0], (char**)args);
+ }
+# endif
redirect(in, STDIN_FILENO);
redirect(out, STDOUT_FILENO);
#else
#if has_fork
pid_t pid;
-# if !has_waitpid
- pid_t w;
-# endif
if (!(pid = vfork())) {
- p = inoutargs;
- tryopen(STDIN_FILENO, *p++, O_BINARY|O_RDONLY);
- tryopen(STDOUT_FILENO, *p++, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY);
- VOID exec_RCS(*p, (char*const*)p);
- if (errno == ENOEXEC) {
- *--p = RCS_SHELL;
- VOID execv(*p, (char*const*)p);
+ char const *notfound;
+ if (infd != -1 && infd != STDIN_FILENO && (
+# ifdef F_DUPFD
+ (VOID close(STDIN_FILENO),
+ fcntl(infd, F_DUPFD, STDIN_FILENO) != STDIN_FILENO)
+# else
+ dup2(infd, STDIN_FILENO) != STDIN_FILENO
+# endif
+ )) {
+ /* Avoid perror since it may misuse buffers. */
+ write_stderr(args[1]);
+ write_stderr(": I/O redirection failed\n");
+ _exit(EXIT_TROUBLE);
}
- VOID write(STDERR_FILENO, *p, strlen(*p));
- VOID write(STDERR_FILENO, ": not found\n", 12);
+
+ if (outname)
+ if (fdreopen(
+ STDOUT_FILENO, outname,
+ O_CREAT | O_TRUNC | O_WRONLY
+ ) < 0) {
+ /* Avoid perror since it may misuse buffers. */
+ write_stderr(args[1]);
+ write_stderr(": ");
+ write_stderr(outname);
+ write_stderr(": cannot create\n");
+ _exit(EXIT_TROUBLE);
+ }
+ VOID exec_RCS(args[1], (char**)(args + 1));
+ notfound = args[1];
+# ifdef RCS_SHELL
+ if (errno == ENOEXEC) {
+ args[0] = notfound = RCS_SHELL;
+ VOID execv(args[0], (char**)args);
+ }
+# endif
+
+ /* Avoid perror since it may misuse buffers. */
+ write_stderr(notfound);
+ write_stderr(": not found\n");
_exit(EXIT_TROUBLE);
}
if (pid < 0)
@@ -736,83 +1124,71 @@ runv(inoutargs)
if (waitpid(pid, &wstatus, 0) < 0)
efaterror("waitpid");
# else
- do {
- if ((w = wait(&wstatus)) < 0)
- efaterror("wait");
- } while (w != pid);
+ {
+ pid_t w;
+ do {
+ if ((w = wait(&wstatus)) < 0)
+ efaterror("wait");
+ } while (w != pid);
+ }
# endif
#else
static struct buf b;
+ char const *p;
/* Use system(). On many hosts system() discards signals. Yuck! */
- p = inoutargs+2;
+ p = args + 1;
bufscpy(&b, *p);
while (*++p)
bufargcat(&b, ' ', *p);
- if (inoutargs[0])
- bufargcat(&b, '<', inoutargs[0]);
- if (inoutargs[1])
- bufargcat(&b, '>', inoutargs[1]);
+ if (infd != -1 && infd != STDIN_FILENO) {
+ char redirection[32];
+ VOID sprintf(redirection, "<&%d", infd);
+ bufscat(&b, redirection);
+ }
+ if (outname)
+ bufargcat(&b, '>', outname);
wstatus = system(b.string);
#endif
#endif
}
- if (!WIFEXITED(wstatus))
- faterror("%s failed", inoutargs[2]);
+ if (!WIFEXITED(wstatus)) {
+ if (WIFSIGNALED(wstatus)) {
+ psignal(WTERMSIG(wstatus), args[1]);
+ fatcleanup(1);
+ }
+ faterror("%s failed for unknown reason", args[1]);
+ }
return WEXITSTATUS(wstatus);
}
#define CARGSMAX 20
/*
* Run a command.
-* The first two arguments are the input and output files (if nonnil);
-* the rest specify the command and its arguments.
+* infd, if not -1, is the input file descriptor.
+* outname, if nonzero, is the name of the output file.
+* The remaining arguments specify the command and its arguments.
*/
int
#if has_prototypes
-run(char const *infile, char const *outfile, ...)
+run(int infd, char const *outname, ...)
#else
/*VARARGS2*/
-run(infile, outfile, va_alist)
- char const *infile;
- char const *outfile;
+run(infd, outname, va_alist)
+ int infd;
+ char const *outname;
va_dcl
#endif
{
va_list ap;
char const *rgargs[CARGSMAX];
- register i = 0;
- rgargs[0] = infile;
- rgargs[1] = outfile;
- vararg_start(ap, outfile);
- for (i = 2; (rgargs[i++] = va_arg(ap, char const*)); )
+ register int i;
+ vararg_start(ap, outname);
+ for (i = 1; (rgargs[i++] = va_arg(ap, char const*)); )
if (CARGSMAX <= i)
faterror("too many command arguments");
va_end(ap);
- return runv(rgargs);
-}
-
-
- char const *
-date2str(date, datebuf)
- char const date[datesize];
- char datebuf[datesize];
-/*
-* Format a user-readable form of the RCS format DATE into the buffer DATEBUF.
-* Yield DATEBUF.
-*/
-{
- register char const *p = date;
-
- while (*p++ != '.')
- ;
- VOID sprintf(datebuf,
- "19%.*s/%.2s/%.2s %.2s:%.2s:%s" +
- (date[2]=='.' && VERSION(5)<=RCSversion ? 0 : 2),
- (int)(p-date-1), date,
- p, p+3, p+6, p+9, p+12
- );
- return datebuf;
+ return runv(infd, outname, rgargs);
}
@@ -825,23 +1201,28 @@ setRCSversion(str)
static int oldversion;
register char const *s = str + 2;
- int v = VERSION_DEFAULT;
-
- if (oldversion)
- redefined('V');
- oldversion = true;
if (*s) {
+ int v = VERSION_DEFAULT;
+
+ if (oldversion)
+ redefined('V');
+ oldversion = true;
v = 0;
while (isdigit(*s))
v = 10*v + *s++ - '0';
if (*s)
- faterror("%s isn't a number", str);
- if (v < VERSION_min || VERSION_max < v)
- faterror("%s out of range %d..%d", str, VERSION_min, VERSION_max);
+ error("%s isn't a number", str);
+ else if (v < VERSION_min || VERSION_max < v)
+ error("%s out of range %d..%d",
+ str, VERSION_min, VERSION_max
+ );
+
+ RCSversion = VERSION(v);
+ } else {
+ printf("RCS version %s\n", RCS_version_string);
+ exit(0);
}
-
- RCSversion = VERSION(v);
}
int
@@ -850,7 +1231,7 @@ getRCSINIT(argc, argv, newargv)
char **argv, ***newargv;
{
register char *p, *q, **pp;
- unsigned n;
+ size_t n;
if (!(q = cgetenv("RCSINIT")))
*newargv = argv;
@@ -919,7 +1300,7 @@ getRCSINIT(argc, argv, newargv)
}
copyrest:
while ((*pp++ = *argv++))
- ;
+ continue;
}
return argc;
}
@@ -947,8 +1328,11 @@ getRCSINIT(argc, argv, newargv)
*/
static void
-set_uid_to(u)
- uid_t u;
+#if has_prototypes
+set_uid_to(uid_t u)
+#else
+ set_uid_to(u) uid_t u;
+#endif
/* Become user u. */
{
static int looping;
@@ -956,8 +1340,13 @@ set_uid_to(u)
if (euid() == ruid())
return;
#if (has_fork||has_spawn) && DIFF_ABSOLUTE
- if (seteuid(u) != 0)
- efaterror("setuid");
+# if has_setreuid
+ if (setreuid(u==euid() ? ruid() : euid(), u) != 0)
+ efaterror("setuid");
+# else
+ if (seteuid(u) != 0)
+ efaterror("setuid");
+# endif
#endif
if (geteuid() != u) {
if (looping)
@@ -992,3 +1381,12 @@ setrid()
set_uid_to(ruid());
}
#endif
+
+ time_t
+now()
+{
+ static time_t t;
+ if (!t && time(&t) == -1)
+ efaterror("time");
+ return t;
+}
diff --git a/gnu/usr.bin/rcs/lib/version.c b/gnu/usr.bin/rcs/lib/version.c
new file mode 100644
index 0000000..81f5585
--- /dev/null
+++ b/gnu/usr.bin/rcs/lib/version.c
@@ -0,0 +1,2 @@
+#include "rcsbase.h"
+char const RCS_version_string[] = "5.7";
OpenPOWER on IntegriCloud