aboutsummaryrefslogtreecommitdiff
path: root/gnu/usr.bin/rcs/rcsclean
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/rcs/rcsclean')
-rw-r--r--gnu/usr.bin/rcs/rcsclean/Makefile8
-rw-r--r--gnu/usr.bin/rcs/rcsclean/rcsclean.1177
-rw-r--r--gnu/usr.bin/rcs/rcsclean/rcsclean.c297
3 files changed, 482 insertions, 0 deletions
diff --git a/gnu/usr.bin/rcs/rcsclean/Makefile b/gnu/usr.bin/rcs/rcsclean/Makefile
new file mode 100644
index 000000000000..2651a3f4b61d
--- /dev/null
+++ b/gnu/usr.bin/rcs/rcsclean/Makefile
@@ -0,0 +1,8 @@
+PROG= rcsclean
+SRCS= rcsclean.c
+CFLAGS+= -I${.CURDIR}/../lib
+LDADD= ${LIBRCS}
+DPADD= ${LIBRCS}
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/rcs/rcsclean/rcsclean.1 b/gnu/usr.bin/rcs/rcsclean/rcsclean.1
new file mode 100644
index 000000000000..88d8305963ad
--- /dev/null
+++ b/gnu/usr.bin/rcs/rcsclean/rcsclean.1
@@ -0,0 +1,177 @@
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id: rcsclean.1,v 1.1.1.1 1993/06/18 04:22:15 jkh Exp $
+.ds r \&\s-1RCS\s0
+.if n .ds - \%--
+.if t .ds - \(em
+.TH RCSCLEAN 1 \*(Dt GNU
+.SH NAME
+rcsclean \- clean up working files
+.SH SYNOPSIS
+.B rcsclean
+.RI [ options "] [ " file " .\|.\|. ]"
+.SH DESCRIPTION
+.B rcsclean
+removes working files that were checked out and never modified.
+For each
+.I file
+given,
+.B rcsclean
+compares the working file and a revision in the corresponding
+\*r file. If it finds a difference, it does nothing.
+Otherwise, it first unlocks the revision if the
+.B \-u
+option is given,
+and then removes the working file
+unless the working file is writable and the revision is locked.
+It logs its actions by outputting the corresponding
+.B "rcs \-u"
+and
+.B "rm \-f"
+commands on the standard output.
+.PP
+If no
+.I file
+is given, all working files in the current directory are cleaned.
+Pathnames matching an \*r suffix denote \*r files;
+all others denote working files.
+Names are paired as explained in
+.BR ci (1).
+.PP
+The number of the revision to which the working file is compared
+may be attached to any of the options
+.BR \-n ,
+.BR \-q ,
+.BR \-r ,
+or
+.BR \-u .
+If no revision number is specified, then if the
+.B \-u
+option is given and the caller has one revision locked,
+.B rcsclean
+uses that revision; otherwise
+.B rcsclean
+uses the latest revision on the default branch, normally the root.
+.PP
+.B rcsclean
+is useful for
+.B clean
+targets in Makefiles.
+See also
+.BR rcsdiff (1),
+which prints out the differences,
+and
+.BR ci (1),
+which
+normally asks whether to check in a file
+if it was not changed.
+.SH OPTIONS
+.TP
+.BI \-k subst
+Use
+.I subst
+style keyword substitution when retrieving the revision for comparison.
+See
+.BR co (1)
+for details.
+.TP
+.BR \-n [\f2rev\fP]
+Do not actually remove any files or unlock any revisions.
+Using this option will tell you what
+.B rcsclean
+would do without actually doing it.
+.TP
+.BR \-q [\f2rev\fP]
+Do not log the actions taken on standard output.
+.TP
+.BR \-r [\f2rev\fP]
+This option has no effect other than specifying the revision for comparison.
+.TP
+.BR \-u [\f2rev\fP]
+Unlock the revision if it is locked and no difference is found.
+.TP
+.BI \-V n
+Emulate \*r version
+.IR n .
+See
+.BR co (1)
+for details.
+.TP
+.BI \-x "suffixes"
+Use
+.I suffixes
+to characterize \*r files.
+See
+.BR ci (1)
+for details.
+.SH EXAMPLES
+.LP
+.RS
+.ft 3
+rcsclean *.c *.h
+.ft
+.RE
+.LP
+removes all working files ending in
+.B .c
+or
+.B .h
+that were not changed
+since their checkout.
+.LP
+.RS
+.ft 3
+rcsclean
+.ft
+.RE
+.LP
+removes all working files in the current directory
+that were not changed since their checkout.
+.SH FILES
+.B rcsclean
+accesses files much as
+.BR ci (1)
+does.
+.SH ENVIRONMENT
+.TP
+.B \s-1RCSINIT\s0
+options prepended to the argument list, separated by spaces.
+A backslash escapes spaces within an option.
+The
+.B \s-1RCSINIT\s0
+options are prepended to the argument lists of most \*r commands.
+Useful
+.B \s-1RCSINIT\s0
+options include
+.BR \-q ,
+.BR \-V ,
+and
+.BR \-x .
+.SH DIAGNOSTICS
+The exit status is zero if and only if all operations were successful.
+Missing working files and \*r files are silently ignored.
+.SH IDENTIFICATION
+Author: Walter F. Tichy.
+.br
+Revision Number: \*(Rv; Release Date: \*(Dt.
+.br
+Copyright \(co 1982, 1988, 1989 by Walter F. Tichy.
+.br
+Copyright \(co 1990, 1991 by Paul Eggert.
+.SH "SEE ALSO"
+ci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1),
+rcsfile(5)
+.br
+Walter F. Tichy,
+\*r\*-A System for Version Control,
+.I "Software\*-Practice & Experience"
+.BR 15 ,
+7 (July 1985), 637-654.
+.SH BUGS
+At least one
+.I file
+must be given in older Unix versions that
+do not provide the needed directory scanning operations.
+.br
diff --git a/gnu/usr.bin/rcs/rcsclean/rcsclean.c b/gnu/usr.bin/rcs/rcsclean/rcsclean.c
new file mode 100644
index 000000000000..3f9b8a06dd3d
--- /dev/null
+++ b/gnu/usr.bin/rcs/rcsclean/rcsclean.c
@@ -0,0 +1,297 @@
+/* rcsclean - clean up working files */
+
+/* Copyright 1991 by 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Report problems and direct all questions to:
+
+ rcs-bugs@cs.purdue.edu
+
+*/
+
+#include "rcsbase.h"
+
+#if has_dirent
+ static int get_directory P((char const*,char***));
+#endif
+
+static int unlock P((struct hshentry *));
+static void cleanup P((void));
+
+static RILE *workptr;
+static int exitstatus;
+
+mainProg(rcscleanId, "rcsclean", "$Id: rcsclean.c,v 1.1.1.1 1993/06/18 04:22:15 jkh Exp $")
+{
+ static char const usage[] =
+ "\nrcsclean: usage: rcsclean [-ksubst] [-{nqru}[rev]] [-Vn] [-xsuffixes] [file ...]";
+
+ static struct buf revision;
+
+ char *a, **newargv;
+ char const *rev, *p;
+ int changelock, expmode, perform, unlocked, unlockflag, waslocked;
+ struct hshentries *deltas;
+ struct hshentry *delta;
+ struct stat workstat;
+
+ setrid();
+
+ expmode = -1;
+ rev = nil;
+ suffixes = X_DEFAULT;
+ perform = true;
+ unlockflag = false;
+
+ argc = getRCSINIT(argc, argv, &newargv);
+ argv = newargv;
+ for (;;) {
+ if (--argc <= 0) {
+# if has_dirent
+ argc = get_directory(".", &newargv);
+ argv = newargv;
+ break;
+# else
+ faterror("no file names specified");
+# endif
+ }
+ a = *++argv;
+ if (*a++ != '-')
+ break;
+ switch (*a++) {
+ case 'k':
+ if (0 <= expmode)
+ redefined('k');
+ if ((expmode = str2expmode(a)) < 0)
+ goto unknown;
+ break;
+
+ case 'n':
+ perform = false;
+ goto handle_revision;
+
+ case 'q':
+ quietflag = true;
+ /* fall into */
+ case 'r':
+ handle_revision:
+ if (*a) {
+ if (rev)
+ warn("redefinition of revision number");
+ rev = a;
+ }
+ break;
+
+ case 'u':
+ unlockflag = true;
+ goto handle_revision;
+
+ case 'V':
+ setRCSversion(*argv);
+ break;
+
+ case 'x':
+ suffixes = a;
+ break;
+
+ default:
+ unknown:
+ faterror("unknown option: %s%s", *argv, usage);
+ }
+ }
+
+ do {
+ ffree();
+
+ if (!(
+ 0 < pairfilenames(
+ argc, argv,
+ unlockflag&perform ? rcswriteopen : rcsreadopen,
+ true, true
+ ) &&
+ (workptr = Iopen(workfilename,FOPEN_R_WORK,&workstat))
+ ))
+ continue;
+
+ gettree();
+
+ p = 0;
+ if (rev) {
+ if (!fexpandsym(rev, &revision, workptr))
+ continue;
+ p = revision.string;
+ } else if (Head)
+ switch (unlockflag ? findlock(false,&delta) : 0) {
+ default:
+ continue;
+ case 0:
+ p = Dbranch ? Dbranch : "";
+ break;
+ case 1:
+ p = delta->num;
+ break;
+ }
+ delta = 0;
+ deltas = 0; /* Keep lint happy. */
+ if (p && !(delta = genrevs(p,(char*)0,(char*)0,(char*)0,&deltas)))
+ continue;
+
+ waslocked = delta && delta->lockedby;
+ locker_expansion = unlock(delta);
+ unlocked = locker_expansion & unlockflag;
+ changelock = unlocked & perform;
+ if (unlocked<waslocked && workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH))
+ continue;
+
+ if (!dorewrite(unlockflag, changelock))
+ continue;
+
+ if (0 <= expmode)
+ Expand = expmode;
+ else if (
+ waslocked &&
+ Expand == KEYVAL_EXPAND &&
+ WORKMODE(RCSstat.st_mode,true) == workstat.st_mode
+ )
+ Expand = KEYVALLOCK_EXPAND;
+
+ getdesc(false);
+
+ if (
+ !delta ? workstat.st_size!=0 :
+ 0 < rcsfcmp(
+ workptr, &workstat,
+ buildrevision(deltas, delta, (FILE*)0, false),
+ delta
+ )
+ )
+ continue;
+
+ if (quietflag < unlocked)
+ aprintf(stdout, "rcs -u%s %s\n", delta->num, RCSfilename);
+
+ if_advise_access(changelock && deltas->first != delta,
+ finptr, MADV_SEQUENTIAL
+ );
+ if (!donerewrite(changelock))
+ continue;
+
+ if (!quietflag)
+ aprintf(stdout, "rm -f %s\n", workfilename);
+ Izclose(&workptr);
+ if (perform && un_link(workfilename) != 0)
+ eerror(workfilename);
+
+ } while (cleanup(), ++argv, 0 < --argc);
+
+ tempunlink();
+ if (!quietflag)
+ Ofclose(stdout);
+ exitmain(exitstatus);
+}
+
+ static void
+cleanup()
+{
+ if (nerror) exitstatus = EXIT_FAILURE;
+ Izclose(&finptr);
+ Izclose(&workptr);
+ Ozclose(&fcopy);
+ Ozclose(&frewrite);
+ dirtempunlink();
+}
+
+#if lint
+# define exiterr rcscleanExit
+#endif
+ exiting void
+exiterr()
+{
+ dirtempunlink();
+ tempunlink();
+ _exit(EXIT_FAILURE);
+}
+
+ static int
+unlock(delta)
+ struct hshentry *delta;
+{
+ register struct lock **al, *l;
+
+ if (delta && delta->lockedby && strcmp(getcaller(),delta->lockedby)==0)
+ for (al = &Locks; (l = *al); al = &l->nextlock)
+ if (l->delta == delta) {
+ *al = l->nextlock;
+ delta->lockedby = 0;
+ return true;
+ }
+ return false;
+}
+
+#if has_dirent
+ static int
+get_directory(dirname, aargv)
+ char const *dirname;
+ char ***aargv;
+/*
+ * Put a vector of all DIRNAME's directory entries names into *AARGV.
+ * Ignore names of RCS files.
+ * Yield the number of entries found. Terminate the vector with 0.
+ * Allocate the storage for the vector and entry names.
+ * Do not sort the names. Do not include '.' and '..'.
+ */
+{
+ int i, entries = 0, entries_max = 64;
+ size_t chars = 0, chars_max = 1024;
+ size_t *offset = tnalloc(size_t, entries_max);
+ char *a = tnalloc(char, chars_max), **p;
+ DIR *d;
+ struct dirent *e;
+
+ if (!(d = opendir(dirname)))
+ efaterror(dirname);
+ while ((errno = 0, e = readdir(d))) {
+ char const *en = e->d_name;
+ size_t s = strlen(en) + 1;
+ if (en[0]=='.' && (!en[1] || en[1]=='.' && !en[2]))
+ continue;
+ if (rcssuffix(en))
+ continue;
+ while (chars_max < s + chars)
+ a = trealloc(char, a, chars_max<<=1);
+ if (entries == entries_max)
+ offset = trealloc(size_t, offset, entries_max<<=1);
+ offset[entries++] = chars;
+ VOID strcpy(a+chars, en);
+ chars += s;
+ }
+ if (errno || closedir(d) != 0)
+ efaterror(dirname);
+ if (chars)
+ a = trealloc(char, a, chars);
+ else
+ tfree(a);
+ *aargv = p = tnalloc(char*, entries+1);
+ for (i=0; i<entries; i++)
+ *p++ = a + offset[i];
+ *p = 0;
+ tfree(offset);
+ return entries;
+}
+#endif