111891Speter/* Clean up working files.  */
29Sjkh
311891Speter/* Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert
49Sjkh   Distributed under license by the Free Software Foundation, Inc.
59Sjkh
69SjkhThis file is part of RCS.
79Sjkh
89SjkhRCS is free software; you can redistribute it and/or modify
99Sjkhit under the terms of the GNU General Public License as published by
109Sjkhthe Free Software Foundation; either version 2, or (at your option)
119Sjkhany later version.
129Sjkh
139SjkhRCS is distributed in the hope that it will be useful,
149Sjkhbut WITHOUT ANY WARRANTY; without even the implied warranty of
159SjkhMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
169SjkhGNU General Public License for more details.
179Sjkh
189SjkhYou should have received a copy of the GNU General Public License
1911891Speteralong with RCS; see the file COPYING.
2011891SpeterIf not, write to the Free Software Foundation,
2111891Speter59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
229Sjkh
239SjkhReport problems and direct all questions to:
249Sjkh
259Sjkh	rcs-bugs@cs.purdue.edu
269Sjkh
279Sjkh*/
289Sjkh
299Sjkh#include "rcsbase.h"
309Sjkh
319Sjkh#if has_dirent
329Sjkh	static int get_directory P((char const*,char***));
339Sjkh#endif
349Sjkh
359Sjkhstatic int unlock P((struct hshentry *));
369Sjkhstatic void cleanup P((void));
379Sjkh
389Sjkhstatic RILE *workptr;
399Sjkhstatic int exitstatus;
409Sjkh
4150472SpetermainProg(rcscleanId, "rcsclean", "$FreeBSD$")
429Sjkh{
439Sjkh	static char const usage[] =
4411891Speter		"\nrcsclean: usage: rcsclean -ksubst -{nqru}[rev] -T -Vn -xsuff -zzone file ...";
459Sjkh
469Sjkh	static struct buf revision;
479Sjkh
489Sjkh	char *a, **newargv;
499Sjkh	char const *rev, *p;
5011891Speter	int dounlock, expmode, perform, unlocked, unlockflag, waslocked;
5111891Speter	int Ttimeflag;
529Sjkh	struct hshentries *deltas;
539Sjkh	struct hshentry *delta;
549Sjkh	struct stat workstat;
559Sjkh
569Sjkh	setrid();
579Sjkh
589Sjkh	expmode = -1;
5911891Speter	rev = 0;
609Sjkh	suffixes = X_DEFAULT;
619Sjkh	perform = true;
629Sjkh	unlockflag = false;
6311891Speter	Ttimeflag = false;
649Sjkh
659Sjkh	argc = getRCSINIT(argc, argv, &newargv);
669Sjkh	argv = newargv;
679Sjkh	for (;;) {
6811891Speter		if (--argc < 1) {
699Sjkh#			if has_dirent
709Sjkh				argc = get_directory(".", &newargv);
719Sjkh				argv = newargv;
729Sjkh				break;
739Sjkh#			else
7411891Speter				faterror("no pathnames specified");
759Sjkh#			endif
769Sjkh		}
779Sjkh		a = *++argv;
7811891Speter		if (!*a  ||  *a++ != '-')
799Sjkh			break;
809Sjkh		switch (*a++) {
819Sjkh			case 'k':
829Sjkh				if (0 <= expmode)
839Sjkh					redefined('k');
849Sjkh				if ((expmode = str2expmode(a))  <  0)
859Sjkh					goto unknown;
869Sjkh				break;
879Sjkh
889Sjkh			case 'n':
899Sjkh				perform = false;
909Sjkh				goto handle_revision;
919Sjkh
929Sjkh			case 'q':
939Sjkh				quietflag = true;
949Sjkh				/* fall into */
959Sjkh			case 'r':
969Sjkh			handle_revision:
979Sjkh				if (*a) {
989Sjkh					if (rev)
999Sjkh						warn("redefinition of revision number");
1009Sjkh					rev = a;
1019Sjkh				}
1029Sjkh				break;
1039Sjkh
10411891Speter			case 'T':
10511891Speter				if (*a)
10611891Speter					goto unknown;
10711891Speter				Ttimeflag = true;
10811891Speter				break;
10911891Speter
1109Sjkh			case 'u':
1119Sjkh				unlockflag = true;
1129Sjkh				goto handle_revision;
1139Sjkh
1149Sjkh			case 'V':
1159Sjkh				setRCSversion(*argv);
1169Sjkh				break;
1179Sjkh
1189Sjkh			case 'x':
1199Sjkh				suffixes = a;
1209Sjkh				break;
1219Sjkh
12211891Speter			case 'z':
12311891Speter				zone_set(a);
12411891Speter				break;
12511891Speter
1269Sjkh			default:
1279Sjkh			unknown:
12811891Speter				error("unknown option: %s%s", *argv, usage);
1299Sjkh		}
1309Sjkh	}
1319Sjkh
13211891Speter	dounlock = perform & unlockflag;
13311891Speter
13411891Speter	if (nerror)
13511891Speter	  cleanup();
13611891Speter	else
13711891Speter	  for (;  0 < argc;  cleanup(), ++argv, --argc) {
13811891Speter
1399Sjkh		ffree();
1409Sjkh
1419Sjkh		if (!(
14211891Speter			0 < pairnames(
1439Sjkh				argc, argv,
14411891Speter				dounlock ? rcswriteopen : rcsreadopen,
1459Sjkh				true, true
1469Sjkh			) &&
14711891Speter			(workptr = Iopen(workname, FOPEN_R_WORK, &workstat))
1489Sjkh		))
1499Sjkh			continue;
1509Sjkh
15111891Speter		if (same_file(RCSstat, workstat, 0)) {
15211891Speter			rcserror("RCS file is the same as working file %s.",
15311891Speter				workname
15411891Speter			);
15511891Speter			continue;
15611891Speter		}
15711891Speter
1589Sjkh		gettree();
1599Sjkh
1609Sjkh		p = 0;
1619Sjkh		if (rev) {
1629Sjkh			if (!fexpandsym(rev, &revision, workptr))
1639Sjkh				continue;
1649Sjkh			p = revision.string;
1659Sjkh		} else if (Head)
1669Sjkh			switch (unlockflag ? findlock(false,&delta) : 0) {
1679Sjkh				default:
1689Sjkh					continue;
1699Sjkh				case 0:
1709Sjkh					p = Dbranch ? Dbranch : "";
1719Sjkh					break;
1729Sjkh				case 1:
1739Sjkh					p = delta->num;
1749Sjkh					break;
1759Sjkh			}
1769Sjkh		delta = 0;
1779Sjkh		deltas = 0;  /* Keep lint happy.  */
1789Sjkh		if (p  &&  !(delta = genrevs(p,(char*)0,(char*)0,(char*)0,&deltas)))
1799Sjkh			continue;
1809Sjkh
1819Sjkh		waslocked = delta && delta->lockedby;
1829Sjkh		locker_expansion = unlock(delta);
1839Sjkh		unlocked = locker_expansion & unlockflag;
1849Sjkh		if (unlocked<waslocked  &&  workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH))
1859Sjkh			continue;
1869Sjkh
18711891Speter		if (unlocked && !checkaccesslist())
1889Sjkh			continue;
1899Sjkh
19011891Speter		if (dorewrite(dounlock, unlocked) != 0)
19111891Speter			continue;
19211891Speter
1939Sjkh		if (0 <= expmode)
1949Sjkh			Expand = expmode;
1959Sjkh		else if (
1969Sjkh			waslocked  &&
1979Sjkh			Expand == KEYVAL_EXPAND  &&
1989Sjkh			WORKMODE(RCSstat.st_mode,true) == workstat.st_mode
1999Sjkh		)
2009Sjkh			Expand = KEYVALLOCK_EXPAND;
2019Sjkh
2029Sjkh		getdesc(false);
2039Sjkh
2049Sjkh		if (
20511891Speter			!delta ? workstat.st_size!=0 :
2069Sjkh			0 < rcsfcmp(
20711891Speter				workptr, &workstat,
20811891Speter				buildrevision(deltas, delta, (FILE*)0, false),
20911891Speter				delta
2109Sjkh			)
2119Sjkh		)
2129Sjkh			continue;
2139Sjkh
2149Sjkh		if (quietflag < unlocked)
21511891Speter			aprintf(stdout, "rcs -u%s %s\n", delta->num, RCSname);
2169Sjkh
21711891Speter		if (perform & unlocked) {
21811891Speter			if_advise_access(deltas->first != delta, finptr, MADV_SEQUENTIAL);
21911891Speter			if (donerewrite(true,
22011891Speter				Ttimeflag ? RCSstat.st_mtime : (time_t)-1
22111891Speter			) != 0)
22211891Speter				continue;
22311891Speter		}
2249Sjkh
2259Sjkh		if (!quietflag)
22611891Speter			aprintf(stdout, "rm -f %s\n", workname);
2279Sjkh		Izclose(&workptr);
22811891Speter		if (perform  &&  un_link(workname) != 0)
22911891Speter			eerror(workname);
2309Sjkh
23111891Speter	  }
2329Sjkh
2339Sjkh	tempunlink();
2349Sjkh	if (!quietflag)
2359Sjkh		Ofclose(stdout);
2369Sjkh	exitmain(exitstatus);
2379Sjkh}
2389Sjkh
2399Sjkh	static void
2409Sjkhcleanup()
2419Sjkh{
2429Sjkh	if (nerror) exitstatus = EXIT_FAILURE;
2439Sjkh	Izclose(&finptr);
2449Sjkh	Izclose(&workptr);
2459Sjkh	Ozclose(&fcopy);
24611891Speter	ORCSclose();
2479Sjkh	dirtempunlink();
2489Sjkh}
2499Sjkh
25011891Speter#if RCS_lint
25111891Speter#	define exiterr rcscleanExit
2529Sjkh#endif
25311891Speter	void
2549Sjkhexiterr()
2559Sjkh{
25611891Speter	ORCSerror();
2579Sjkh	dirtempunlink();
2589Sjkh	tempunlink();
2599Sjkh	_exit(EXIT_FAILURE);
2609Sjkh}
2619Sjkh
2629Sjkh	static int
2639Sjkhunlock(delta)
2649Sjkh	struct hshentry *delta;
2659Sjkh{
26611891Speter	register struct rcslock **al, *l;
2679Sjkh
2689Sjkh	if (delta && delta->lockedby && strcmp(getcaller(),delta->lockedby)==0)
2699Sjkh		for (al = &Locks;  (l = *al);  al = &l->nextlock)
2709Sjkh			if (l->delta == delta) {
2719Sjkh				*al = l->nextlock;
2729Sjkh				delta->lockedby = 0;
2739Sjkh				return true;
2749Sjkh			}
2759Sjkh	return false;
2769Sjkh}
2779Sjkh
2789Sjkh#if has_dirent
2799Sjkh	static int
2809Sjkhget_directory(dirname, aargv)
2819Sjkh	char const *dirname;
2829Sjkh	char ***aargv;
2839Sjkh/*
2849Sjkh * Put a vector of all DIRNAME's directory entries names into *AARGV.
2859Sjkh * Ignore names of RCS files.
2869Sjkh * Yield the number of entries found.  Terminate the vector with 0.
2879Sjkh * Allocate the storage for the vector and entry names.
2889Sjkh * Do not sort the names.  Do not include '.' and '..'.
2899Sjkh */
2909Sjkh{
2919Sjkh	int i, entries = 0, entries_max = 64;
2929Sjkh	size_t chars = 0, chars_max = 1024;
2939Sjkh	size_t *offset = tnalloc(size_t, entries_max);
2949Sjkh	char *a = tnalloc(char, chars_max), **p;
2959Sjkh	DIR *d;
2969Sjkh	struct dirent *e;
2979Sjkh
2989Sjkh	if (!(d = opendir(dirname)))
2999Sjkh		efaterror(dirname);
3009Sjkh	while ((errno = 0,  e = readdir(d))) {
3019Sjkh		char const *en = e->d_name;
3029Sjkh		size_t s = strlen(en) + 1;
30311891Speter		if (en[0]=='.'   &&   (!en[1]  ||  (en[1]=='.' && !en[2])))
3049Sjkh			continue;
3059Sjkh		if (rcssuffix(en))
3069Sjkh			continue;
3079Sjkh		while (chars_max < s + chars)
3089Sjkh			a = trealloc(char, a, chars_max<<=1);
3099Sjkh		if (entries == entries_max)
3109Sjkh			offset = trealloc(size_t, offset, entries_max<<=1);
3119Sjkh		offset[entries++] = chars;
3129Sjkh		VOID strcpy(a+chars, en);
3139Sjkh		chars += s;
3149Sjkh	}
31511891Speter#	if void_closedir
31611891Speter#		define close_directory(d) (closedir(d), 0)
31711891Speter#	else
31811891Speter#		define close_directory(d) closedir(d)
31911891Speter#	endif
32011891Speter	if (errno  ||  close_directory(d) != 0)
3219Sjkh		efaterror(dirname);
3229Sjkh	if (chars)
3239Sjkh		a = trealloc(char, a, chars);
3249Sjkh	else
3259Sjkh		tfree(a);
3269Sjkh	*aargv = p = tnalloc(char*, entries+1);
3279Sjkh	for (i=0; i<entries; i++)
3289Sjkh		*p++ = a + offset[i];
3299Sjkh	*p = 0;
3309Sjkh	tfree(offset);
3319Sjkh	return entries;
3329Sjkh}
3339Sjkh#endif
334