diff options
author | Xavier Santolaria <xsa@cvs.openbsd.org> | 2006-04-21 17:17:30 +0000 |
---|---|---|
committer | Xavier Santolaria <xsa@cvs.openbsd.org> | 2006-04-21 17:17:30 +0000 |
commit | 983cac9499e023e5b064864b91c92a9c75bc6465 (patch) | |
tree | 8701df726e0d0ce95be0039d4ed47ca10c417824 /usr.bin | |
parent | 3badf17decc7a041cd9abe96ba152aa9b09aca38 (diff) |
move shared functions into rcsutil.[ch]; this makes rcsprog.c cleaner;
"the voices in my head say OK!" joris@.
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/rcs/Makefile | 6 | ||||
-rw-r--r-- | usr.bin/rcs/ci.c | 5 | ||||
-rw-r--r-- | usr.bin/rcs/co.c | 4 | ||||
-rw-r--r-- | usr.bin/rcs/rcsclean.c | 4 | ||||
-rw-r--r-- | usr.bin/rcs/rcsdiff.c | 4 | ||||
-rw-r--r-- | usr.bin/rcs/rcsmerge.c | 4 | ||||
-rw-r--r-- | usr.bin/rcs/rcsprog.c | 423 | ||||
-rw-r--r-- | usr.bin/rcs/rcsprog.h | 13 | ||||
-rw-r--r-- | usr.bin/rcs/rcsutil.c | 445 | ||||
-rw-r--r-- | usr.bin/rcs/rcsutil.h | 45 | ||||
-rw-r--r-- | usr.bin/rcs/rlog.c | 4 |
11 files changed, 513 insertions, 444 deletions
diff --git a/usr.bin/rcs/Makefile b/usr.bin/rcs/Makefile index e4ec2df4151..3c60706be19 100644 --- a/usr.bin/rcs/Makefile +++ b/usr.bin/rcs/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.30 2006/04/02 02:42:33 ray Exp $ +# $OpenBSD: Makefile,v 1.31 2006/04/21 17:17:29 xsa Exp $ .PATH: ${.CURDIR}/../cvs @@ -6,8 +6,8 @@ PROG= rcs MAN= ci.1 co.1 ident.1 rcs.1 rcsclean.1 rcsdiff.1 rcsmerge.1 rlog.1 SRCS= ci.c co.c ident.c rcsclean.c rcsdiff.c rcsmerge.c rcsprog.c rlog.c \ - buf.c date.y diff.c diff3.c fatal.c log.c rcs.c rcsnum.c rcstime.c \ - util.c worklist.c xmalloc.c + rcsutil.c buf.c date.y diff.c diff3.c fatal.c log.c rcs.c rcsnum.c \ + rcstime.c util.c worklist.c xmalloc.c CPPFLAGS+=-I${.CURDIR}/../cvs -DRCSPROG diff --git a/usr.bin/rcs/ci.c b/usr.bin/rcs/ci.c index 671f9d7107d..974a755d597 100644 --- a/usr.bin/rcs/ci.c +++ b/usr.bin/rcs/ci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ci.c,v 1.155 2006/04/21 14:18:26 xsa Exp $ */ +/* $OpenBSD: ci.c,v 1.156 2006/04/21 17:17:29 xsa Exp $ */ /* * Copyright (c) 2005, 2006 Niall O'Higgins <niallo@openbsd.org> * All rights reserved. @@ -234,7 +234,8 @@ checkin_main(int argc, char **argv) * Test for existence of ,v file. If we are expected to * create one, set NEWFILE flag. */ - if (rcs_statfile(pb.filename, pb.fpath, sizeof(pb.fpath)) < 0) { + if (rcs_statfile(pb.filename, pb.fpath, + sizeof(pb.fpath), pb.flags) < 0) { if (pb.openflags & RCS_CREATE) pb.flags |= NEWFILE; else { diff --git a/usr.bin/rcs/co.c b/usr.bin/rcs/co.c index 6012e92494d..5172d1219c1 100644 --- a/usr.bin/rcs/co.c +++ b/usr.bin/rcs/co.c @@ -1,4 +1,4 @@ -/* $OpenBSD: co.c,v 1.81 2006/04/21 14:18:26 xsa Exp $ */ +/* $OpenBSD: co.c,v 1.82 2006/04/21 17:17:29 xsa Exp $ */ /* * Copyright (c) 2005 Joris Vink <joris@openbsd.org> * All rights reserved. @@ -152,7 +152,7 @@ checkout_main(int argc, char **argv) fatal("getlogin failed"); for (i = 0; i < argc; i++) { - if (rcs_statfile(argv[i], fpath, sizeof(fpath)) < 0) + if (rcs_statfile(argv[i], fpath, sizeof(fpath), flags) < 0) continue; if (!(flags & QUIET)) diff --git a/usr.bin/rcs/rcsclean.c b/usr.bin/rcs/rcsclean.c index 9df700ad56d..16790e8e832 100644 --- a/usr.bin/rcs/rcsclean.c +++ b/usr.bin/rcs/rcsclean.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rcsclean.c,v 1.38 2006/04/21 14:18:26 xsa Exp $ */ +/* $OpenBSD: rcsclean.c,v 1.39 2006/04/21 17:17:29 xsa Exp $ */ /* * Copyright (c) 2005 Joris Vink <joris@openbsd.org> * All rights reserved. @@ -138,7 +138,7 @@ rcsclean_file(char *fname, const char *rev_str) file = NULL; rev = NULL; - if (rcs_statfile(fname, fpath, sizeof(fpath)) < 0) + if (rcs_statfile(fname, fpath, sizeof(fpath), flags) < 0) goto out; if ((file = rcs_open(fpath, RCS_RDWR)) == NULL) diff --git a/usr.bin/rcs/rcsdiff.c b/usr.bin/rcs/rcsdiff.c index aa7328f50b4..e5ccfe84f70 100644 --- a/usr.bin/rcs/rcsdiff.c +++ b/usr.bin/rcs/rcsdiff.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rcsdiff.c,v 1.52 2006/04/21 14:18:26 xsa Exp $ */ +/* $OpenBSD: rcsdiff.c,v 1.53 2006/04/21 17:17:29 xsa Exp $ */ /* * Copyright (c) 2005 Joris Vink <joris@openbsd.org> * All rights reserved. @@ -109,7 +109,7 @@ rcsdiff_main(int argc, char **argv) } for (i = 0; i < argc; i++) { - if (rcs_statfile(argv[i], fpath, sizeof(fpath)) < 0) + if (rcs_statfile(argv[i], fpath, sizeof(fpath), flags) < 0) continue; if ((file = rcs_open(fpath, RCS_READ|RCS_PARSE_FULLY)) == NULL) diff --git a/usr.bin/rcs/rcsmerge.c b/usr.bin/rcs/rcsmerge.c index 278aa214845..1203151a026 100644 --- a/usr.bin/rcs/rcsmerge.c +++ b/usr.bin/rcs/rcsmerge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rcsmerge.c,v 1.29 2006/04/21 14:18:26 xsa Exp $ */ +/* $OpenBSD: rcsmerge.c,v 1.30 2006/04/21 17:17:29 xsa Exp $ */ /* * Copyright (c) 2005, 2006 Xavier Santolaria <xsa@openbsd.org> * All rights reserved. @@ -104,7 +104,7 @@ rcsmerge_main(int argc, char **argv) } for (i = 0; i < argc; i++) { - if (rcs_statfile(argv[i], fpath, sizeof(fpath)) < 0) + if (rcs_statfile(argv[i], fpath, sizeof(fpath), flags) < 0) continue; if ((file = rcs_open(fpath, RCS_READ)) == NULL) diff --git a/usr.bin/rcs/rcsprog.c b/usr.bin/rcs/rcsprog.c index dd02a1f7fb0..866ee2c696d 100644 --- a/usr.bin/rcs/rcsprog.c +++ b/usr.bin/rcs/rcsprog.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rcsprog.c,v 1.111 2006/04/21 14:42:12 xsa Exp $ */ +/* $OpenBSD: rcsprog.c,v 1.112 2006/04/21 17:17:29 xsa Exp $ */ /* * Copyright (c) 2005 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -36,7 +36,6 @@ const char rcs_version[] = "OpenCVS RCS version 3.6"; -int flags; int rcsflags; int rcs_optind; char *rcs_optarg; @@ -72,57 +71,6 @@ sighdlr(int sig) _exit(1); } -/* - * Allocate an RCSNUM and store in <rev>. - */ -void -rcs_set_rev(const char *str, RCSNUM **rev) -{ - if (str == NULL || (*rev = rcsnum_parse(str)) == NULL) - fatal("bad revision number '%s'", str); -} - -/* - * rcs_get_mtime() - * - * Get <filename> last modified time. - * Returns last modified time on success, or -1 on failure. - */ -time_t -rcs_get_mtime(const char *filename) -{ - struct stat st; - time_t mtime; - - if (stat(filename, &st) == -1) { - warn("%s", filename); - return (-1); - } - mtime = (time_t)st.st_mtimespec.tv_sec; - - return (mtime); -} - -/* - * rcs_set_mtime() - * - * Set <filename> last modified time to <mtime> if it's not set to -1. - */ -void -rcs_set_mtime(const char *filename, time_t mtime) -{ - static struct timeval tv[2]; - - if (mtime == -1) - return; - - tv[0].tv_sec = mtime; - tv[1].tv_sec = tv[0].tv_sec; - - if (utimes(filename, tv) == -1) - fatal("error setting utimes: %s", strerror(errno)); -} - int rcs_init(char *envstr, char **argv, int argvlen) { @@ -160,261 +108,6 @@ rcs_init(char *envstr, char **argv, int argvlen) } int -rcs_getopt(int argc, char **argv, const char *optstr) -{ - char *a; - const char *c; - static int i = 1; - int opt, hasargument, ret; - - hasargument = 0; - rcs_optarg = NULL; - - if (i >= argc) - return (-1); - - a = argv[i++]; - if (*a++ != '-') - return (-1); - - ret = 0; - opt = *a; - for (c = optstr; *c != '\0'; c++) { - if (*c == opt) { - a++; - ret = opt; - - if (*(c + 1) == ':') { - if (*(c + 2) == ':') { - if (*a != '\0') - hasargument = 1; - } else { - if (*a != '\0') { - hasargument = 1; - } else { - ret = 1; - break; - } - } - } - - if (hasargument == 1) - rcs_optarg = a; - - if (ret == opt) - rcs_optind++; - break; - } - } - - if (ret == 0) - warnx("unknown option -%c", opt); - else if (ret == 1) - warnx("missing argument for option -%c", opt); - - return (ret); -} - -/* - * rcs_choosefile() - * - * Given a relative filename, decide where the corresponding RCS file - * should be. Tries each extension until a file is found. If no file - * was found, returns a path with the first extension. - * - * Returns pointer to a char array on success, NULL on failure. - */ -char * -rcs_choosefile(const char *filename) -{ - struct stat sb; - char *p, *ext, name[MAXPATHLEN], *next, *ptr, rcsdir[MAXPATHLEN], - *ret, *suffixes, rcspath[MAXPATHLEN]; - - /* If -x flag was not given, use default. */ - if (rcs_suffixes == NULL) - rcs_suffixes = RCS_DEFAULT_SUFFIX; - - /* - * If `filename' contains a directory, `rcspath' contains that - * directory, including a trailing slash. Otherwise `rcspath' - * contains an empty string. - */ - if (strlcpy(rcspath, filename, sizeof(rcspath)) >= sizeof(rcspath)) - return (NULL); - /* If `/' is found, end string after `/'. */ - if ((ptr = strrchr(rcspath, '/')) != NULL) - *(++ptr) = '\0'; - else - rcspath[0] = '\0'; - - /* Append RCS/ to `rcspath' if it exists. */ - if (strlcpy(rcsdir, rcspath, sizeof(rcsdir)) >= sizeof(rcsdir) || - strlcat(rcsdir, RCSDIR, sizeof(rcsdir)) >= sizeof(rcsdir)) - return (NULL); - if (stat(rcsdir, &sb) == 0 && (sb.st_mode & S_IFDIR)) - if (strlcpy(rcspath, rcsdir, sizeof(rcspath)) >= sizeof(rcspath) || - strlcat(rcspath, "/", sizeof(rcspath)) >= sizeof(rcspath)) - return (NULL); - - /* Name of file without path. */ - if ((ptr = strrchr(filename, '/')) == NULL) { - if (strlcpy(name, filename, sizeof(name)) >= sizeof(name)) - return (NULL); - } else { - /* Skip `/'. */ - if (strlcpy(name, ptr + 1, sizeof(name)) >= sizeof(name)) - return (NULL); - } - - /* Name of RCS file without an extension. */ - if (strlcat(rcspath, name, sizeof(rcspath)) >= sizeof(rcspath)) - return (NULL); - - /* - * If only the empty suffix was given, use existing rcspath. - * This ensures that there is at least one suffix for strsep(). - */ - if (strcmp(rcs_suffixes, "") == 0) { - ret = xstrdup(rcspath); - return (ret); - } - - /* - * Cycle through slash-separated `rcs_suffixes', appending each - * extension to `rcspath' and testing if the file exists. If it - * does, return that string. Otherwise return path with first - * extension. - */ - suffixes = xstrdup(rcs_suffixes); - for (ret = NULL, next = suffixes; (ext = strsep(&next, "/")) != NULL;) { - char fpath[MAXPATHLEN]; - - if ((p = strrchr(rcspath, ',')) != NULL) { - if (!strcmp(p, ext)) { - if (stat(rcspath, &sb) == 0) { - ret = xstrdup(rcspath); - goto out; - } - } - - continue; - } - - /* Construct RCS file path. */ - if (strlcpy(fpath, rcspath, sizeof(fpath)) >= sizeof(fpath) || - strlcat(fpath, ext, sizeof(fpath)) >= sizeof(fpath)) - goto out; - - /* Don't use `filename' as RCS file. */ - if (strcmp(fpath, filename) == 0) - continue; - - if (stat(fpath, &sb) == 0) { - ret = xstrdup(fpath); - goto out; - } - } - - /* - * `ret' is still NULL. No RCS file with any extension exists - * so we use the first extension. - * - * `suffixes' should now be NUL separated, so the first - * extension can be read just by reading `suffixes'. - */ - if (strlcat(rcspath, suffixes, sizeof(rcspath)) >= - sizeof(rcspath)) - goto out; - ret = xstrdup(rcspath); - -out: - /* `ret' may be NULL, which indicates an error. */ - xfree(suffixes); - return (ret); -} - -/* - * Find the name of an RCS file, given a file name `fname'. If an RCS - * file is found, the name is copied to the `len' sized buffer `out'. - * Returns 0 if RCS file was found, -1 otherwise. - */ -int -rcs_statfile(char *fname, char *out, size_t len) -{ - struct stat st; - char *rcspath; - - if ((rcspath = rcs_choosefile(fname)) == NULL) - fatal("rcs_statfile: path truncation"); - - /* Error out if file not found and we are not creating one. */ - if (stat(rcspath, &st) == -1 && !(flags & RCS_CREATE)) { - if (strcmp(__progname, "rcsclean") != 0 && - strcmp(__progname, "ci") != 0) - warn("%s", rcspath); - xfree(rcspath); - return (-1); - } - - if (strlcpy(out, rcspath, len) >= len) - fatal("rcs_statfile: path truncation"); - - xfree(rcspath); - - return (0); -} - -/* - * Set <str> to <new_str>. Print warning if <str> is redefined. - */ -void -rcs_setrevstr(char **str, char *new_str) -{ - if (new_str == NULL) - return; - if (*str != NULL) - warnx("redefinition of revision number"); - *str = new_str; -} - -/* - * Set <str1> or <str2> to <new_str>, depending on which is not set. - * If both are set, error out. - */ -void -rcs_setrevstr2(char **str1, char **str2, char *new_str) -{ - if (new_str == NULL) - return; - if (*str1 == NULL) - *str1 = new_str; - else if (*str2 == NULL) - *str2 = new_str; - else - fatal("too many revision numbers"); -} - -/* - * Get revision from file. The revision can be specified as a symbol or - * a revision number. - */ -RCSNUM * -rcs_getrevnum(const char *rev_str, RCSFILE *file) -{ - RCSNUM *rev; - - /* Search for symbol. */ - rev = rcs_sym_getrev(file, rev_str); - - /* Search for revision number. */ - if (rev == NULL) - rev = rcsnum_parse(rev_str); - - return (rev); -} - -int main(int argc, char **argv) { u_int i; @@ -485,7 +178,7 @@ rcs_usage(void) int rcs_main(int argc, char **argv) { - int i, j, ch, kflag, lkmode; + int i, j, ch, flags, kflag, lkmode; char fpath[MAXPATHLEN], ofpath[MAXPATHLEN]; char *logstr, *logmsg, *nflag, *descfile; char *alist, *comment, *elist, *lrev, *urev, *orange; @@ -510,7 +203,8 @@ rcs_main(int argc, char **argv) while ((ch = rcs_getopt(argc, argv, RCSPROG_OPTSTRING)) != -1) { switch (ch) { case 'A': - if (rcs_statfile(rcs_optarg, ofpath, sizeof(ofpath)) < 0) + if (rcs_statfile(rcs_optarg, ofpath, + sizeof(ofpath), flags) < 0) exit(1); rcsflags |= CO_ACLAPPEND; break; @@ -610,7 +304,7 @@ rcs_main(int argc, char **argv) } for (i = 0; i < argc; i++) { - if (rcs_statfile(argv[i], fpath, sizeof(fpath)) < 0) + if (rcs_statfile(argv[i], fpath, sizeof(fpath), flags) < 0) continue; if (!(rcsflags & QUIET)) @@ -875,110 +569,3 @@ rcs_set_description(RCSFILE *file, const char *in) rcs_desc_set(file, content); xfree(content); } - -/* - * Prompt for and store user's input in an allocated string. - * - * Returns the string's pointer. - */ -char * -rcs_prompt(const char *prompt) -{ - BUF *bp; - size_t len; - char *buf; - - bp = cvs_buf_alloc(0, BUF_AUTOEXT); - if (isatty(STDIN_FILENO)) - (void)fprintf(stderr, "%s", prompt); - if (isatty(STDIN_FILENO)) - (void)fprintf(stderr, ">> "); - while ((buf = fgetln(stdin, &len)) != NULL) { - /* The last line may not be EOL terminated. */ - if (buf[0] == '.' && (len == 1 || buf[1] == '\n')) - break; - else - cvs_buf_append(bp, buf, len); - - if (isatty(STDIN_FILENO)) - (void)fprintf(stderr, ">> "); - } - cvs_buf_putc(bp, '\0'); - - return (cvs_buf_release(bp)); -} - -u_int -rcs_rev_select(RCSFILE *file, char *range) -{ - int i; - u_int nrev; - char *ep; - char *lstr, *rstr; - struct rcs_delta *rdp; - struct cvs_argvector *revargv, *revrange; - RCSNUM lnum, rnum; - - nrev = 0; - (void)memset(&lnum, 0, sizeof(lnum)); - (void)memset(&rnum, 0, sizeof(rnum)); - - if (range == NULL) { - TAILQ_FOREACH(rdp, &file->rf_delta, rd_list) - if (rcsnum_cmp(rdp->rd_num, file->rf_head, 0) == 0) { - rdp->rd_flags |= RCS_RD_SELECT; - return (1); - } - return (0); - } - - revargv = cvs_strsplit(range, ","); - for (i = 0; revargv->argv[i] != NULL; i++) { - revrange = cvs_strsplit(revargv->argv[i], ":"); - if (revrange->argv[0] == NULL) - /* should not happen */ - fatal("invalid revision range: %s", revargv->argv[i]); - else if (revrange->argv[1] == NULL) - lstr = rstr = revrange->argv[0]; - else { - if (revrange->argv[2] != NULL) - fatal("invalid revision range: %s", - revargv->argv[i]); - lstr = revrange->argv[0]; - rstr = revrange->argv[1]; - if (strcmp(lstr, "") == 0) - lstr = NULL; - if (strcmp(rstr, "") == 0) - rstr = NULL; - } - - if (lstr == NULL) - lstr = RCS_HEAD_INIT; - if (rcsnum_aton(lstr, &ep, &lnum) == 0 || (*ep != '\0')) - fatal("invalid revision: %s", lstr); - - if (rstr != NULL) { - if (rcsnum_aton(rstr, &ep, &rnum) == 0 || (*ep != '\0')) - fatal("invalid revision: %s", rstr); - } else - rcsnum_cpy(file->rf_head, &rnum, 0); - - cvs_argv_destroy(revrange); - - TAILQ_FOREACH(rdp, &file->rf_delta, rd_list) - if (rcsnum_cmp(rdp->rd_num, &lnum, 0) <= 0 && - rcsnum_cmp(rdp->rd_num, &rnum, 0) >= 0 && - !(rdp->rd_flags & RCS_RD_SELECT)) { - rdp->rd_flags |= RCS_RD_SELECT; - nrev++; - } - } - cvs_argv_destroy(revargv); - - if (lnum.rn_id != NULL) - xfree(lnum.rn_id); - if (rnum.rn_id != NULL) - xfree(rnum.rn_id); - - return (nrev); -} diff --git a/usr.bin/rcs/rcsprog.h b/usr.bin/rcs/rcsprog.h index a5f5bda7b7f..2c3011ffabe 100644 --- a/usr.bin/rcs/rcsprog.h +++ b/usr.bin/rcs/rcsprog.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rcsprog.h,v 1.52 2006/04/21 14:18:26 xsa Exp $ */ +/* $OpenBSD: rcsprog.h,v 1.53 2006/04/21 17:17:29 xsa Exp $ */ /* * Copyright (c) 2005 Joris Vink <joris@openbsd.org> * All rights reserved. @@ -31,6 +31,7 @@ #include "log.h" #include "rcs.h" +#include "rcsutil.h" #include "worklist.h" #include "util.h" #include "xmalloc.h" @@ -111,16 +112,6 @@ void rcsmerge_usage(void); int rcs_init(char *, char **, int); int rcs_getopt(int, char **, const char *); int rcs_main(int, char **); -void rcs_set_mtime(const char *, time_t); -char *rcs_choosefile(const char *); -int rcs_statfile(char *, char *, size_t); -time_t rcs_get_mtime(const char *); -RCSNUM *rcs_getrevnum(const char *, RCSFILE *); -char *rcs_prompt(const char *); -u_int rcs_rev_select(RCSFILE *, char *); -void rcs_set_rev(const char *, RCSNUM **); -void rcs_setrevstr(char **, char *); -void rcs_setrevstr2(char **, char **, char *); void rcs_usage(void); void (*usage)(void); diff --git a/usr.bin/rcs/rcsutil.c b/usr.bin/rcs/rcsutil.c new file mode 100644 index 00000000000..9e0dba9d535 --- /dev/null +++ b/usr.bin/rcs/rcsutil.c @@ -0,0 +1,445 @@ +/* $OpenBSD: rcsutil.c,v 1.1 2006/04/21 17:17:29 xsa Exp $ */ +/* + * Copyright (c) 2005, 2006 Joris Vink <joris@openbsd.org> + * Copyright (c) 2006 Xavier Santolaria <xsa@openbsd.org> + * Copyright (c) 2006 Niall O'Higgins <niallo@openbsd.org> + * Copyright (c) 2006 Ray Lai <ray@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 "includes.h" + +#include "rcsprog.h" + +/* + * rcs_get_mtime() + * + * Get <filename> last modified time. + * Returns last modified time on success, or -1 on failure. + */ +time_t +rcs_get_mtime(const char *filename) +{ + struct stat st; + time_t mtime; + + if (stat(filename, &st) == -1) { + warn("%s", filename); + return (-1); + } + mtime = (time_t)st.st_mtimespec.tv_sec; + + return (mtime); +} + +/* + * rcs_set_mtime() + * + * Set <filename> last modified time to <mtime> if it's not set to -1. + */ +void +rcs_set_mtime(const char *filename, time_t mtime) +{ + static struct timeval tv[2]; + + if (mtime == -1) + return; + + tv[0].tv_sec = mtime; + tv[1].tv_sec = tv[0].tv_sec; + + if (utimes(filename, tv) == -1) + fatal("error setting utimes: %s", strerror(errno)); +} + +int +rcs_getopt(int argc, char **argv, const char *optstr) +{ + char *a; + const char *c; + static int i = 1; + int opt, hasargument, ret; + + hasargument = 0; + rcs_optarg = NULL; + + if (i >= argc) + return (-1); + + a = argv[i++]; + if (*a++ != '-') + return (-1); + + ret = 0; + opt = *a; + for (c = optstr; *c != '\0'; c++) { + if (*c == opt) { + a++; + ret = opt; + + if (*(c + 1) == ':') { + if (*(c + 2) == ':') { + if (*a != '\0') + hasargument = 1; + } else { + if (*a != '\0') { + hasargument = 1; + } else { + ret = 1; + break; + } + } + } + + if (hasargument == 1) + rcs_optarg = a; + + if (ret == opt) + rcs_optind++; + break; + } + } + + if (ret == 0) + warnx("unknown option -%c", opt); + else if (ret == 1) + warnx("missing argument for option -%c", opt); + + return (ret); +} + +/* + * rcs_choosefile() + * + * Given a relative filename, decide where the corresponding RCS file + * should be. Tries each extension until a file is found. If no file + * was found, returns a path with the first extension. + * + * Returns pointer to a char array on success, NULL on failure. + */ +char * +rcs_choosefile(const char *filename) +{ + struct stat sb; + char *p, *ext, name[MAXPATHLEN], *next, *ptr, rcsdir[MAXPATHLEN], + *ret, *suffixes, rcspath[MAXPATHLEN]; + + /* If -x flag was not given, use default. */ + if (rcs_suffixes == NULL) + rcs_suffixes = RCS_DEFAULT_SUFFIX; + + /* + * If `filename' contains a directory, `rcspath' contains that + * directory, including a trailing slash. Otherwise `rcspath' + * contains an empty string. + */ + if (strlcpy(rcspath, filename, sizeof(rcspath)) >= sizeof(rcspath)) + return (NULL); + /* If `/' is found, end string after `/'. */ + if ((ptr = strrchr(rcspath, '/')) != NULL) + *(++ptr) = '\0'; + else + rcspath[0] = '\0'; + + /* Append RCS/ to `rcspath' if it exists. */ + if (strlcpy(rcsdir, rcspath, sizeof(rcsdir)) >= sizeof(rcsdir) || + strlcat(rcsdir, RCSDIR, sizeof(rcsdir)) >= sizeof(rcsdir)) + return (NULL); + if (stat(rcsdir, &sb) == 0 && (sb.st_mode & S_IFDIR)) + if (strlcpy(rcspath, rcsdir, sizeof(rcspath)) >= sizeof(rcspath) || + strlcat(rcspath, "/", sizeof(rcspath)) >= sizeof(rcspath)) + return (NULL); + + /* Name of file without path. */ + if ((ptr = strrchr(filename, '/')) == NULL) { + if (strlcpy(name, filename, sizeof(name)) >= sizeof(name)) + return (NULL); + } else { + /* Skip `/'. */ + if (strlcpy(name, ptr + 1, sizeof(name)) >= sizeof(name)) + return (NULL); + } + + /* Name of RCS file without an extension. */ + if (strlcat(rcspath, name, sizeof(rcspath)) >= sizeof(rcspath)) + return (NULL); + + /* + * If only the empty suffix was given, use existing rcspath. + * This ensures that there is at least one suffix for strsep(). + */ + if (strcmp(rcs_suffixes, "") == 0) { + ret = xstrdup(rcspath); + return (ret); + } + + /* + * Cycle through slash-separated `rcs_suffixes', appending each + * extension to `rcspath' and testing if the file exists. If it + * does, return that string. Otherwise return path with first + * extension. + */ + suffixes = xstrdup(rcs_suffixes); + for (ret = NULL, next = suffixes; (ext = strsep(&next, "/")) != NULL;) { + char fpath[MAXPATHLEN]; + + if ((p = strrchr(rcspath, ',')) != NULL) { + if (!strcmp(p, ext)) { + if (stat(rcspath, &sb) == 0) { + ret = xstrdup(rcspath); + goto out; + } + } + + continue; + } + + /* Construct RCS file path. */ + if (strlcpy(fpath, rcspath, sizeof(fpath)) >= sizeof(fpath) || + strlcat(fpath, ext, sizeof(fpath)) >= sizeof(fpath)) + goto out; + + /* Don't use `filename' as RCS file. */ + if (strcmp(fpath, filename) == 0) + continue; + + if (stat(fpath, &sb) == 0) { + ret = xstrdup(fpath); + goto out; + } + } + + /* + * `ret' is still NULL. No RCS file with any extension exists + * so we use the first extension. + * + * `suffixes' should now be NUL separated, so the first + * extension can be read just by reading `suffixes'. + */ + if (strlcat(rcspath, suffixes, sizeof(rcspath)) >= + sizeof(rcspath)) + goto out; + ret = xstrdup(rcspath); + +out: + /* `ret' may be NULL, which indicates an error. */ + xfree(suffixes); + return (ret); +} + +/* + * Find the name of an RCS file, given a file name `fname'. If an RCS + * file is found, the name is copied to the `len' sized buffer `out'. + * Returns 0 if RCS file was found, -1 otherwise. + */ +int +rcs_statfile(char *fname, char *out, size_t len, int flags) +{ + struct stat st; + char *rcspath; + + if ((rcspath = rcs_choosefile(fname)) == NULL) + fatal("rcs_statfile: path truncation"); + + /* Error out if file not found and we are not creating one. */ + if (stat(rcspath, &st) == -1 && !(flags & RCS_CREATE)) { + if (strcmp(__progname, "rcsclean") != 0 && + strcmp(__progname, "ci") != 0) + warn("%s", rcspath); + xfree(rcspath); + return (-1); + } + + if (strlcpy(out, rcspath, len) >= len) + fatal("rcs_statfile: path truncation"); + + xfree(rcspath); + + return (0); +} + +/* + * Allocate an RCSNUM and store in <rev>. + */ +void +rcs_set_rev(const char *str, RCSNUM **rev) +{ + if (str == NULL || (*rev = rcsnum_parse(str)) == NULL) + fatal("bad revision number '%s'", str); +} + +/* + * Set <str> to <new_str>. Print warning if <str> is redefined. + */ +void +rcs_setrevstr(char **str, char *new_str) +{ + if (new_str == NULL) + return; + if (*str != NULL) + warnx("redefinition of revision number"); + *str = new_str; +} + +/* + * Set <str1> or <str2> to <new_str>, depending on which is not set. + * If both are set, error out. + */ +void +rcs_setrevstr2(char **str1, char **str2, char *new_str) +{ + if (new_str == NULL) + return; + if (*str1 == NULL) + *str1 = new_str; + else if (*str2 == NULL) + *str2 = new_str; + else + fatal("too many revision numbers"); +} + +/* + * Get revision from file. The revision can be specified as a symbol or + * a revision number. + */ +RCSNUM * +rcs_getrevnum(const char *rev_str, RCSFILE *file) +{ + RCSNUM *rev; + + /* Search for symbol. */ + rev = rcs_sym_getrev(file, rev_str); + + /* Search for revision number. */ + if (rev == NULL) + rev = rcsnum_parse(rev_str); + + return (rev); +} + +/* + * Prompt for and store user's input in an allocated string. + * + * Returns the string's pointer. + */ +char * +rcs_prompt(const char *prompt) +{ + BUF *bp; + size_t len; + char *buf; + + bp = cvs_buf_alloc(0, BUF_AUTOEXT); + if (isatty(STDIN_FILENO)) + (void)fprintf(stderr, "%s", prompt); + if (isatty(STDIN_FILENO)) + (void)fprintf(stderr, ">> "); + while ((buf = fgetln(stdin, &len)) != NULL) { + /* The last line may not be EOL terminated. */ + if (buf[0] == '.' && (len == 1 || buf[1] == '\n')) + break; + else + cvs_buf_append(bp, buf, len); + + if (isatty(STDIN_FILENO)) + (void)fprintf(stderr, ">> "); + } + cvs_buf_putc(bp, '\0'); + + return (cvs_buf_release(bp)); +} + +u_int +rcs_rev_select(RCSFILE *file, char *range) +{ + int i; + u_int nrev; + char *ep; + char *lstr, *rstr; + struct rcs_delta *rdp; + struct cvs_argvector *revargv, *revrange; + RCSNUM lnum, rnum; + + nrev = 0; + (void)memset(&lnum, 0, sizeof(lnum)); + (void)memset(&rnum, 0, sizeof(rnum)); + + if (range == NULL) { + TAILQ_FOREACH(rdp, &file->rf_delta, rd_list) + if (rcsnum_cmp(rdp->rd_num, file->rf_head, 0) == 0) { + rdp->rd_flags |= RCS_RD_SELECT; + return (1); + } + return (0); + } + + revargv = cvs_strsplit(range, ","); + for (i = 0; revargv->argv[i] != NULL; i++) { + revrange = cvs_strsplit(revargv->argv[i], ":"); + if (revrange->argv[0] == NULL) + /* should not happen */ + fatal("invalid revision range: %s", revargv->argv[i]); + else if (revrange->argv[1] == NULL) + lstr = rstr = revrange->argv[0]; + else { + if (revrange->argv[2] != NULL) + fatal("invalid revision range: %s", + revargv->argv[i]); + lstr = revrange->argv[0]; + rstr = revrange->argv[1]; + if (strcmp(lstr, "") == 0) + lstr = NULL; + if (strcmp(rstr, "") == 0) + rstr = NULL; + } + + if (lstr == NULL) + lstr = RCS_HEAD_INIT; + if (rcsnum_aton(lstr, &ep, &lnum) == 0 || (*ep != '\0')) + fatal("invalid revision: %s", lstr); + + if (rstr != NULL) { + if (rcsnum_aton(rstr, &ep, &rnum) == 0 || (*ep != '\0')) + fatal("invalid revision: %s", rstr); + } else + rcsnum_cpy(file->rf_head, &rnum, 0); + + cvs_argv_destroy(revrange); + + TAILQ_FOREACH(rdp, &file->rf_delta, rd_list) + if (rcsnum_cmp(rdp->rd_num, &lnum, 0) <= 0 && + rcsnum_cmp(rdp->rd_num, &rnum, 0) >= 0 && + !(rdp->rd_flags & RCS_RD_SELECT)) { + rdp->rd_flags |= RCS_RD_SELECT; + nrev++; + } + } + cvs_argv_destroy(revargv); + + if (lnum.rn_id != NULL) + xfree(lnum.rn_id); + if (rnum.rn_id != NULL) + xfree(rnum.rn_id); + + return (nrev); +} diff --git a/usr.bin/rcs/rcsutil.h b/usr.bin/rcs/rcsutil.h new file mode 100644 index 00000000000..717a75d3916 --- /dev/null +++ b/usr.bin/rcs/rcsutil.h @@ -0,0 +1,45 @@ +/* $OpenBSD: rcsutil.h,v 1.1 2006/04/21 17:17:29 xsa Exp $ */ +/* + * Copyright (c) 2006 Xavier Santolaria <xsa@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. + */ + +#ifndef RCSUTIL_H +#define RCSUTIL_H + +#include "rcs.h" + +/* rcsutil.c */ +int rcs_getopt(int, char **, const char *); +void rcs_set_mtime(const char *, time_t); +char *rcs_choosefile(const char *); +int rcs_statfile(char *, char *, size_t, int); +time_t rcs_get_mtime(const char *); +RCSNUM *rcs_getrevnum(const char *, RCSFILE *); +char *rcs_prompt(const char *); +u_int rcs_rev_select(RCSFILE *, char *); +void rcs_set_rev(const char *, RCSNUM **); +void rcs_setrevstr(char **, char *); +void rcs_setrevstr2(char **, char **, char *); + +#endif /* RCSUTIL_H */ diff --git a/usr.bin/rcs/rlog.c b/usr.bin/rcs/rlog.c index d8af2d79989..a4985bafe5b 100644 --- a/usr.bin/rcs/rlog.c +++ b/usr.bin/rcs/rlog.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rlog.c,v 1.48 2006/04/21 14:18:26 xsa Exp $ */ +/* $OpenBSD: rlog.c,v 1.49 2006/04/21 17:17:29 xsa Exp $ */ /* * Copyright (c) 2005 Joris Vink <joris@openbsd.org> * Copyright (c) 2005, 2006 Xavier Santolaria <xsa@openbsd.org> @@ -137,7 +137,7 @@ rlog_main(int argc, char **argv) } for (i = 0; i < argc; i++) { - if (rcs_statfile(argv[i], fpath, sizeof(fpath)) < 0) + if (rcs_statfile(argv[i], fpath, sizeof(fpath), 0) < 0) continue; if ((file = rcs_open(fpath, RCS_READ|RCS_PARSE_FULLY)) == NULL) |