rcsclean.c revision 9
19Sjkh/* rcsclean - clean up working files */
29Sjkh
39Sjkh/* Copyright 1991 by 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
199Sjkhalong with RCS; see the file COPYING.  If not, write to
209Sjkhthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
219Sjkh
229SjkhReport problems and direct all questions to:
239Sjkh
249Sjkh	rcs-bugs@cs.purdue.edu
259Sjkh
269Sjkh*/
279Sjkh
289Sjkh#include "rcsbase.h"
299Sjkh
309Sjkh#if has_dirent
319Sjkh	static int get_directory P((char const*,char***));
329Sjkh#endif
339Sjkh
349Sjkhstatic int unlock P((struct hshentry *));
359Sjkhstatic void cleanup P((void));
369Sjkh
379Sjkhstatic RILE *workptr;
389Sjkhstatic int exitstatus;
399Sjkh
409SjkhmainProg(rcscleanId, "rcsclean", "$Id: rcsclean.c,v 5.1 1991/11/03 01:11:44 eggert Exp $")
419Sjkh{
429Sjkh	static char const usage[] =
439Sjkh		"\nrcsclean: usage: rcsclean [-ksubst] [-{nqru}[rev]] [-Vn] [-xsuffixes] [file ...]";
449Sjkh
459Sjkh	static struct buf revision;
469Sjkh
479Sjkh	char *a, **newargv;
489Sjkh	char const *rev, *p;
499Sjkh	int changelock, expmode, perform, unlocked, unlockflag, waslocked;
509Sjkh	struct hshentries *deltas;
519Sjkh	struct hshentry *delta;
529Sjkh	struct stat workstat;
539Sjkh
549Sjkh	setrid();
559Sjkh
569Sjkh	expmode = -1;
579Sjkh	rev = nil;
589Sjkh	suffixes = X_DEFAULT;
599Sjkh	perform = true;
609Sjkh	unlockflag = false;
619Sjkh
629Sjkh	argc = getRCSINIT(argc, argv, &newargv);
639Sjkh	argv = newargv;
649Sjkh	for (;;) {
659Sjkh		if (--argc <= 0) {
669Sjkh#			if has_dirent
679Sjkh				argc = get_directory(".", &newargv);
689Sjkh				argv = newargv;
699Sjkh				break;
709Sjkh#			else
719Sjkh				faterror("no file names specified");
729Sjkh#			endif
739Sjkh		}
749Sjkh		a = *++argv;
759Sjkh		if (*a++ != '-')
769Sjkh			break;
779Sjkh		switch (*a++) {
789Sjkh			case 'k':
799Sjkh				if (0 <= expmode)
809Sjkh					redefined('k');
819Sjkh				if ((expmode = str2expmode(a))  <  0)
829Sjkh					goto unknown;
839Sjkh				break;
849Sjkh
859Sjkh			case 'n':
869Sjkh				perform = false;
879Sjkh				goto handle_revision;
889Sjkh
899Sjkh			case 'q':
909Sjkh				quietflag = true;
919Sjkh				/* fall into */
929Sjkh			case 'r':
939Sjkh			handle_revision:
949Sjkh				if (*a) {
959Sjkh					if (rev)
969Sjkh						warn("redefinition of revision number");
979Sjkh					rev = a;
989Sjkh				}
999Sjkh				break;
1009Sjkh
1019Sjkh			case 'u':
1029Sjkh				unlockflag = true;
1039Sjkh				goto handle_revision;
1049Sjkh
1059Sjkh			case 'V':
1069Sjkh				setRCSversion(*argv);
1079Sjkh				break;
1089Sjkh
1099Sjkh			case 'x':
1109Sjkh				suffixes = a;
1119Sjkh				break;
1129Sjkh
1139Sjkh			default:
1149Sjkh			unknown:
1159Sjkh				faterror("unknown option: %s%s", *argv, usage);
1169Sjkh		}
1179Sjkh	}
1189Sjkh
1199Sjkh	do {
1209Sjkh		ffree();
1219Sjkh
1229Sjkh		if (!(
1239Sjkh			0 < pairfilenames(
1249Sjkh				argc, argv,
1259Sjkh				unlockflag&perform ? rcswriteopen : rcsreadopen,
1269Sjkh				true, true
1279Sjkh			) &&
1289Sjkh			(workptr = Iopen(workfilename,FOPEN_R_WORK,&workstat))
1299Sjkh		))
1309Sjkh			continue;
1319Sjkh
1329Sjkh		gettree();
1339Sjkh
1349Sjkh		p = 0;
1359Sjkh		if (rev) {
1369Sjkh			if (!fexpandsym(rev, &revision, workptr))
1379Sjkh				continue;
1389Sjkh			p = revision.string;
1399Sjkh		} else if (Head)
1409Sjkh			switch (unlockflag ? findlock(false,&delta) : 0) {
1419Sjkh				default:
1429Sjkh					continue;
1439Sjkh				case 0:
1449Sjkh					p = Dbranch ? Dbranch : "";
1459Sjkh					break;
1469Sjkh				case 1:
1479Sjkh					p = delta->num;
1489Sjkh					break;
1499Sjkh			}
1509Sjkh		delta = 0;
1519Sjkh		deltas = 0;  /* Keep lint happy.  */
1529Sjkh		if (p  &&  !(delta = genrevs(p,(char*)0,(char*)0,(char*)0,&deltas)))
1539Sjkh			continue;
1549Sjkh
1559Sjkh		waslocked = delta && delta->lockedby;
1569Sjkh		locker_expansion = unlock(delta);
1579Sjkh		unlocked = locker_expansion & unlockflag;
1589Sjkh		changelock = unlocked & perform;
1599Sjkh		if (unlocked<waslocked  &&  workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH))
1609Sjkh			continue;
1619Sjkh
1629Sjkh		if (!dorewrite(unlockflag, changelock))
1639Sjkh			continue;
1649Sjkh
1659Sjkh		if (0 <= expmode)
1669Sjkh			Expand = expmode;
1679Sjkh		else if (
1689Sjkh			waslocked  &&
1699Sjkh			Expand == KEYVAL_EXPAND  &&
1709Sjkh			WORKMODE(RCSstat.st_mode,true) == workstat.st_mode
1719Sjkh		)
1729Sjkh			Expand = KEYVALLOCK_EXPAND;
1739Sjkh
1749Sjkh		getdesc(false);
1759Sjkh
1769Sjkh		if (
1779Sjkh		    !delta ? workstat.st_size!=0 :
1789Sjkh			0 < rcsfcmp(
1799Sjkh			    workptr, &workstat,
1809Sjkh			    buildrevision(deltas, delta, (FILE*)0, false),
1819Sjkh			    delta
1829Sjkh			)
1839Sjkh		)
1849Sjkh			continue;
1859Sjkh
1869Sjkh		if (quietflag < unlocked)
1879Sjkh			aprintf(stdout, "rcs -u%s %s\n", delta->num, RCSfilename);
1889Sjkh
1899Sjkh		if_advise_access(changelock  &&  deltas->first != delta,
1909Sjkh			finptr, MADV_SEQUENTIAL
1919Sjkh		);
1929Sjkh		if (!donerewrite(changelock))
1939Sjkh			continue;
1949Sjkh
1959Sjkh		if (!quietflag)
1969Sjkh			aprintf(stdout, "rm -f %s\n", workfilename);
1979Sjkh		Izclose(&workptr);
1989Sjkh		if (perform  &&  un_link(workfilename) != 0)
1999Sjkh			eerror(workfilename);
2009Sjkh
2019Sjkh	} while (cleanup(),  ++argv,  0 < --argc);
2029Sjkh
2039Sjkh	tempunlink();
2049Sjkh	if (!quietflag)
2059Sjkh		Ofclose(stdout);
2069Sjkh	exitmain(exitstatus);
2079Sjkh}
2089Sjkh
2099Sjkh	static void
2109Sjkhcleanup()
2119Sjkh{
2129Sjkh	if (nerror) exitstatus = EXIT_FAILURE;
2139Sjkh	Izclose(&finptr);
2149Sjkh	Izclose(&workptr);
2159Sjkh	Ozclose(&fcopy);
2169Sjkh	Ozclose(&frewrite);
2179Sjkh	dirtempunlink();
2189Sjkh}
2199Sjkh
2209Sjkh#if lint
2219Sjkh#       define exiterr rcscleanExit
2229Sjkh#endif
2239Sjkh	exiting void
2249Sjkhexiterr()
2259Sjkh{
2269Sjkh	dirtempunlink();
2279Sjkh	tempunlink();
2289Sjkh	_exit(EXIT_FAILURE);
2299Sjkh}
2309Sjkh
2319Sjkh	static int
2329Sjkhunlock(delta)
2339Sjkh	struct hshentry *delta;
2349Sjkh{
2359Sjkh	register struct lock **al, *l;
2369Sjkh
2379Sjkh	if (delta && delta->lockedby && strcmp(getcaller(),delta->lockedby)==0)
2389Sjkh		for (al = &Locks;  (l = *al);  al = &l->nextlock)
2399Sjkh			if (l->delta == delta) {
2409Sjkh				*al = l->nextlock;
2419Sjkh				delta->lockedby = 0;
2429Sjkh				return true;
2439Sjkh			}
2449Sjkh	return false;
2459Sjkh}
2469Sjkh
2479Sjkh#if has_dirent
2489Sjkh	static int
2499Sjkhget_directory(dirname, aargv)
2509Sjkh	char const *dirname;
2519Sjkh	char ***aargv;
2529Sjkh/*
2539Sjkh * Put a vector of all DIRNAME's directory entries names into *AARGV.
2549Sjkh * Ignore names of RCS files.
2559Sjkh * Yield the number of entries found.  Terminate the vector with 0.
2569Sjkh * Allocate the storage for the vector and entry names.
2579Sjkh * Do not sort the names.  Do not include '.' and '..'.
2589Sjkh */
2599Sjkh{
2609Sjkh	int i, entries = 0, entries_max = 64;
2619Sjkh	size_t chars = 0, chars_max = 1024;
2629Sjkh	size_t *offset = tnalloc(size_t, entries_max);
2639Sjkh	char *a = tnalloc(char, chars_max), **p;
2649Sjkh	DIR *d;
2659Sjkh	struct dirent *e;
2669Sjkh
2679Sjkh	if (!(d = opendir(dirname)))
2689Sjkh		efaterror(dirname);
2699Sjkh	while ((errno = 0,  e = readdir(d))) {
2709Sjkh		char const *en = e->d_name;
2719Sjkh		size_t s = strlen(en) + 1;
2729Sjkh		if (en[0]=='.'   &&   (!en[1]  ||  en[1]=='.' && !en[2]))
2739Sjkh			continue;
2749Sjkh		if (rcssuffix(en))
2759Sjkh			continue;
2769Sjkh		while (chars_max < s + chars)
2779Sjkh			a = trealloc(char, a, chars_max<<=1);
2789Sjkh		if (entries == entries_max)
2799Sjkh			offset = trealloc(size_t, offset, entries_max<<=1);
2809Sjkh		offset[entries++] = chars;
2819Sjkh		VOID strcpy(a+chars, en);
2829Sjkh		chars += s;
2839Sjkh	}
2849Sjkh	if (errno  ||  closedir(d) != 0)
2859Sjkh		efaterror(dirname);
2869Sjkh	if (chars)
2879Sjkh		a = trealloc(char, a, chars);
2889Sjkh	else
2899Sjkh		tfree(a);
2909Sjkh	*aargv = p = tnalloc(char*, entries+1);
2919Sjkh	for (i=0; i<entries; i++)
2929Sjkh		*p++ = a + offset[i];
2939Sjkh	*p = 0;
2949Sjkh	tfree(offset);
2959Sjkh	return entries;
2969Sjkh}
2979Sjkh#endif
298