Date: Wed, 6 May 2015 23:52:16 +0000 (UTC) From: "Pedro F. Giffuni" <pfg@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-vendor@freebsd.org Subject: svn commit: r282572 - vendor/OpenBSD/dist/usr.bin/rcs Message-ID: <201505062352.t46NqGRq020002@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: pfg Date: Wed May 6 23:52:15 2015 New Revision: 282572 URL: https://svnweb.freebsd.org/changeset/base/282572 Log: Bring OpenRCS 20150326 to the vendor area. A BSD-licensed alternative to GNU Revision Control System. Obtained from: OpenBSD Added: vendor/OpenBSD/dist/usr.bin/rcs/ vendor/OpenBSD/dist/usr.bin/rcs/Makefile (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/buf.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/buf.h (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/ci.1 (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/ci.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/co.1 (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/co.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/date.y vendor/OpenBSD/dist/usr.bin/rcs/diff.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/diff.h (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/diff3.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/ident.1 (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/ident.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/merge.1 (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/merge.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rcs.1 (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rcs.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rcs.h (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rcsclean.1 (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rcsclean.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rcsdiff.1 (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rcsdiff.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rcsmerge.1 (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rcsmerge.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rcsnum.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rcsparse.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rcsparse.h (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rcsprog.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rcsprog.h (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rcstime.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rcsutil.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rcsutil.h (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rlog.1 (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/rlog.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/worklist.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/worklist.h (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/xmalloc.c (contents, props changed) vendor/OpenBSD/dist/usr.bin/rcs/xmalloc.h (contents, props changed) Added: vendor/OpenBSD/dist/usr.bin/rcs/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ vendor/OpenBSD/dist/usr.bin/rcs/Makefile Wed May 6 23:52:15 2015 (r282572) @@ -0,0 +1,23 @@ +# $OpenBSD: Makefile,v 1.40 2010/10/15 08:44:12 tobias Exp $ + +PROG= rcs +MAN= ci.1 co.1 ident.1 merge.1 rcs.1 rcsclean.1 rcsdiff.1 rcsmerge.1 rlog.1 + +SRCS= ci.c co.c ident.c merge.c rcsclean.c rcsdiff.c rcsmerge.c rcsparse.c \ + rcsprog.c rlog.c rcsutil.c buf.c date.y diff.c diff3.c rcs.c rcsnum.c \ + rcstime.c worklist.c xmalloc.c + +LINKS= ${BINDIR}/rcs ${BINDIR}/ci ${BINDIR}/rcs ${BINDIR}/co \ + ${BINDIR}/rcs ${BINDIR}/ident ${BINDIR}/rcs ${BINDIR}/merge \ + ${BINDIR}/rcs ${BINDIR}/rcsclean ${BINDIR}/rcs ${BINDIR}/rcsdiff \ + ${BINDIR}/rcs ${BINDIR}/rcsmerge ${BINDIR}/rcs ${BINDIR}/rlog + +CPPFLAGS+=-I${.CURDIR} +CFLAGS+=-Wall +CFLAGS+=-Wstrict-prototypes -Wmissing-prototypes +CFLAGS+=-Wmissing-declarations +CFLAGS+=-Wshadow -Wpointer-arith -Wcast-qual +CFLAGS+=-Wsign-compare +YFLAGS= + +.include <bsd.prog.mk> Added: vendor/OpenBSD/dist/usr.bin/rcs/buf.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ vendor/OpenBSD/dist/usr.bin/rcs/buf.c Wed May 6 23:52:15 2015 (r282572) @@ -0,0 +1,331 @@ +/* $OpenBSD: buf.c,v 1.24 2015/02/05 12:59:58 millert Exp $ */ +/* + * Copyright (c) 2003 Jean-Francois Brousseau <jfb@openbsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/queue.h> +#include <sys/stat.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "buf.h" +#include "xmalloc.h" +#include "worklist.h" + +#define BUF_INCR 128 + +struct buf { + /* buffer handle, buffer size, and data length */ + u_char *cb_buf; + size_t cb_size; + size_t cb_len; +}; + +#define SIZE_LEFT(b) (b->cb_size - b->cb_len) + +static void buf_grow(BUF *, size_t); + +/* + * Create a new buffer structure and return a pointer to it. This structure + * uses dynamically-allocated memory and must be freed with buf_free(), once + * the buffer is no longer needed. + */ +BUF * +buf_alloc(size_t len) +{ + BUF *b; + + b = xmalloc(sizeof(*b)); + /* Postpone creation of zero-sized buffers */ + if (len > 0) + b->cb_buf = xcalloc(1, len); + else + b->cb_buf = NULL; + + b->cb_size = len; + b->cb_len = 0; + + return (b); +} + +/* + * Open the file specified by <path> and load all of its contents into a + * buffer. + * Returns the loaded buffer on success or NULL on failure. + * Sets errno on error. + */ +BUF * +buf_load(const char *path) +{ + int fd; + ssize_t ret; + size_t len; + u_char *bp; + struct stat st; + BUF *buf; + + buf = NULL; + + if ((fd = open(path, O_RDONLY, 0600)) == -1) + goto out; + + if (fstat(fd, &st) == -1) + goto out; + + if (st.st_size > SIZE_MAX) { + errno = EFBIG; + goto out; + } + buf = buf_alloc(st.st_size); + for (bp = buf->cb_buf; ; bp += (size_t)ret) { + len = SIZE_LEFT(buf); + ret = read(fd, bp, len); + if (ret == -1) { + int saved_errno; + + saved_errno = errno; + buf_free(buf); + buf = NULL; + errno = saved_errno; + goto out; + } else if (ret == 0) + break; + + buf->cb_len += (size_t)ret; + } + +out: + if (fd != -1) { + int saved_errno; + + /* We may want to preserve errno here. */ + saved_errno = errno; + (void)close(fd); + errno = saved_errno; + } + + return (buf); +} + +void +buf_free(BUF *b) +{ + if (b->cb_buf != NULL) + xfree(b->cb_buf); + xfree(b); +} + +/* + * Free the buffer <b>'s structural information but do not free the contents + * of the buffer. Instead, they are returned and should be freed later using + * xfree(). + */ +void * +buf_release(BUF *b) +{ + void *tmp; + + tmp = b->cb_buf; + xfree(b); + return (tmp); +} + +u_char * +buf_get(BUF *b) +{ + return (b->cb_buf); +} + +/* + * Empty the contents of the buffer <b> and reset pointers. + */ +void +buf_empty(BUF *b) +{ + memset(b->cb_buf, 0, b->cb_size); + b->cb_len = 0; +} + +/* + * Append a single character <c> to the end of the buffer <b>. + */ +void +buf_putc(BUF *b, int c) +{ + u_char *bp; + + if (SIZE_LEFT(b) == 0) + buf_grow(b, BUF_INCR); + bp = b->cb_buf + b->cb_len; + *bp = (u_char)c; + b->cb_len++; +} + +/* + * Append a string <s> to the end of buffer <b>. + */ +void +buf_puts(BUF *b, const char *str) +{ + buf_append(b, str, strlen(str)); +} + +/* + * Return u_char at buffer position <pos>. + */ +u_char +buf_getc(BUF *b, size_t pos) +{ + return (b->cb_buf[pos]); +} + +/* + * Append <len> bytes of data pointed to by <data> to the buffer <b>. If the + * buffer is too small to accept all data, it will get resized to an + * appropriate size to accept all data. + * Returns the number of bytes successfully appended to the buffer. + */ +size_t +buf_append(BUF *b, const void *data, size_t len) +{ + size_t left, rlen; + u_char *bp; + + left = SIZE_LEFT(b); + rlen = len; + + if (left < len) + buf_grow(b, len - left); + bp = b->cb_buf + b->cb_len; + memcpy(bp, data, rlen); + b->cb_len += rlen; + + return (rlen); +} + +/* + * Returns the size of the buffer that is being used. + */ +size_t +buf_len(BUF *b) +{ + return (b->cb_len); +} + +/* + * Write the contents of the buffer <b> to the specified <fd> + */ +int +buf_write_fd(BUF *b, int fd) +{ + u_char *bp; + size_t len; + ssize_t ret; + + len = b->cb_len; + bp = b->cb_buf; + + do { + ret = write(fd, bp, len); + if (ret == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + return (-1); + } + + len -= (size_t)ret; + bp += (size_t)ret; + } while (len > 0); + + return (0); +} + +/* + * Write the contents of the buffer <b> to the file whose path is given in + * <path>. If the file does not exist, it is created with mode <mode>. + */ +int +buf_write(BUF *b, const char *path, mode_t mode) +{ + int fd; + open: + if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) { + if (errno == EACCES && unlink(path) != -1) + goto open; + else + err(1, "%s", path); + } + + if (buf_write_fd(b, fd) == -1) { + (void)unlink(path); + errx(1, "buf_write: buf_write_fd: `%s'", path); + } + + if (fchmod(fd, mode) < 0) + warn("permissions not set on file %s", path); + + (void)close(fd); + + return (0); +} + +/* + * Write the contents of the buffer <b> to a temporary file whose path is + * specified using <template> (see mkstemp.3). + * NB. This function will modify <template>, as per mkstemp + */ +void +buf_write_stmp(BUF *b, char *template) +{ + int fd; + + if ((fd = mkstemp(template)) == -1) + err(1, "%s", template); + + worklist_add(template, &temp_files); + + if (buf_write_fd(b, fd) == -1) { + (void)unlink(template); + errx(1, "buf_write_stmp: buf_write_fd: `%s'", template); + } + + (void)close(fd); +} + +/* + * Grow the buffer <b> by <len> bytes. The contents are unchanged by this + * operation regardless of the result. + */ +static void +buf_grow(BUF *b, size_t len) +{ + b->cb_buf = xreallocarray(b->cb_buf, 1, b->cb_size + len); + b->cb_size += len; +} Added: vendor/OpenBSD/dist/usr.bin/rcs/buf.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ vendor/OpenBSD/dist/usr.bin/rcs/buf.h Wed May 6 23:52:15 2015 (r282572) @@ -0,0 +1,60 @@ +/* $OpenBSD: buf.h,v 1.13 2011/07/06 15:36:52 nicm Exp $ */ +/* + * Copyright (c) 2003 Jean-Francois Brousseau <jfb@openbsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Buffer management + * ----------------- + * + * This code provides an API to generic memory buffer management. All + * operations are performed on a buf structure, which is kept opaque to the + * API user in order to avoid corruption of the fields and make sure that only + * the internals can modify the fields. + * + * The first step is to allocate a new buffer using the buf_alloc() + * function, which returns a pointer to a new buffer. + */ + +#ifndef BUF_H +#define BUF_H + +#include <sys/types.h> + +typedef struct buf BUF; + +BUF *buf_alloc(size_t); +BUF *buf_load(const char *); +void buf_free(BUF *); +void *buf_release(BUF *); +u_char buf_getc(BUF *, size_t); +void buf_empty(BUF *); +size_t buf_append(BUF *, const void *, size_t); +void buf_putc(BUF *, int); +void buf_puts(BUF *b, const char *str); +size_t buf_len(BUF *); +int buf_write_fd(BUF *, int); +int buf_write(BUF *, const char *, mode_t); +void buf_write_stmp(BUF *, char *); +u_char *buf_get(BUF *b); + +#endif /* BUF_H */ Added: vendor/OpenBSD/dist/usr.bin/rcs/ci.1 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ vendor/OpenBSD/dist/usr.bin/rcs/ci.1 Wed May 6 23:52:15 2015 (r282572) @@ -0,0 +1,202 @@ +.\" $OpenBSD: ci.1,v 1.38 2013/08/12 14:19:53 jmc Exp $ +.\" +.\" Copyright (c) 2005 Niall O'Higgins <niallo@openbsd.org> +.\" All rights reserved. +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.Dd $Mdocdate: August 12 2013 $ +.Dt CI 1 +.Os +.Sh NAME +.Nm ci +.Nd check in RCS revisions +.Sh SYNOPSIS +.Nm +.Bk -words +.Op Fl qV +.Op Fl d Ns Op Ar date +.Op Fl f Ns Op Ar rev +.Op Fl I Ns Op Ar rev +.Op Fl i Ns Op Ar rev +.Op Fl j Ns Op Ar rev +.Op Fl k Ns Op Ar rev +.Op Fl l Ns Op Ar rev +.Op Fl M Ns Op Ar rev +.Op Fl m Ns Ar msg +.Op Fl N Ns Ar symbol +.Op Fl n Ns Ar symbol +.Op Fl r Ns Op Ar rev +.Op Fl s Ns Ar state +.Op Fl t Ns Op Ar str +.Op Fl u Ns Op Ar rev +.Op Fl w Ns Ar username +.Op Fl x Ns Ar suffixes +.Op Fl z Ns Ar tz +.Ar +.Ek +.Sh DESCRIPTION +The +.Nm +program is used to check in new revisions to RCS files. +.Pp +When a file is checked in, +it is stored in the RCS directory with a specific revision number, +and the original file itself is deleted. +The RCS file is stored with the same name, but with +.Sq ,v +appended. +.Nm +will prompt for a check-in message, +to be stored with the file, +which can be displayed using +.Xr rlog 1 . +.Pp +Revision numbering starts at 1.1 +and increases logically. +Numbering can be altered using the +.Fl k +option, however. +The +.Sq ,v +suffix can also be altered, +using the +.Fl x +option. +.Pp +.Nm +also supports +keyword substitution \(en +see the +.Xr rcs 1 +man page for more information. +.Pp +The following options are supported: +.Bl -tag -width Ds +.It Fl d Ns Op Ar date +Uses +.Ar date +for check-in date and time. +If +.Ar date +is not specified, use the working file's last modification time. +.It Fl f Ns Op Ar rev +Force check-in +\(en even if no changes have been made to the working file. +.It Fl I Ns Op Ar rev +Interactive mode. +.It Fl i Ns Op Ar rev +Only do initial check-in. +Print error and refuse to do check-in if the RCS file already exists. +.It Fl j Ns Op Ar rev +Only do update check-in. +Print error and refuse to do check-in if the RCS file does not already exist. +.It Fl k Ns Op Ar rev +Search the working file for keywords and set the revision number, +creation date, state and author to the values found in these keywords +instead of computing them. +.It Fl l Ns Op Ar rev +The same as +.Fl r , +but also immediately checks out the deposited revision and locks it. +This is useful if you wish to continue to edit the working file after check-in. +.It Fl M Ns Op Ar rev +Set the modification time of the file to the date of the +retrieved revision. +.It Fl m Ns Ar msg +Specify a log message. +A line beginning with a hash character +.Pq Sq # +is considered a comment and ignored. +.It Fl N Ns Ar symbol +Assign the symbolic name +.Ar symbol +to the checked in revision, overwriting any previous assignment of +.Ar symbol . +.It Fl n Ns Ar symbol +The same as +.Fl N +except it does not overwrite previous symbols. +.It Fl q +Be quiet about reporting. +.It Fl r Ns Op Ar rev +Check in revision +.Ar rev . +However, if +.Ar rev +is not specified the meaning is completely different \(en override any +.Fl l +or +.Fl u +options, ensuring the default behaviour of releasing a lock and removing the +working file. +.It Fl s Ns Ar state +Sets the state of the deposited revision to the identifier +.Ar state . +The specified value may not contain a space character. +.It Fl t Ns Op Ar str +Change the descriptive text. +The argument +.Ar str +is interpreted as the name of a file containing +the descriptive text or, +if prefixed with a +.Sq - , +the actual descriptive text itself. +If no argument is given, +this option is ignored +(for compatibility reasons). +.It Fl u Ns Op Ar rev +The same as +.Fl r , +but also immediately checks out the deposited revision read-only. +Useful if you wish to read the working file after check-in. +.It Fl V +Print RCS's version number. +.It Fl w Ns Ar username +Uses +.Ar username +as the author field of the deposited revision. +.It Fl x Ns Ar suffixes +Specifies the suffixes for RCS files. +Suffixes should be separated by the +.Sq / +character. +.It Fl z Ns Ar tz +Specify the date output format in keyword substitution, and the +default time zone for +.Ar date +used in the +.Fl d +option. +.El +.Sh ENVIRONMENT +.Bl -tag -width RCSINIT +.It Ev RCSINIT +If set, this variable should contain a list of space-delimited options that +are prepended to the argument list. +.It Ev TMPDIR +When set, this variable specifies the directory where temporary files +are to be created. +The default is set to +.Pa /tmp . +.El +.Sh EXIT STATUS +.Ex -std ci +.Sh SEE ALSO +.Xr co 1 , +.Xr ident 1 , +.Xr rcs 1 , +.Xr rcsclean 1 , +.Xr rcsdiff 1 , +.Xr rcsmerge 1 , +.Xr rlog 1 Added: vendor/OpenBSD/dist/usr.bin/rcs/ci.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ vendor/OpenBSD/dist/usr.bin/rcs/ci.c Wed May 6 23:52:15 2015 (r282572) @@ -0,0 +1,1037 @@ +/* $OpenBSD: ci.c,v 1.219 2015/01/16 06:40:11 deraadt Exp $ */ +/* + * Copyright (c) 2005, 2006 Niall O'Higgins <niallo@openbsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/stat.h> + +#include <ctype.h> +#include <err.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "rcsprog.h" +#include "diff.h" + +#define CI_OPTSTRING "d::f::I::i::j::k::l::M::m::N:n:qr::s:Tt::u::Vw:x::z::" +#define DATE_NOW -1 +#define DATE_MTIME -2 + +#define KW_ID "Id" +#define KW_OPENBSD "OpenBSD" +#define KW_AUTHOR "Author" +#define KW_DATE "Date" +#define KW_STATE "State" +#define KW_REVISION "Revision" + +#define KW_TYPE_ID 1 +#define KW_TYPE_AUTHOR 2 +#define KW_TYPE_DATE 3 +#define KW_TYPE_STATE 4 +#define KW_TYPE_REVISION 5 + +/* Maximum number of tokens in a keyword. */ +#define KW_NUMTOKS_MAX 10 + +#define RCSNUM_ZERO_ENDING(x) (x->rn_id[x->rn_len - 1] == 0) + +extern struct rcs_kw rcs_expkw[]; + +static int workfile_fd; + +struct checkin_params { + int flags, openflags; + mode_t fmode; + time_t date; + RCSFILE *file; + RCSNUM *frev, *newrev; + const char *description, *symbol; + char fpath[PATH_MAX], *rcs_msg, *username, *filename; + char *author, *state; + BUF *deltatext; +}; + +static int checkin_attach_symbol(struct checkin_params *); +static int checkin_checklock(struct checkin_params *); +static BUF *checkin_diff_file(struct checkin_params *); +static char *checkin_getlogmsg(RCSNUM *, RCSNUM *, int); +static int checkin_init(struct checkin_params *); +static int checkin_keywordscan(BUF *, RCSNUM **, time_t *, char **, + char **); +static int checkin_keywordtype(char *); +static void checkin_mtimedate(struct checkin_params *); +static void checkin_parsekeyword(char *, RCSNUM **, time_t *, char **, + char **); +static int checkin_update(struct checkin_params *); +static int checkin_revert(struct checkin_params *); + +__dead void +checkin_usage(void) +{ + fprintf(stderr, + "usage: ci [-qV] [-d[date]] [-f[rev]] [-I[rev]] [-i[rev]]\n" + " [-j[rev]] [-k[rev]] [-l[rev]] [-M[rev]] [-mmsg]\n" + " [-Nsymbol] [-nsymbol] [-r[rev]] [-sstate] [-t[str]]\n" + " [-u[rev]] [-wusername] [-xsuffixes] [-ztz] file ...\n"); + + exit(1); +} + +/* + * checkin_main() + * + * Handler for the `ci' program. + * Returns 0 on success, or >0 on error. + */ +int +checkin_main(int argc, char **argv) +{ + int fd; + int i, ch, status; + int base_flags, base_openflags; + char *rev_str; + struct checkin_params pb; + + pb.date = DATE_NOW; + pb.file = NULL; + pb.rcs_msg = pb.username = pb.author = pb.state = NULL; + pb.description = pb.symbol = NULL; + pb.deltatext = NULL; + pb.newrev = NULL; + pb.fmode = S_IRUSR|S_IRGRP|S_IROTH; + status = 0; + base_flags = INTERACTIVE; + base_openflags = RCS_RDWR|RCS_CREATE|RCS_PARSE_FULLY; + rev_str = NULL; + + while ((ch = rcs_getopt(argc, argv, CI_OPTSTRING)) != -1) { + switch (ch) { + case 'd': + if (rcs_optarg == NULL) + pb.date = DATE_MTIME; + else if ((pb.date = date_parse(rcs_optarg)) == -1) + errx(1, "invalid date"); + break; + case 'f': + rcs_setrevstr(&rev_str, rcs_optarg); + base_flags |= FORCE; + break; + case 'I': + rcs_setrevstr(&rev_str, rcs_optarg); + base_flags |= INTERACTIVE; + break; + case 'i': + rcs_setrevstr(&rev_str, rcs_optarg); + base_openflags |= RCS_CREATE; + base_flags |= CI_INIT; + break; + case 'j': + rcs_setrevstr(&rev_str, rcs_optarg); + base_openflags &= ~RCS_CREATE; + base_flags &= ~CI_INIT; + break; + case 'k': + rcs_setrevstr(&rev_str, rcs_optarg); + base_flags |= CI_KEYWORDSCAN; + break; + case 'l': + rcs_setrevstr(&rev_str, rcs_optarg); + base_flags |= CO_LOCK; + break; + case 'M': + rcs_setrevstr(&rev_str, rcs_optarg); + base_flags |= CO_REVDATE; + break; + case 'm': + pb.rcs_msg = rcs_optarg; + if (pb.rcs_msg == NULL) + errx(1, "missing message for -m option"); + base_flags &= ~INTERACTIVE; + break; + case 'N': + base_flags |= CI_SYMFORCE; + /* FALLTHROUGH */ + case 'n': + pb.symbol = rcs_optarg; + if (rcs_sym_check(pb.symbol) != 1) + errx(1, "invalid symbol `%s'", pb.symbol); + break; + case 'q': + base_flags |= QUIET; + break; + case 'r': + rcs_setrevstr(&rev_str, rcs_optarg); + base_flags |= CI_DEFAULT; + break; + case 's': + pb.state = rcs_optarg; + if (rcs_state_check(pb.state) < 0) + errx(1, "invalid state `%s'", pb.state); + break; + case 'T': + base_flags |= PRESERVETIME; + break; + case 't': + /* Ignore bare -t; kept for backwards compatibility. */ + if (rcs_optarg == NULL) + break; + pb.description = rcs_optarg; + base_flags |= DESCRIPTION; + break; + case 'u': + rcs_setrevstr(&rev_str, rcs_optarg); + base_flags |= CO_UNLOCK; + break; + case 'V': + printf("%s\n", rcs_version); + exit(0); + case 'w': + if (pb.author != NULL) + xfree(pb.author); + pb.author = xstrdup(rcs_optarg); + break; + case 'x': + /* Use blank extension if none given. */ + rcs_suffixes = rcs_optarg ? rcs_optarg : ""; + break; + case 'z': + timezone_flag = rcs_optarg; + break; + default: + (usage)(); + } + } + + argc -= rcs_optind; + argv += rcs_optind; + + if (argc == 0) { + warnx("no input file"); + (usage)(); + } + + if ((pb.username = getlogin()) == NULL) + err(1, "getlogin"); + + for (i = 0; i < argc; i++) { + /* + * The pb.flags and pb.openflags may change during + * loop iteration so restore them for each file. + */ + pb.flags = base_flags; + pb.openflags = base_openflags; + + pb.filename = argv[i]; + rcs_strip_suffix(pb.filename); + + if ((workfile_fd = open(pb.filename, O_RDONLY)) == -1) + err(1, "%s", pb.filename); + + /* Find RCS file path. */ + fd = rcs_choosefile(pb.filename, pb.fpath, sizeof(pb.fpath)); + + if (fd < 0) { + if (pb.openflags & RCS_CREATE) + pb.flags |= NEWFILE; + else { + /* XXX - Check if errno == ENOENT. */ + warnx("No existing RCS file"); + status = 1; + (void)close(workfile_fd); + continue; + } + } else { + if (pb.flags & CI_INIT) { + warnx("%s already exists", pb.fpath); + status = 1; + (void)close(fd); + (void)close(workfile_fd); + continue; + } + pb.openflags &= ~RCS_CREATE; + } + + pb.file = rcs_open(pb.fpath, fd, pb.openflags, pb.fmode); + if (pb.file == NULL) + errx(1, "failed to open rcsfile `%s'", pb.fpath); + + if ((pb.flags & DESCRIPTION) && + rcs_set_description(pb.file, pb.description) == -1) + err(1, "%s", pb.filename); + + if (!(pb.flags & QUIET)) + (void)fprintf(stderr, + "%s <-- %s\n", pb.fpath, pb.filename); + + if (rev_str != NULL) + if ((pb.newrev = rcs_getrevnum(rev_str, pb.file)) == + NULL) + errx(1, "invalid revision: %s", rev_str); + + if (!(pb.flags & NEWFILE)) + pb.flags |= CI_SKIPDESC; + + /* XXX - support for committing to a file without revisions */ + if (pb.file->rf_ndelta == 0) { + pb.flags |= NEWFILE; + pb.file->rf_flags |= RCS_CREATE; + } + + /* + * workfile_fd will be closed in checkin_init or + * checkin_update + */ + if (pb.flags & NEWFILE) { + if (checkin_init(&pb) == -1) + status = 1; + } else { + if (checkin_update(&pb) == -1) + status = 1; + } + + rcs_close(pb.file); + if (rev_str != NULL) + rcsnum_free(pb.newrev); + pb.newrev = NULL; + } + + if (!(base_flags & QUIET) && status == 0) + (void)fprintf(stderr, "done\n"); + + return (status); +} + +/* + * checkin_diff_file() + * + * Generate the diff between the working file and a revision. + * Returns pointer to a BUF on success, NULL on failure. + */ +static BUF * +checkin_diff_file(struct checkin_params *pb) +{ + char *path1, *path2; + BUF *b1, *b2, *b3; + + b1 = b2 = b3 = NULL; + path1 = path2 = NULL; + + if ((b1 = buf_load(pb->filename)) == NULL) { + warnx("failed to load file: `%s'", pb->filename); + goto out; + } + + if ((b2 = rcs_getrev(pb->file, pb->frev)) == NULL) { + warnx("failed to load revision"); + goto out; + } + b2 = rcs_kwexp_buf(b2, pb->file, pb->frev); + b3 = buf_alloc(128); + + (void)xasprintf(&path1, "%s/diff1.XXXXXXXXXX", rcs_tmpdir); + buf_write_stmp(b1, path1); + + buf_free(b1); + b1 = NULL; + + (void)xasprintf(&path2, "%s/diff2.XXXXXXXXXX", rcs_tmpdir); + buf_write_stmp(b2, path2); + + buf_free(b2); + b2 = NULL; + + diff_format = D_RCSDIFF; + if (diffreg(path1, path2, b3, D_FORCEASCII) == D_ERROR) + goto out; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201505062352.t46NqGRq020002>