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