home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume25 / rcs-5.6 / part05 < prev    next >
Text File  |  1991-12-19  |  69KB  |  2,307 lines

  1. Newsgroups: comp.sources.unix
  2. From: hammer@cs.purdue.edu (Adam Hammer)
  3. Subject: v25i081: rcs-5.6 - Revision Control System, V5.6, Part05/11
  4. Sender: sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: hammer@cs.purdue.edu (Adam Hammer)
  8. Posting-Number: Volume 25, Issue 81
  9. Archive-Name: rcs-5.6/part05
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 5 (of 11)."
  18. # Contents:  src/co.c src/rcsbase.h src/rcsrev.c
  19. # Wrapped by vixie@cognition.pa.dec.com on Fri Dec 20 16:23:40 1991
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'src/co.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'src/co.c'\"
  23. else
  24. echo shar: Extracting \"'src/co.c'\" \(21119 characters\)
  25. sed "s/^X//" >'src/co.c' <<'END_OF_FILE'
  26. X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
  27. X   Copyright 1990, 1991 by Paul Eggert
  28. X   Distributed under license by the Free Software Foundation, Inc.
  29. X
  30. This file is part of RCS.
  31. X
  32. RCS is free software; you can redistribute it and/or modify
  33. it under the terms of the GNU General Public License as published by
  34. the Free Software Foundation; either version 2, or (at your option)
  35. any later version.
  36. X
  37. RCS is distributed in the hope that it will be useful,
  38. but WITHOUT ANY WARRANTY; without even the implied warranty of
  39. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  40. GNU General Public License for more details.
  41. X
  42. You should have received a copy of the GNU General Public License
  43. along with RCS; see the file COPYING.  If not, write to
  44. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  45. X
  46. Report problems and direct all questions to:
  47. X
  48. X    rcs-bugs@cs.purdue.edu
  49. X
  50. X*/
  51. X
  52. X/*
  53. X *                     RCS checkout operation
  54. X */
  55. X/*****************************************************************************
  56. X *                       check out revisions from RCS files
  57. X *****************************************************************************
  58. X */
  59. X
  60. X
  61. X/* $Log: co.c,v $
  62. X * Revision 5.9  1991/10/07  17:32:46  eggert
  63. X * ci -u src/RCS/co.c,v src/co.c <<\.
  64. X * -k affects just working file, not RCS file.
  65. X *
  66. X * Revision 5.8  1991/08/19  03:13:55  eggert
  67. X * Warn before removing somebody else's file.
  68. X * Add -M.  Fix co -j bugs.  Tune.
  69. X *
  70. X * Revision 5.7  1991/04/21  11:58:15  eggert
  71. X * Ensure that working file is newer than RCS file after co -[lu].
  72. X * Add -x, RCSINIT, MS-DOS support.
  73. X *
  74. X * Revision 5.6  1990/12/04  05:18:38  eggert
  75. X * Don't checkaccesslist() unless necessary.
  76. X * Use -I for prompts and -q for diagnostics.
  77. X *
  78. X * Revision 5.5  1990/11/01  05:03:26  eggert
  79. X * Fix -j.  Add -I.
  80. X *
  81. X * Revision 5.4  1990/10/04  06:30:11  eggert
  82. X * Accumulate exit status across files.
  83. X *
  84. X * Revision 5.3  1990/09/11  02:41:09  eggert
  85. X * co -kv yields a readonly working file.
  86. X *
  87. X * Revision 5.2  1990/09/04  08:02:13  eggert
  88. X * Standardize yes-or-no procedure.
  89. X *
  90. X * Revision 5.0  1990/08/22  08:10:02  eggert
  91. X * Permit multiple locks by same user.  Add setuid support.
  92. X * Remove compile-time limits; use malloc instead.
  93. X * Permit dates past 1999/12/31.  Switch to GMT.
  94. X * Make lock and temp files faster and safer.
  95. X * Ansify and Posixate.  Add -k, -V.  Remove snooping.  Tune.
  96. X *
  97. X * Revision 4.7  89/05/01  15:11:41  narten
  98. X * changed copyright header to reflect current distribution rules
  99. X * 
  100. X * Revision 4.6  88/08/09  19:12:15  eggert
  101. X * Fix "co -d" core dump; rawdate wasn't always initialized.
  102. X * Use execv(), not system(); fix putchar('\0') and diagnose() botches; remove lint
  103. X * 
  104. X * Revision 4.5  87/12/18  11:35:40  narten
  105. X * lint cleanups (from Guy Harris)
  106. X * 
  107. X * Revision 4.4  87/10/18  10:20:53  narten
  108. X * Updating version numbers changes relative to 1.1, are actually
  109. X * relative to 4.2
  110. X * 
  111. X * Revision 1.3  87/09/24  13:58:30  narten
  112. X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  113. X * warnings)
  114. X * 
  115. X * Revision 1.2  87/03/27  14:21:38  jenkins
  116. X * Port to suns
  117. X * 
  118. X * Revision 4.2  83/12/05  13:39:48  wft
  119. X * made rewriteflag external.
  120. X * 
  121. X * Revision 4.1  83/05/10  16:52:55  wft
  122. X * Added option -u and -f.
  123. X * Added handling of default branch.
  124. X * Replaced getpwuid() with getcaller().
  125. X * Removed calls to stat(); now done by pairfilenames().
  126. X * Changed and renamed rmoldfile() to rmworkfile().
  127. X * Replaced catchints() calls with restoreints(), unlink()--link() with rename();
  128. X * 
  129. X * Revision 3.7  83/02/15  15:27:07  wft
  130. X * Added call to fastcopy() to copy remainder of RCS file.
  131. X *
  132. X * Revision 3.6  83/01/15  14:37:50  wft
  133. X * Added ignoring of interrupts while RCS file is renamed; this avoids
  134. X * deletion of RCS files during the unlink/link window.
  135. X *
  136. X * Revision 3.5  82/12/08  21:40:11  wft
  137. X * changed processing of -d to use DATEFORM; removed actual from
  138. X * call to preparejoin; re-fixed printing of done at the end.
  139. X *
  140. X * Revision 3.4  82/12/04  18:40:00  wft
  141. X * Replaced getdelta() with gettree(), SNOOPDIR with SNOOPFILE.
  142. X * Fixed printing of "done".
  143. X *
  144. X * Revision 3.3  82/11/28  22:23:11  wft
  145. X * Replaced getlogin() with getpwuid(), flcose() with ffclose(),
  146. X * %02d with %.2d, mode generation for working file with WORKMODE.
  147. X * Fixed nil printing. Fixed -j combined with -l and -p, and exit
  148. X * for non-existing revisions in preparejoin().
  149. X *
  150. X * Revision 3.2  82/10/18  20:47:21  wft
  151. X * Mode of working file is now maintained even for co -l, but write permission
  152. X * is removed.
  153. X * The working file inherits its mode from the RCS file, plus write permission
  154. X * for the owner. The write permission is not given if locking is strict and
  155. X * co does not lock.
  156. X * An existing working file without write permission is deleted automatically.
  157. X * Otherwise, co asks (empty answer: abort co).
  158. X * Call to getfullRCSname() added, check for write error added, call
  159. X * for getlogin() fixed.
  160. X *
  161. X * Revision 3.1  82/10/13  16:01:30  wft
  162. X * fixed type of variables receiving from getc() (char -> int).
  163. X * removed unused variables.
  164. X */
  165. X
  166. X
  167. X
  168. X
  169. X#include "rcsbase.h"
  170. X
  171. static char const *getancestor P((char const*,char const*));
  172. static int buildjoin P((char const*));
  173. static int preparejoin P((void));
  174. static int rmlock P((struct hshentry const*));
  175. static int rmworkfile P((void));
  176. static void cleanup P((void));
  177. X
  178. static char const quietarg[] = "-q";
  179. X
  180. static char const *expandarg, *join, *suffixarg, *versionarg;
  181. static char const *joinlist[joinlength]; /* revisions to be joined */
  182. static FILE *neworkptr;
  183. static int exitstatus;
  184. static int forceflag;
  185. static int lastjoin;            /* index of last element in joinlist  */
  186. static int lockflag; /* -1 -> unlock, 0 -> do nothing, 1 -> lock */
  187. static int mtimeflag;
  188. static struct hshentries *gendeltas;    /* deltas to be generated    */
  189. static struct hshentry *targetdelta;    /* final delta to be generated    */
  190. static struct stat workstat;
  191. X
  192. mainProg(coId, "co", "$Id: co.c,v 5.9 1991/10/07 17:32:46 eggert Exp $")
  193. X{
  194. X    static char const cmdusage[] =
  195. X        "\nco usage: co -{flpqru}[rev] -ddate -jjoinlist -sstate -w[login] -Vn file ...";
  196. X
  197. X    char *a, **newargv;
  198. X    char const *author, *date, *rev, *state;
  199. X    char const *joinfilename, *newdate, *neworkfilename;
  200. X    int changelock;  /* 1 if a lock has been changed, -1 if error */
  201. X    int expmode, r, tostdout, workstatstat;
  202. X    struct buf numericrev;    /* expanded revision number    */
  203. X    char finaldate[datesize];
  204. X
  205. X    setrid();
  206. X    author = date = rev = state = nil;
  207. X    bufautobegin(&numericrev);
  208. X    expmode = -1;
  209. X    suffixes = X_DEFAULT;
  210. X    tostdout = false;
  211. X
  212. X    argc = getRCSINIT(argc, argv, &newargv);
  213. X    argv = newargv;
  214. X    while (a = *++argv,  0<--argc && *a++=='-') {
  215. X        switch (*a++) {
  216. X
  217. X                case 'r':
  218. X        revno:
  219. X            if (*a) {
  220. X                if (rev) warn("redefinition of revision number");
  221. X                rev = a;
  222. X                        }
  223. X                        break;
  224. X
  225. X        case 'f':
  226. X            forceflag=true;
  227. X            goto revno;
  228. X
  229. X                case 'l':
  230. X            if (lockflag < 0) {
  231. X                                warn("-l overrides -u.");
  232. X                        }
  233. X            lockflag = 1;
  234. X                        goto revno;
  235. X
  236. X                case 'u':
  237. X            if (0 < lockflag) {
  238. X                                warn("-l overrides -u.");
  239. X                        }
  240. X            lockflag = -1;
  241. X                        goto revno;
  242. X
  243. X                case 'p':
  244. X            tostdout = true;
  245. X                        goto revno;
  246. X
  247. X        case 'I':
  248. X            interactiveflag = true;
  249. X            goto revno;
  250. X
  251. X                case 'q':
  252. X                        quietflag=true;
  253. X                        goto revno;
  254. X
  255. X                case 'd':
  256. X            if (date)
  257. X                redefined('d');
  258. X            str2date(a, finaldate);
  259. X                        date=finaldate;
  260. X                        break;
  261. X
  262. X                case 'j':
  263. X            if (*a) {
  264. X                if (join) redefined('j');
  265. X                join = a;
  266. X                        }
  267. X                        break;
  268. X
  269. X        case 'M':
  270. X            mtimeflag = true;
  271. X            goto revno;
  272. X
  273. X                case 's':
  274. X            if (*a) {
  275. X                if (state) redefined('s');
  276. X                state = a;
  277. X                        }
  278. X                        break;
  279. X
  280. X                case 'w':
  281. X            if (author) redefined('w');
  282. X            if (*a)
  283. X                author = a;
  284. X            else
  285. X                author = getcaller();
  286. X                        break;
  287. X
  288. X        case 'x':
  289. X            suffixarg = *argv;
  290. X            suffixes = a;
  291. X            break;
  292. X
  293. X        case 'V':
  294. X            versionarg = *argv;
  295. X            setRCSversion(versionarg);
  296. X            break;
  297. X
  298. X        case 'k':    /*  set keyword expand mode  */
  299. X            expandarg = *argv;
  300. X            if (0 <= expmode) redefined('k');
  301. X            if (0 <= (expmode = str2expmode(a)))
  302. X                break;
  303. X            /* fall into */
  304. X                default:
  305. X            faterror("unknown option: %s%s", *argv, cmdusage);
  306. X
  307. X                };
  308. X        } /* end of option processing */
  309. X
  310. X    if (argc<1) faterror("no input file%s", cmdusage);
  311. X    if (tostdout)
  312. X#        if text_equals_binary_stdio || text_work_stdio
  313. X        workstdout = stdout;
  314. X#        else
  315. X        if (!(workstdout = fdopen(STDOUT_FILENO, FOPEN_W_WORK)))
  316. X            efaterror("stdout");
  317. X#        endif
  318. X
  319. X        /* now handle all filenames */
  320. X        do {
  321. X    ffree();
  322. X
  323. X    if (pairfilenames(argc, argv, lockflag?rcswriteopen:rcsreadopen, true, false)  <=  0)
  324. X        continue;
  325. X
  326. X        /* now RCSfilename contains the name of the RCS file, and finptr
  327. X     * points at it.  workfilename contains the name of the working file.
  328. X     * Also, RCSstat has been set.
  329. X         */
  330. X    diagnose("%s  -->  %s\n", RCSfilename,tostdout?"stdout":workfilename);
  331. X
  332. X    workstatstat = -1;
  333. X    if (tostdout) {
  334. X        neworkfilename = 0;
  335. X        neworkptr = workstdout;
  336. X    } else {
  337. X        workstatstat = stat(workfilename, &workstat);
  338. X        neworkfilename = makedirtemp(workfilename, 1);
  339. X        if (!(neworkptr = fopen(neworkfilename, FOPEN_W_WORK))) {
  340. X            if (errno == EACCES)
  341. X                error("%s: parent directory isn't writable",
  342. X                    workfilename
  343. X                );
  344. X            else
  345. X                eerror(neworkfilename);
  346. X            continue;
  347. X        }
  348. X    }
  349. X
  350. X        gettree();  /* reads in the delta tree */
  351. X
  352. X        if (Head==nil) {
  353. X                /* no revisions; create empty file */
  354. X        diagnose("no revisions present; generating empty revision 0.0\n");
  355. X        Ozclose(&fcopy);
  356. X        if (workstatstat == 0)
  357. X            if (!rmworkfile()) continue;
  358. X        changelock = 0;
  359. X        newdate = 0;
  360. X                /* Can't reserve a delta, so don't call addlock */
  361. X        } else {
  362. X                if (rev!=nil) {
  363. X                        /* expand symbolic revision number */
  364. X            if (!expandsym(rev, &numericrev))
  365. X                                continue;
  366. X        } else
  367. X            switch (lockflag<0 ? findlock(false,&targetdelta) : 0) {
  368. X                default:
  369. X                continue;
  370. X                case 0:
  371. X                bufscpy(&numericrev, Dbranch?Dbranch:"");
  372. X                break;
  373. X                case 1:
  374. X                bufscpy(&numericrev, targetdelta->num);
  375. X                break;
  376. X            }
  377. X                /* get numbers of deltas to be generated */
  378. X        if (!(targetdelta=genrevs(numericrev.string,date,author,state,&gendeltas)))
  379. X                        continue;
  380. X                /* check reservations */
  381. X        changelock =
  382. X            lockflag < 0 ?
  383. X                rmlock(targetdelta)
  384. X            : lockflag == 0 ?
  385. X                0
  386. X            :
  387. X                addlock(targetdelta);
  388. X
  389. X        if (
  390. X            changelock < 0 ||
  391. X            changelock && !checkaccesslist() ||
  392. X            !dorewrite(lockflag, changelock)
  393. X        )
  394. X            continue;
  395. X
  396. X        if (0 <= expmode)
  397. X            Expand = expmode;
  398. X        if (0 < lockflag  &&  Expand == VAL_EXPAND) {
  399. X            error("cannot combine -kv and -l");
  400. X            continue;
  401. X        }
  402. X
  403. X                if (join && !preparejoin()) continue;
  404. X
  405. X        diagnose("revision %s%s\n",targetdelta->num,
  406. X             0<lockflag ? " (locked)" :
  407. X             lockflag<0 ? " (unlocked)" : "");
  408. X
  409. X        /* Prepare to remove old working file if necessary.  */
  410. X        if (workstatstat == 0)
  411. X                        if (!rmworkfile()) continue;
  412. X
  413. X                /* skip description */
  414. X                getdesc(false); /* don't echo*/
  415. X
  416. X        locker_expansion = 0 < lockflag;
  417. X        joinfilename = buildrevision(
  418. X            gendeltas, targetdelta,
  419. X            join&&tostdout ? (FILE*)0 : neworkptr,
  420. X            Expand!=OLD_EXPAND
  421. X        );
  422. X#        if !large_memory
  423. X            if (fcopy == neworkptr)
  424. X                fcopy = 0;  /* Don't close it twice.  */
  425. X#        endif
  426. X        if_advise_access(changelock && gendeltas->first!=targetdelta,
  427. X            finptr, MADV_SEQUENTIAL
  428. X        );
  429. X
  430. X        if (!donerewrite(changelock))
  431. X            continue;
  432. X
  433. X        newdate = targetdelta->date;
  434. X        if (join) {
  435. X            newdate = 0;
  436. X            if (!joinfilename) {
  437. X                aflush(neworkptr);
  438. X                joinfilename = neworkfilename;
  439. X            }
  440. X            if (!buildjoin(joinfilename))
  441. X                continue;
  442. X        }
  443. X        }
  444. X    if (!tostdout) {
  445. X        r = 0;
  446. X        if (mtimeflag && newdate) {
  447. X        if (!join)
  448. X            aflush(neworkptr);
  449. X        r = setfiledate(neworkfilename, newdate);
  450. X        }
  451. X        if (r == 0) {
  452. X        ignoreints();
  453. X        r = chnamemod(&neworkptr, neworkfilename, workfilename,
  454. X          WORKMODE(RCSstat.st_mode,
  455. X            !(Expand==VAL_EXPAND || lockflag<=0&&StrictLocks)
  456. X          )
  457. X        );
  458. X        keepdirtemp(neworkfilename);
  459. X        restoreints();
  460. X        }
  461. X        if (r != 0) {
  462. X        eerror(workfilename);
  463. X        error("see %s", neworkfilename);
  464. X        continue;
  465. X        }
  466. X        diagnose("done\n");
  467. X    }
  468. X        } while (cleanup(),
  469. X                 ++argv, --argc >=1);
  470. X
  471. X    tempunlink();
  472. X    Ofclose(workstdout);
  473. X    exitmain(exitstatus);
  474. X
  475. X}       /* end of main (co) */
  476. X
  477. X    static void
  478. cleanup()
  479. X{
  480. X    if (nerror) exitstatus = EXIT_FAILURE;
  481. X    Izclose(&finptr);
  482. X    Ozclose(&frewrite);
  483. X#    if !large_memory
  484. X        if (fcopy!=workstdout) Ozclose(&fcopy);
  485. X#    endif
  486. X    if (neworkptr!=workstdout) Ozclose(&neworkptr);
  487. X    dirtempunlink();
  488. X}
  489. X
  490. X#if lint
  491. X#    define exiterr coExit
  492. X#endif
  493. X    exiting void
  494. exiterr()
  495. X{
  496. X    dirtempunlink();
  497. X    tempunlink();
  498. X    _exit(EXIT_FAILURE);
  499. X}
  500. X
  501. X
  502. X/*****************************************************************
  503. X * The following routines are auxiliary routines
  504. X *****************************************************************/
  505. X
  506. X    static int
  507. rmworkfile()
  508. X/* Function: prepares to remove workfilename, if it exists, and if
  509. X * it is read-only.
  510. X * Otherwise (file writable):
  511. X *   if !quietmode asks the user whether to really delete it (default: fail);
  512. X *   otherwise failure.
  513. X * Returns true if permission is gotten.
  514. X */
  515. X{
  516. X    if (workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH) && !forceflag) {
  517. X        /* File is writable */
  518. X        if (!yesorno(false, "writable %s exists%s; remove it? [ny](n): ",
  519. X            workfilename,
  520. X            myself(workstat.st_uid) ? "" : ", and you do not own it"
  521. X        )) {
  522. X        error(!quietflag && ttystdin()
  523. X            ? "checkout aborted"
  524. X            : "writable %s exists; checkout aborted", workfilename);
  525. X        return false;
  526. X            }
  527. X        }
  528. X    /* Actual unlink is done later by caller. */
  529. X    return true;
  530. X}
  531. X
  532. X
  533. X    static int
  534. rmlock(delta)
  535. X    struct hshentry const *delta;
  536. X/* Function: removes the lock held by caller on delta.
  537. X * Returns -1 if someone else holds the lock,
  538. X * 0 if there is no lock on delta,
  539. X * and 1 if a lock was found and removed.
  540. X */
  541. X{       register struct lock * next, * trail;
  542. X    char const *num;
  543. X        struct lock dummy;
  544. X        int whomatch, nummatch;
  545. X
  546. X        num=delta->num;
  547. X        dummy.nextlock=next=Locks;
  548. X        trail = &dummy;
  549. X        while (next!=nil) {
  550. X        whomatch = strcmp(getcaller(), next->login);
  551. X                nummatch=strcmp(num,next->delta->num);
  552. X                if ((whomatch==0) && (nummatch==0)) break;
  553. X            /*found a lock on delta by caller*/
  554. X                if ((whomatch!=0)&&(nummatch==0)) {
  555. X                    error("revision %s locked by %s; use co -r or rcs -u",num,next->login);
  556. X                    return -1;
  557. X                }
  558. X                trail=next;
  559. X                next=next->nextlock;
  560. X        }
  561. X        if (next!=nil) {
  562. X                /*found one; delete it */
  563. X                trail->nextlock=next->nextlock;
  564. X                Locks=dummy.nextlock;
  565. X                next->delta->lockedby=nil; /* reset locked-by */
  566. X                return 1; /*success*/
  567. X        } else  return 0; /*no lock on delta*/
  568. X}
  569. X
  570. X
  571. X
  572. X
  573. X/*****************************************************************
  574. X * The rest of the routines are for handling joins
  575. X *****************************************************************/
  576. X
  577. X
  578. X    static char const *
  579. addjoin(joinrev)
  580. X    char *joinrev;
  581. X/* Add joinrev's number to joinlist, yielding address of char past joinrev,
  582. X * or nil if no such revision exists.
  583. X */
  584. X{
  585. X    register char *j;
  586. X    register struct hshentry const *d;
  587. X    char terminator;
  588. X    struct buf numrev;
  589. X    struct hshentries *joindeltas;
  590. X
  591. X    j = joinrev;
  592. X    for (;;) {
  593. X        switch (*j++) {
  594. X        default:
  595. X            continue;
  596. X        case 0:
  597. X        case ' ': case '\t': case '\n':
  598. X        case ':': case ',': case ';':
  599. X            break;
  600. X        }
  601. X        break;
  602. X    }
  603. X    terminator = *--j;
  604. X    *j = 0;
  605. X    bufautobegin(&numrev);
  606. X    d = 0;
  607. X    if (expandsym(joinrev, &numrev))
  608. X        d = genrevs(numrev.string,(char*)nil,(char*)nil,(char*)nil,&joindeltas);
  609. X    bufautoend(&numrev);
  610. X    *j = terminator;
  611. X    if (d) {
  612. X        joinlist[++lastjoin] = d->num;
  613. X        return j;
  614. X    }
  615. X    return nil;
  616. X}
  617. X
  618. X    static int
  619. preparejoin()
  620. X/* Function: Parses a join list pointed to by join and places pointers to the
  621. X * revision numbers into joinlist.
  622. X */
  623. X{
  624. X    register char const *j;
  625. X
  626. X        j=join;
  627. X        lastjoin= -1;
  628. X        for (;;) {
  629. X                while ((*j==' ')||(*j=='\t')||(*j==',')) j++;
  630. X                if (*j=='\0') break;
  631. X                if (lastjoin>=joinlength-2) {
  632. X                        error("too many joins");
  633. X                        return(false);
  634. X                }
  635. X        if (!(j = addjoin(j))) return false;
  636. X                while ((*j==' ') || (*j=='\t')) j++;
  637. X                if (*j == ':') {
  638. X                        j++;
  639. X                        while((*j==' ') || (*j=='\t')) j++;
  640. X                        if (*j!='\0') {
  641. X                if (!(j = addjoin(j))) return false;
  642. X                        } else {
  643. X                                error("join pair incomplete");
  644. X                                return false;
  645. X                        }
  646. X                } else {
  647. X                        if (lastjoin==0) { /* first pair */
  648. X                                /* common ancestor missing */
  649. X                                joinlist[1]=joinlist[0];
  650. X                                lastjoin=1;
  651. X                                /*derive common ancestor*/
  652. X                if (!(joinlist[0] = getancestor(targetdelta->num,joinlist[1])))
  653. X                                       return false;
  654. X                        } else {
  655. X                                error("join pair incomplete");
  656. X                                return false;
  657. X                        }
  658. X                }
  659. X        }
  660. X        if (lastjoin<1) {
  661. X                error("empty join");
  662. X                return false;
  663. X        } else  return true;
  664. X}
  665. X
  666. X
  667. X
  668. X    static char const *
  669. getancestor(r1, r2)
  670. X    char const *r1, *r2;
  671. X/* Yield the common ancestor of r1 and r2 if successful, nil otherwise.
  672. X * Work reliably only if r1 and r2 are not branch numbers.
  673. X */
  674. X{
  675. X    static struct buf t1, t2;
  676. X
  677. X    unsigned l1, l2, l3;
  678. X    char const *r;
  679. X
  680. X    l1 = countnumflds(r1);
  681. X    l2 = countnumflds(r2);
  682. X    if ((2<l1 || 2<l2)  &&  cmpnum(r1,r2)!=0) {
  683. X        /* not on main trunk or identical */
  684. X        l3 = 0;
  685. X        while (cmpnumfld(r1, r2, l3+1)==0 && cmpnumfld(r1, r2, l3+2)==0)
  686. X        l3 += 2;
  687. X        /* This will terminate since r1 and r2 are not the same; see above. */
  688. X        if (l3==0) {
  689. X        /* no common prefix; common ancestor on main trunk */
  690. X        VOID partialno(&t1, r1, l1>2 ? (unsigned)2 : l1);
  691. X        VOID partialno(&t2, r2, l2>2 ? (unsigned)2 : l2);
  692. X        r = cmpnum(t1.string,t2.string)<0 ? t1.string : t2.string;
  693. X        if (cmpnum(r,r1)!=0 && cmpnum(r,r2)!=0)
  694. X            return r;
  695. X        } else if (cmpnumfld(r1, r2, l3+1)!=0)
  696. X            return partialno(&t1,r1,l3);
  697. X    }
  698. X    error("common ancestor of %s and %s undefined", r1, r2);
  699. X    return nil;
  700. X}
  701. X
  702. X
  703. X
  704. X    static int
  705. buildjoin(initialfile)
  706. X    char const *initialfile;
  707. X/* Function: merge pairs of elements in joinlist into initialfile
  708. X * If workstdout is set, copy result to stdout.
  709. X * All unlinking of initialfile, rev2, and rev3 should be done by tempunlink().
  710. X */
  711. X{
  712. X    struct buf commarg;
  713. X    struct buf subs;
  714. X    char const *rev2, *rev3;
  715. X        int i;
  716. X    char const *cov[10], *mergev[12];
  717. X    char const **p;
  718. X
  719. X    bufautobegin(&commarg);
  720. X    bufautobegin(&subs);
  721. X    rev2 = maketemp(0);
  722. X    rev3 = maketemp(3); /* buildrevision() may use 1 and 2 */
  723. X
  724. X    cov[0] = nil;
  725. X    /* cov[1] setup below */
  726. X    cov[2] = CO;
  727. X    /* cov[3] setup below */
  728. X    p = &cov[4];
  729. X    if (expandarg) *p++ = expandarg;
  730. X    if (suffixarg) *p++ = suffixarg;
  731. X    if (versionarg) *p++ = versionarg;
  732. X    *p++ = quietarg;
  733. X    *p++ = RCSfilename;
  734. X    *p = nil;
  735. X
  736. X    mergev[0] = nil;
  737. X    mergev[1] = nil;
  738. X    mergev[2] = MERGE;
  739. X    mergev[3] = mergev[5] = "-L";
  740. X    /* rest of mergev setup below */
  741. X
  742. X        i=0;
  743. X        while (i<lastjoin) {
  744. X                /*prepare marker for merge*/
  745. X                if (i==0)
  746. X            bufscpy(&subs, targetdelta->num);
  747. X        else {
  748. X            bufscat(&subs, ",");
  749. X            bufscat(&subs, joinlist[i-2]);
  750. X            bufscat(&subs, ":");
  751. X            bufscat(&subs, joinlist[i-1]);
  752. X        }
  753. X        diagnose("revision %s\n",joinlist[i]);
  754. X        bufscpy(&commarg, "-p");
  755. X        bufscat(&commarg, joinlist[i]);
  756. X        cov[1] = rev2;
  757. X        cov[3] = commarg.string;
  758. X        if (runv(cov))
  759. X            goto badmerge;
  760. X        diagnose("revision %s\n",joinlist[i+1]);
  761. X        bufscpy(&commarg, "-p");
  762. X        bufscat(&commarg, joinlist[i+1]);
  763. X        cov[1] = rev3;
  764. X        cov[3] = commarg.string;
  765. X        if (runv(cov))
  766. X            goto badmerge;
  767. X        diagnose("merging...\n");
  768. X        mergev[4] = subs.string;
  769. X        mergev[6] = joinlist[i+1];
  770. X        p = &mergev[7];
  771. X        if (quietflag) *p++ = quietarg;
  772. X        if (lastjoin<=i+2 && workstdout) *p++ = "-p";
  773. X        *p++ = initialfile;
  774. X        *p++ = rev2;
  775. X        *p++ = rev3;
  776. X        *p = nil;
  777. X        switch (runv(mergev)) {
  778. X            case DIFF_FAILURE: case DIFF_SUCCESS:
  779. X            break;
  780. X            default:
  781. X            goto badmerge;
  782. X        }
  783. X                i=i+2;
  784. X        }
  785. X    bufautoend(&commarg);
  786. X    bufautoend(&subs);
  787. X        return true;
  788. X
  789. X    badmerge:
  790. X    nerror++;
  791. X    bufautoend(&commarg);
  792. X    bufautoend(&subs);
  793. X    return false;
  794. X}
  795. END_OF_FILE
  796. if test 21119 -ne `wc -c <'src/co.c'`; then
  797.     echo shar: \"'src/co.c'\" unpacked with wrong size!
  798. fi
  799. # end of 'src/co.c'
  800. fi
  801. if test -f 'src/rcsbase.h' -a "${1}" != "-c" ; then 
  802.   echo shar: Will not clobber existing file \"'src/rcsbase.h'\"
  803. else
  804. echo shar: Extracting \"'src/rcsbase.h'\" \(22152 characters\)
  805. sed "s/^X//" >'src/rcsbase.h' <<'END_OF_FILE'
  806. X
  807. X/*
  808. X *                     RCS common definitions and data structures
  809. X */
  810. X#define RCSBASE "$Id: rcsbase.h,v 5.11 1991/10/07 17:32:46 eggert Exp $"
  811. X
  812. X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
  813. X   Copyright 1990, 1991 by Paul Eggert
  814. X   Distributed under license by the Free Software Foundation, Inc.
  815. X
  816. This file is part of RCS.
  817. X
  818. RCS is free software; you can redistribute it and/or modify
  819. it under the terms of the GNU General Public License as published by
  820. the Free Software Foundation; either version 2, or (at your option)
  821. any later version.
  822. X
  823. RCS is distributed in the hope that it will be useful,
  824. but WITHOUT ANY WARRANTY; without even the implied warranty of
  825. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  826. GNU General Public License for more details.
  827. X
  828. You should have received a copy of the GNU General Public License
  829. along with RCS; see the file COPYING.  If not, write to
  830. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  831. X
  832. Report problems and direct all questions to:
  833. X
  834. X    rcs-bugs@cs.purdue.edu
  835. X
  836. X*/
  837. X
  838. X
  839. X
  840. X/*****************************************************************************
  841. X * INSTRUCTIONS:
  842. X * =============
  843. X * See the Makefile for how to define C preprocessor symbols.
  844. X * If you need to change the comment leaders, update the table comtable[]
  845. X * in rcsfnms.c. (This can wait until you know what a comment leader is.)
  846. X *****************************************************************************
  847. X */
  848. X
  849. X
  850. X/* $Log: rcsbase.h,v $
  851. X * Revision 5.11  1991/10/07  17:32:46  eggert
  852. X * Support piece tables even if !has_mmap.
  853. X *
  854. X * Revision 5.10  1991/09/24  00:28:39  eggert
  855. X * Remove unexported functions.
  856. X *
  857. X * Revision 5.9  1991/08/19  03:13:55  eggert
  858. X * Add piece tables and other tuneups, and NFS workarounds.
  859. X *
  860. X * Revision 5.8  1991/04/21  11:58:20  eggert
  861. X * Add -x, RCSINIT, MS-DOS support.
  862. X *
  863. X * Revision 5.7  1991/02/28  19:18:50  eggert
  864. X * Try setuid() if seteuid() doesn't work.
  865. X *
  866. X * Revision 5.6  1991/02/26  17:48:37  eggert
  867. X * Support new link behavior.  Move ANSI C / Posix declarations into conf.sh.
  868. X *
  869. X * Revision 5.5  1990/12/04  05:18:43  eggert
  870. X * Use -I for prompts and -q for diagnostics.
  871. X *
  872. X * Revision 5.4  1990/11/01  05:03:35  eggert
  873. X * Don't assume that builtins are functions; they may be macros.
  874. X * Permit arbitrary data in logs.
  875. X *
  876. X * Revision 5.3  1990/09/26  23:36:58  eggert
  877. X * Port wait() to non-Posix ANSI C hosts.
  878. X *
  879. X * Revision 5.2  1990/09/04  08:02:20  eggert
  880. X * Don't redefine NAME_MAX, PATH_MAX.
  881. X * Improve incomplete line handling.  Standardize yes-or-no procedure.
  882. X *
  883. X * Revision 5.1  1990/08/29  07:13:53  eggert
  884. X * Add -kkvl.  Fix type typos exposed by porting.  Clean old log messages too.
  885. X *
  886. X * Revision 5.0  1990/08/22  08:12:44  eggert
  887. X * Adjust ANSI C / Posix support.  Add -k, -V, setuid.  Don't call access().
  888. X * Remove compile-time limits; use malloc instead.
  889. X * Ansify and Posixate.  Add support for ISO 8859.
  890. X * Remove snoop and v2 support.
  891. X *
  892. X * Revision 4.9  89/05/01  15:17:14  narten
  893. X * botched previous USG fix 
  894. X * 
  895. X * Revision 4.8  89/05/01  14:53:05  narten
  896. X * changed #include <strings.h> -> string.h for USG systems.
  897. X * 
  898. X * Revision 4.7  88/11/08  15:58:45  narten
  899. X * removed defs for functions loaded from libraries
  900. X * 
  901. X * Revision 4.6  88/08/09  19:12:36  eggert
  902. X * Shrink stdio code size; remove lint; permit -Dhshsize=nn.
  903. X * 
  904. X * Revision 4.5  87/12/18  17:06:41  narten
  905. X * made removed BSD ifdef, now uses V4_2BSD
  906. X * 
  907. X * Revision 4.4  87/10/18  10:29:49  narten
  908. X * Updating version numbers
  909. X * Changes relative to 1.1 are actually relative to 4.2
  910. X * 
  911. X * Revision 1.3  87/09/24  14:02:25  narten
  912. X * changes for lint
  913. X * 
  914. X * Revision 1.2  87/03/27  14:22:02  jenkins
  915. X * Port to suns
  916. X * 
  917. X * Revision 4.2  83/12/20  16:04:20  wft
  918. X * merged 3.6.1.1 and 4.1 (SMALLOG, logsize).
  919. X * moved setting of STRICT_LOCKING to Makefile.
  920. X * changed DOLLAR to UNKN (conflict with KDELIM).
  921. X * 
  922. X * Revision 4.1  83/05/04  09:12:41  wft
  923. X * Added markers Id and RCSfile.
  924. X * Added Dbranch for default branches.
  925. X * 
  926. X * Revision 3.6.1.1  83/12/02  21:56:22  wft
  927. X * Increased logsize, added macro SMALLOG.
  928. X * 
  929. X * Revision 3.6  83/01/15  16:43:28  wft
  930. X * 4.2 prerelease
  931. X * 
  932. X * Revision 3.6  83/01/15  16:43:28  wft
  933. X * Replaced dbm.h with BYTESIZ, fixed definition of rindex().
  934. X * Added variants of NCPFN and NCPPN for bsd 4.2, selected by defining V4_2BSD.
  935. X * Added macro DELNUMFORM to have uniform format for printing delta text nodes.
  936. X * Added macro DELETE to mark deleted deltas.
  937. X *
  938. X * Revision 3.5  82/12/10  12:16:56  wft
  939. X * Added two forms of DATEFORM, one using %02d, the other %.2d.
  940. X *
  941. X * Revision 3.4  82/12/04  20:01:25  wft
  942. X * added LOCKER, Locker, and USG (redefinition of rindex).
  943. X *
  944. X * Revision 3.3  82/12/03  12:22:04  wft
  945. X * Added dbm.h, stdio.h, RCSBASE, RCSSEP, RCSSUF, WORKMODE, TMPFILE3,
  946. X * PRINTDATE, PRINTTIME, map, and ctab; removed Suffix. Redefined keyvallength
  947. X * using NCPPN. Changed putc() to abort on write error.
  948. X *
  949. X * Revision 3.2  82/10/18  15:03:52  wft
  950. X * added macro STRICT_LOCKING, removed RCSUMASK.
  951. X * renamed JOINFILE[1,2] to JOINFIL[1,2].
  952. X *
  953. X * Revision 3.1  82/10/11  19:41:17  wft
  954. X * removed NBPW, NBPC, NCPW.
  955. X * added typdef int void to aid compiling
  956. X */
  957. X
  958. X
  959. X#include "conf.h"
  960. X
  961. X
  962. X#define EXIT_TROUBLE DIFF_TROUBLE
  963. X
  964. X#ifdef PATH_MAX
  965. X#    define SIZEABLE_PATH PATH_MAX /* size of a large path; not a hard limit */
  966. X#else
  967. X#    define SIZEABLE_PATH _POSIX_PATH_MAX
  968. X#endif
  969. X
  970. X/* for traditional C hosts with unusual size arguments */
  971. X#define Fread(p,s,n,f)  fread(p, (freadarg_type)(s), (freadarg_type)(n), f)
  972. X#define Fwrite(p,s,n,f)  fwrite(p, (freadarg_type)(s), (freadarg_type)(n), f)
  973. X
  974. X
  975. X/*
  976. X * Parameters
  977. X */
  978. X
  979. X/* backwards compatibility with old versions of RCS */
  980. X#define VERSION_min 3        /* old output RCS format supported */
  981. X#define VERSION_max 5        /* newest output RCS format supported */
  982. X#ifndef VERSION_DEFAULT        /* default RCS output format */
  983. X#    define VERSION_DEFAULT VERSION_max
  984. X#endif
  985. X#define VERSION(n) ((n) - VERSION_DEFAULT) /* internally, 0 is the default */
  986. X
  987. X#ifndef STRICT_LOCKING
  988. X#define STRICT_LOCKING 1
  989. X#endif
  990. X                  /* 0 sets the default locking to non-strict;  */
  991. X                              /* used in experimental environments.         */
  992. X                              /* 1 sets the default locking to strict;      */
  993. X                              /* used in production environments.           */
  994. X
  995. X#define yearlength       16 /* (good through AD 9,999,999,999,999,999)    */
  996. X#define datesize (yearlength+16) /* size of output of DATEFORM            */
  997. X#define joinlength         20 /* number of joined revisions permitted       */
  998. X#define RCSTMPPREFIX '_' /* prefix for temp files in working dir  */
  999. X#define KDELIM            '$' /* delimiter for keywords                     */
  1000. X#define VDELIM            ':' /* separates keywords from values             */
  1001. X#define DEFAULTSTATE    "Exp" /* default state of revisions                 */
  1002. X
  1003. X
  1004. X
  1005. X#define true     1
  1006. X#define false    0
  1007. X#define nil      0
  1008. X
  1009. X
  1010. X/*
  1011. X * RILE - readonly file
  1012. X * declarecache; - declares local cache for RILE variable(s)
  1013. X * setupcache - sets up the local RILE cache, but does not initialize it
  1014. X * cache, uncache - caches and uncaches the local RILE;
  1015. X *    (uncache,cache) is needed around functions that advance the RILE pointer
  1016. X * Igeteof(f,c,s) - get a char c from f, executing statement s at EOF
  1017. X * cachegeteof(c,s) - Igeteof applied to the local RILE
  1018. X * Iget(f,c) - like Igeteof, except EOF is an error
  1019. X * cacheget(c) - Iget applied to the local RILE
  1020. X * Ifileno, Irewind, Iseek, Itell - analogs to stdio routines
  1021. X */
  1022. X
  1023. X#if large_memory
  1024. X    typedef unsigned char const *Iptr_type;
  1025. X    typedef struct {
  1026. X        Iptr_type ptr, lim;
  1027. X        unsigned char *base; /* for lint, not Iptr_type even if has_mmap */
  1028. X#        if has_mmap
  1029. X#            define Ifileno(f) ((f)->fd)
  1030. X            int fd;
  1031. X#        else
  1032. X#            define Ifileno(f) fileno((f)->stream)
  1033. X            FILE *stream;
  1034. X            unsigned char *readlim;
  1035. X#        endif
  1036. X    } RILE;
  1037. X#    if has_mmap
  1038. X#        define declarecache register Iptr_type ptr, lim
  1039. X#        define setupcache(f) (lim = (f)->lim)
  1040. X#        define Igeteof(f,c,s) if ((f)->ptr==(f)->lim) s else (c)= *(f)->ptr++
  1041. X#        define cachegeteof(c,s) if (ptr==lim) s else (c)= *ptr++
  1042. X#    else
  1043. X#        define declarecache register Iptr_type ptr; register RILE *rRILE
  1044. X#        define setupcache(f) (rRILE = (f))
  1045. X#        define Igeteof(f,c,s) if ((f)->ptr==(f)->readlim && !Igetmore(f)) s else (c)= *(f)->ptr++
  1046. X#        define cachegeteof(c,s) if (ptr==rRILE->readlim && !Igetmore(rRILE)) s else (c)= *ptr++
  1047. X#    endif
  1048. X#    define uncache(f) ((f)->ptr = ptr)
  1049. X#    define cache(f) (ptr = (f)->ptr)
  1050. X#    define Iget(f,c) Igeteof(f,c,Ieof();)
  1051. X#    define cacheget(c) cachegeteof(c,Ieof();)
  1052. X#    define Itell(f) ((f)->ptr)
  1053. X#    define Iseek(f,p) ((f)->ptr = (p))
  1054. X#    define Irewind(f) Iseek(f, (f)->base)
  1055. X#    define cachetell() ptr
  1056. X#else
  1057. X#    define RILE FILE
  1058. X#    define declarecache register FILE *ptr
  1059. X#    define setupcache(f) (ptr = (f))
  1060. X#    define uncache(f)
  1061. X#    define cache(f)
  1062. X#    define Igeteof(f,c,s) if(((c)=getc(f))<0){testIerror(f);if(feof(f))s}else
  1063. X#    define cachegeteof(c,s) Igeteof(ptr,c,s)
  1064. X#    define Iget(f,c) if (((c)=getc(f))<0) testIeof(f); else
  1065. X#    define cacheget(c) Iget(ptr,c)
  1066. X#    define Ifileno(f) fileno(f)
  1067. X#endif
  1068. X
  1069. X/* Print a char, but abort on write error.  */
  1070. X#define aputc(c,o) if (putc(c,o)<0) testOerror(o); else
  1071. X
  1072. X/* Get a character from an RCS file, perhaps copying to a new RCS file.  */
  1073. X#define GETCeof(o,c,s) { cachegeteof(c,s); if (o) aputc(c,o); }
  1074. X#define GETC(o,c) { cacheget(c); if (o) aputc(c,o); }
  1075. X
  1076. X
  1077. X#define WORKMODE(RCSmode, writable) ((RCSmode)&~(S_IWUSR|S_IWGRP|S_IWOTH) | ((writable)?S_IWUSR:0))
  1078. X/* computes mode of working file: same as RCSmode, but write permission     */
  1079. X/* determined by writable */
  1080. X
  1081. X
  1082. X/* character classes and token codes */
  1083. enum tokens {
  1084. X/* classes */    DELIM,    DIGIT,    IDCHAR,    NEWLN,    LETTER,    Letter,
  1085. X        PERIOD,    SBEGIN,    SPACE,    UNKN,
  1086. X/* tokens */    COLON,    ID,    NUM,    SEMI,    STRING
  1087. X};
  1088. X
  1089. X#define SDELIM  '@'     /* the actual character is needed for string handling*/
  1090. X/* SDELIM must be consistent with ctab[], so that ctab[SDELIM]==SBEGIN.
  1091. X * there should be no overlap among SDELIM, KDELIM, and VDELIM
  1092. X */
  1093. X
  1094. X#define isdigit(c) ((unsigned)((c)-'0') <= 9) /* faster than ctab[c]==DIGIT */
  1095. X
  1096. X
  1097. X
  1098. X
  1099. X
  1100. X/***************************************
  1101. X * Data structures for the symbol table
  1102. X ***************************************/
  1103. X
  1104. X/* Buffer of arbitrary data */
  1105. struct buf {
  1106. X    char *string;
  1107. X    size_t size;
  1108. X};
  1109. struct cbuf {
  1110. X    char const *string;
  1111. X    size_t size;
  1112. X};
  1113. X
  1114. X/* Hash table entry */
  1115. struct hshentry {
  1116. X    char const      * num;      /* pointer to revision number (ASCIZ) */
  1117. X    char const      * date;     /* pointer to date of checkin        */
  1118. X    char const      * author;   /* login of person checking in        */
  1119. X    char const      * lockedby; /* who locks the revision            */
  1120. X    char const      * state;    /* state of revision (Exp by default) */
  1121. X    struct cbuf        log;      /* log message requested at checkin   */
  1122. X        struct branchhead * branches; /* list of first revisions on branches*/
  1123. X    struct cbuf        ig;          /* ignored phrases of revision        */
  1124. X        struct hshentry   * next;     /* next revision on same branch       */
  1125. X    struct hshentry   * nexthsh;  /* next revision with same hash value */
  1126. X    unsigned long        insertlns;/* lines inserted (computed by rlog)  */
  1127. X    unsigned long        deletelns;/* lines deleted  (computed by rlog)  */
  1128. X    char            selector; /* true if selected, false if deleted */
  1129. X};
  1130. X
  1131. X/* list of hash entries */
  1132. struct hshentries {
  1133. X    struct hshentries *rest;
  1134. X    struct hshentry *first;
  1135. X};
  1136. X
  1137. X/* list element for branch lists */
  1138. struct branchhead {
  1139. X        struct hshentry   * hsh;
  1140. X        struct branchhead * nextbranch;
  1141. X};
  1142. X
  1143. X/* accesslist element */
  1144. struct access {
  1145. X    char const      * login;
  1146. X        struct access     * nextaccess;
  1147. X};
  1148. X
  1149. X/* list element for locks  */
  1150. struct lock {
  1151. X    char const      * login;
  1152. X        struct hshentry   * delta;
  1153. X        struct lock       * nextlock;
  1154. X};
  1155. X
  1156. X/* list element for symbolic names */
  1157. struct assoc {
  1158. X    char const      * symbol;
  1159. X    char const      * num;
  1160. X        struct assoc      * nextassoc;
  1161. X};
  1162. X
  1163. X
  1164. X#define mainArgs (argc,argv) int argc; char **argv;
  1165. X
  1166. X#if lint
  1167. X#    define libId(name,rcsid)
  1168. X#    define mainProg(name,cmd,rcsid) int name mainArgs
  1169. X#else
  1170. X#    define libId(name,rcsid) char const name[] = rcsid;
  1171. X#    define mainProg(name,cmd,rcsid) char const copyright[] = "Copyright 1982,1988,1989 by Walter F. Tichy\nPurdue CS\nCopyright 1990,1991 by Paul Eggert", rcsbaseId[] = RCSBASE, cmdid[] = cmd; libId(name,rcsid) int main mainArgs
  1172. X#endif
  1173. X
  1174. X/*
  1175. X * Markers for keyword expansion (used in co and ident)
  1176. X *    Every byte must have class LETTER or Letter.
  1177. X */
  1178. X#define AUTHOR          "Author"
  1179. X#define DATE            "Date"
  1180. X#define HEADER          "Header"
  1181. X#define IDH             "Id"
  1182. X#define LOCKER          "Locker"
  1183. X#define LOG             "Log"
  1184. X#define RCSFILE         "RCSfile"
  1185. X#define REVISION        "Revision"
  1186. X#define SOURCE          "Source"
  1187. X#define STATE           "State"
  1188. X#define keylength 8 /* max length of any of the above keywords */
  1189. X
  1190. enum markers { Nomatch, Author, Date, Header, Id,
  1191. X           Locker, Log, RCSfile, Revision, Source, State };
  1192. X    /* This must be in the same order as rcskeys.c's Keyword[] array. */
  1193. X
  1194. X#define DELNUMFORM      "\n\n%s\n%s\n"
  1195. X/* used by putdtext and scanlogtext */
  1196. X
  1197. X#define EMPTYLOG "*** empty log message ***" /* used by ci and rlog */
  1198. X
  1199. X/* main program */
  1200. extern char const cmdid[];
  1201. exiting void exiterr P((void));
  1202. X
  1203. X/* maketime */
  1204. int setfiledate P((char const*,char const[datesize]));
  1205. void str2date P((char const*,char[datesize]));
  1206. void time2date P((time_t,char[datesize]));
  1207. X
  1208. X/* merge */
  1209. int merge P((int,char const*const[2],char const*const[3]));
  1210. X
  1211. X/* partime */
  1212. int partime P((char const*,struct tm*,int*));
  1213. X
  1214. X/* rcsedit */
  1215. X#define ciklogsize 23 /* sizeof("checked in with -k by ") */
  1216. extern FILE *fcopy;
  1217. extern char const *resultfile;
  1218. extern char const ciklog[ciklogsize];
  1219. extern int locker_expansion;
  1220. extern struct buf dirtfname[];
  1221. X#define newRCSfilename (dirtfname[0].string)
  1222. RILE *rcswriteopen P((struct buf*,struct stat*,int));
  1223. char const *makedirtemp P((char const*,int));
  1224. char const *getcaller P((void));
  1225. int addlock P((struct hshentry*));
  1226. int addsymbol P((char const*,char const*,int));
  1227. int checkaccesslist P((void));
  1228. int chnamemod P((FILE**,char const*,char const*,mode_t));
  1229. int donerewrite P((int));
  1230. int dorewrite P((int,int));
  1231. int expandline P((RILE*,FILE*,struct hshentry const*,int,FILE*));
  1232. int findlock P((int,struct hshentry**));
  1233. void aflush P((FILE*));
  1234. void copystring P((void));
  1235. void dirtempunlink P((void));
  1236. void enterstring P((void));
  1237. void finishedit P((struct hshentry const*,FILE*,int));
  1238. void keepdirtemp P((char const*));
  1239. void openfcopy P((FILE*));
  1240. void snapshotedit P((FILE*));
  1241. void xpandstring P((struct hshentry const*));
  1242. X#if has_NFS || bad_unlink
  1243. X    int un_link P((char const*));
  1244. X#else
  1245. X#    define un_link(s) unlink(s)
  1246. X#endif
  1247. X#if large_memory
  1248. X    void edit_string P((void));
  1249. X#    define editstring(delta) edit_string()
  1250. X#else
  1251. X    void editstring P((struct hshentry const*));
  1252. X#endif
  1253. X
  1254. X/* rcsfcmp */
  1255. int rcsfcmp P((RILE*,struct stat const*,char const*,struct hshentry const*));
  1256. X
  1257. X/* rcsfnms */
  1258. X#define bufautobegin(b) ((void) ((b)->string = 0, (b)->size = 0))
  1259. extern FILE *workstdout;
  1260. extern char *workfilename;
  1261. extern char const *RCSfilename;
  1262. extern char const *suffixes;
  1263. extern struct stat RCSstat;
  1264. RILE *rcsreadopen P((struct buf*,struct stat*,int));
  1265. char *bufenlarge P((struct buf*,char const**));
  1266. char const *basename P((char const*));
  1267. char const *getfullRCSname P((void));
  1268. char const *maketemp P((int));
  1269. char const *rcssuffix P((char const*));
  1270. int pairfilenames P((int,char**,RILE*(*)P((struct buf*,struct stat*,int)),int,int));
  1271. size_t dirlen P((char const*));
  1272. struct cbuf bufremember P((struct buf*,size_t));
  1273. void bufalloc P((struct buf*,size_t));
  1274. void bufautoend P((struct buf*));
  1275. void bufrealloc P((struct buf*,size_t));
  1276. void bufscat P((struct buf*,char const*));
  1277. void bufscpy P((struct buf*,char const*));
  1278. void tempunlink P((void));
  1279. X
  1280. X/* rcsgen */
  1281. extern int interactiveflag;
  1282. extern struct buf curlogbuf;
  1283. char const *buildrevision P((struct hshentries const*,struct hshentry*,FILE*,int));
  1284. int getcstdin P((void));
  1285. int ttystdin P((void));
  1286. int yesorno P((int,char const*,...));
  1287. struct cbuf cleanlogmsg P((char*,size_t));
  1288. struct cbuf getsstdin P((char const*,char const*,char const*,struct buf*));
  1289. void putdesc P((int,char*));
  1290. X
  1291. X/* rcskeep */
  1292. extern int prevkeys;
  1293. extern struct buf prevauthor, prevdate, prevrev, prevstate;
  1294. int getoldkeys P((RILE*));
  1295. X
  1296. X/* rcskeys */
  1297. extern char const *const Keyword[];
  1298. enum markers trymatch P((char const*));
  1299. X
  1300. X/* rcslex */
  1301. extern FILE *foutptr;
  1302. extern FILE *frewrite;
  1303. extern RILE *finptr;
  1304. extern char const *NextString;
  1305. extern enum tokens nexttok;
  1306. extern int hshenter;
  1307. extern int nerror;
  1308. extern int nextc;
  1309. extern int quietflag;
  1310. extern unsigned long rcsline;
  1311. char const *getid P((void));
  1312. exiting void efaterror P((char const*));
  1313. exiting void enfaterror P((int,char const*));
  1314. exiting void faterror P((char const*,...));
  1315. exiting void fatserror P((char const*,...));
  1316. exiting void Ieof P((void));
  1317. exiting void Ierror P((void));
  1318. exiting void Oerror P((void));
  1319. char *checkid P((char*,int));
  1320. int eoflex P((void));
  1321. int getkeyopt P((char const*));
  1322. int getlex P((enum tokens));
  1323. struct cbuf getphrases P((char const*));
  1324. struct cbuf savestring P((struct buf*));
  1325. struct hshentry *getnum P((void));
  1326. void Ifclose P((RILE*));
  1327. void Izclose P((RILE**));
  1328. void Lexinit P((void));
  1329. void Ofclose P((FILE*));
  1330. void Ozclose P((FILE**));
  1331. void afputc P((int,FILE*));
  1332. void aprintf P((FILE*,char const*,...));
  1333. void aputs P((char const*,FILE*));
  1334. void checksid P((char*));
  1335. void diagnose P((char const*,...));
  1336. void eerror P((char const*));
  1337. void eflush P((void));
  1338. void enerror P((int,char const*));
  1339. void error P((char const*,...));
  1340. void fvfprintf P((FILE*,char const*,va_list));
  1341. void getkey P((char const*));
  1342. void getkeystring P((char const*));
  1343. void nextlex P((void));
  1344. void oflush P((void));
  1345. void printstring P((void));
  1346. void readstring P((void));
  1347. void redefined P((int));
  1348. void testIerror P((FILE*));
  1349. void testOerror P((FILE*));
  1350. void warn P((char const*,...));
  1351. void warnignore P((void));
  1352. X#if has_madvise && has_mmap && large_memory
  1353. X    void advise_access P((RILE*,int));
  1354. X#    define if_advise_access(p,f,advice) if (p) advise_access(f,advice)
  1355. X#else
  1356. X#    define advise_access(f,advice)
  1357. X#    define if_advise_access(p,f,advice)
  1358. X#endif
  1359. X#if has_mmap && large_memory
  1360. X    RILE *I_open P((char const*,struct stat*));
  1361. X#    define Iopen(f,m,s) I_open(f,s)
  1362. X#else
  1363. X    RILE *Iopen P((char const*,char const*,struct stat*));
  1364. X#endif
  1365. X#if !large_memory
  1366. X    void testIeof P((FILE*));
  1367. X    void Irewind P((RILE*));
  1368. X#endif
  1369. X
  1370. X/* rcsmap */
  1371. extern const enum tokens ctab[];
  1372. X
  1373. X/* rcsrev */
  1374. char *partialno P((struct buf*,char const*,unsigned));
  1375. char const *tiprev P((void));
  1376. int cmpnum P((char const*,char const*));
  1377. int cmpnumfld P((char const*,char const*,unsigned));
  1378. int compartial P((char const*,char const*,unsigned));
  1379. int expandsym P((char const*,struct buf*));
  1380. int fexpandsym P((char const*,struct buf*,RILE*));
  1381. struct hshentry *genrevs P((char const*,char const*,char const*,char const*,struct hshentries**));
  1382. unsigned countnumflds P((char const*));
  1383. void getbranchno P((char const*,struct buf*));
  1384. X
  1385. X/* rcssyn */
  1386. X/* These expand modes must agree with Expand_names[] in rcssyn.c.  */
  1387. X#define KEYVAL_EXPAND 0 /* -kkv `$Keyword: value $' */
  1388. X#define KEYVALLOCK_EXPAND 1 /* -kkvl `$Keyword: value locker $' */
  1389. X#define KEY_EXPAND 2 /* -kk `$Keyword$' */
  1390. X#define VAL_EXPAND 3 /* -kv `value' */
  1391. X#define OLD_EXPAND 4 /* -ko use old string, omitting expansion */
  1392. struct diffcmd {
  1393. X    unsigned long
  1394. X        line1, /* number of first line */
  1395. X        nlines, /* number of lines affected */
  1396. X        adprev, /* previous 'a' line1+1 or 'd' line1 */
  1397. X        dafter; /* sum of previous 'd' line1 and previous 'd' nlines */
  1398. X};
  1399. extern char const      * Dbranch;
  1400. extern struct access   * AccessList;
  1401. extern struct assoc    * Symbols;
  1402. extern struct cbuf Comment;
  1403. extern struct lock     * Locks;
  1404. extern struct hshentry * Head;
  1405. extern int         Expand;
  1406. extern int               StrictLocks;
  1407. extern unsigned TotalDeltas;
  1408. extern char const *const expand_names[];
  1409. extern char const Kdesc[];
  1410. extern char const Klog[];
  1411. extern char const Ktext[];
  1412. int getdiffcmd P((RILE*,int,FILE*,struct diffcmd*));
  1413. int putdftext P((char const*,struct cbuf,RILE*,FILE*,int));
  1414. int putdtext P((char const*,struct cbuf,char const*,FILE*,int));
  1415. int str2expmode P((char const*));
  1416. void getadmin P((void));
  1417. void getdesc P((int));
  1418. void gettree P((void));
  1419. void ignorephrase P((void));
  1420. void initdiffcmd P((struct diffcmd*));
  1421. void putadmin P((FILE*));
  1422. void putstring P((FILE*,int,struct cbuf,int));
  1423. void puttree P((struct hshentry const*,FILE*));
  1424. X
  1425. X/* rcsutil */
  1426. extern int RCSversion;
  1427. char *cgetenv P((char const*));
  1428. char *fstr_save P((char const*));
  1429. char *str_save P((char const*));
  1430. char const *date2str P((char const[datesize],char[datesize]));
  1431. char const *getusername P((int));
  1432. int getRCSINIT P((int,char**,char***));
  1433. int run P((char const*,char const*,...));
  1434. int runv P((char const**));
  1435. malloc_type fremember P((malloc_type));
  1436. malloc_type ftestalloc P((size_t));
  1437. malloc_type testalloc P((size_t));
  1438. malloc_type testrealloc P((malloc_type,size_t));
  1439. X#define ftalloc(T) ftnalloc(T,1)
  1440. X#define talloc(T) tnalloc(T,1)
  1441. X#if lint
  1442. X    extern malloc_type lintalloc;
  1443. X#    define ftnalloc(T,n) (lintalloc = ftestalloc(sizeof(T)*(n)), (T*)0)
  1444. X#    define tnalloc(T,n) (lintalloc = testalloc(sizeof(T)*(n)), (T*)0)
  1445. X#    define trealloc(T,p,n) (lintalloc = testrealloc((malloc_type)0, sizeof(T)*(n)), p)
  1446. X#    define tfree(p)
  1447. X#else
  1448. X#    define ftnalloc(T,n) ((T*) ftestalloc(sizeof(T)*(n)))
  1449. X#    define tnalloc(T,n) ((T*) testalloc(sizeof(T)*(n)))
  1450. X#    define trealloc(T,p,n) ((T*) testrealloc((malloc_type)(p), sizeof(T)*(n)))
  1451. X#    define tfree(p) free((malloc_type)(p))
  1452. X#endif
  1453. void awrite P((char const*,size_t,FILE*));
  1454. void fastcopy P((RILE*,FILE*));
  1455. void ffree P((void));
  1456. void ffree1 P((char const*));
  1457. void setRCSversion P((char const*));
  1458. X#if has_signal
  1459. X    void catchints P((void));
  1460. X    void ignoreints P((void));
  1461. X    void restoreints P((void));
  1462. X#else
  1463. X#    define catchints()
  1464. X#    define ignoreints()
  1465. X#    define restoreints()
  1466. X#endif
  1467. X#if has_getuid
  1468. X    uid_t ruid P((void));
  1469. X#    define myself(u) ((u) == ruid())
  1470. X#else
  1471. X#    define myself(u) true
  1472. X#endif
  1473. X#if has_setuid
  1474. X    uid_t euid P((void));
  1475. X    void nosetid P((void));
  1476. X    void seteid P((void));
  1477. X    void setrid P((void));
  1478. X#else
  1479. X#    define nosetid()
  1480. X#    define seteid()
  1481. X#    define setrid()
  1482. X#endif
  1483. END_OF_FILE
  1484. if test 22152 -ne `wc -c <'src/rcsbase.h'`; then
  1485.     echo shar: \"'src/rcsbase.h'\" unpacked with wrong size!
  1486. fi
  1487. # end of 'src/rcsbase.h'
  1488. fi
  1489. if test -f 'src/rcsrev.c' -a "${1}" != "-c" ; then 
  1490.   echo shar: Will not clobber existing file \"'src/rcsrev.c'\"
  1491. else
  1492. echo shar: Extracting \"'src/rcsrev.c'\" \(21002 characters\)
  1493. sed "s/^X//" >'src/rcsrev.c' <<'END_OF_FILE'
  1494. X/*
  1495. X *                     RCS revision number handling
  1496. X */
  1497. X
  1498. X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
  1499. X   Copyright 1990, 1991 by Paul Eggert
  1500. X   Distributed under license by the Free Software Foundation, Inc.
  1501. X
  1502. This file is part of RCS.
  1503. X
  1504. RCS is free software; you can redistribute it and/or modify
  1505. it under the terms of the GNU General Public License as published by
  1506. the Free Software Foundation; either version 2, or (at your option)
  1507. any later version.
  1508. X
  1509. RCS is distributed in the hope that it will be useful,
  1510. but WITHOUT ANY WARRANTY; without even the implied warranty of
  1511. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1512. GNU General Public License for more details.
  1513. X
  1514. You should have received a copy of the GNU General Public License
  1515. along with RCS; see the file COPYING.  If not, write to
  1516. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  1517. X
  1518. Report problems and direct all questions to:
  1519. X
  1520. X    rcs-bugs@cs.purdue.edu
  1521. X
  1522. X*/
  1523. X
  1524. X
  1525. X
  1526. X
  1527. X/* $Log: rcsrev.c,v $
  1528. X * Revision 5.3  1991/08/19  03:13:55  eggert
  1529. X * Add `-r$', `-rB.'.  Remove botches like `<now>' from messages.  Tune.
  1530. X *
  1531. X * Revision 5.2  1991/04/21  11:58:28  eggert
  1532. X * Add tiprev().
  1533. X *
  1534. X * Revision 5.1  1991/02/25  07:12:43  eggert
  1535. X * Avoid overflow when comparing revision numbers.
  1536. X *
  1537. X * Revision 5.0  1990/08/22  08:13:43  eggert
  1538. X * Remove compile-time limits; use malloc instead.
  1539. X * Ansify and Posixate.  Tune.
  1540. X * Remove possibility of an internal error.  Remove lint.
  1541. X *
  1542. X * Revision 4.5  89/05/01  15:13:22  narten
  1543. X * changed copyright header to reflect current distribution rules
  1544. X * 
  1545. X * Revision 4.4  87/12/18  11:45:22  narten
  1546. X * more lint cleanups. Also, the NOTREACHED comment is no longer necessary, 
  1547. X * since there's now a return value there with a value. (Guy Harris)
  1548. X * 
  1549. X * Revision 4.3  87/10/18  10:38:42  narten
  1550. X * Updating version numbers. Changes relative to version 1.1 actually 
  1551. X * relative to 4.1
  1552. X * 
  1553. X * Revision 1.3  87/09/24  14:00:37  narten
  1554. X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  1555. X * warnings)
  1556. X * 
  1557. X * Revision 1.2  87/03/27  14:22:37  jenkins
  1558. X * Port to suns
  1559. X * 
  1560. X * Revision 4.1  83/03/25  21:10:45  wft
  1561. X * Only changed $Header to $Id.
  1562. X * 
  1563. X * Revision 3.4  82/12/04  13:24:08  wft
  1564. X * Replaced getdelta() with gettree().
  1565. X *
  1566. X * Revision 3.3  82/11/28  21:33:15  wft
  1567. X * fixed compartial() and compnum() for nil-parameters; fixed nils
  1568. X * in error messages. Testprogram output shortenend.
  1569. X *
  1570. X * Revision 3.2  82/10/18  21:19:47  wft
  1571. X * renamed compnum->cmpnum, compnumfld->cmpnumfld,
  1572. X * numericrevno->numricrevno.
  1573. X *
  1574. X * Revision 3.1  82/10/11  19:46:09  wft
  1575. X * changed expandsym() to check for source==nil; returns zero length string
  1576. X * in that case.
  1577. X */
  1578. X
  1579. X
  1580. X
  1581. X/*
  1582. X#define REVTEST
  1583. X*/
  1584. X/* version REVTEST is for testing the routines that generate a sequence
  1585. X * of delta numbers needed to regenerate a given delta.
  1586. X */
  1587. X
  1588. X#include "rcsbase.h"
  1589. X
  1590. libId(revId, "$Id: rcsrev.c,v 5.3 1991/08/19 03:13:55 eggert Exp $")
  1591. X
  1592. static char const *branchtip P((char const*));
  1593. static struct hshentry *genbranch P((struct hshentry const*,char const*,unsigned,char const*,char const*,char const*,struct hshentries**));
  1594. X
  1595. X
  1596. X
  1597. X    unsigned
  1598. countnumflds(s)
  1599. X    char const *s;
  1600. X/* Given a pointer s to a dotted number (date or revision number),
  1601. X * countnumflds returns the number of digitfields in s.
  1602. X */
  1603. X{
  1604. X    register char const *sp;
  1605. X    register unsigned count;
  1606. X        if ((sp=s)==nil) return(0);
  1607. X        if (*sp == '\0') return(0);
  1608. X        count = 1;
  1609. X    do {
  1610. X                if (*sp++ == '.') count++;
  1611. X    } while (*sp);
  1612. X        return(count);
  1613. X}
  1614. X
  1615. X    void
  1616. getbranchno(revno,branchno)
  1617. X    char const *revno;
  1618. X    struct buf *branchno;
  1619. X/* Given a non-nil revision number revno, getbranchno copies the number of the branch
  1620. X * on which revno is into branchno. If revno itself is a branch number,
  1621. X * it is copied unchanged.
  1622. X */
  1623. X{
  1624. X    register unsigned numflds;
  1625. X    register char *tp;
  1626. X
  1627. X    bufscpy(branchno, revno);
  1628. X        numflds=countnumflds(revno);
  1629. X    if (!(numflds & 1)) {
  1630. X        tp = branchno->string;
  1631. X        while (--numflds)
  1632. X            while (*tp++ != '.')
  1633. X                ;
  1634. X                *(tp-1)='\0';
  1635. X        }
  1636. X}
  1637. X
  1638. X
  1639. X
  1640. int cmpnum(num1, num2)
  1641. X    char const *num1, *num2;
  1642. X/* compares the two dotted numbers num1 and num2 lexicographically
  1643. X * by field. Individual fields are compared numerically.
  1644. X * returns <0, 0, >0 if num1<num2, num1==num2, and num1>num2, resp.
  1645. X * omitted fields are assumed to be higher than the existing ones.
  1646. X*/
  1647. X{
  1648. X    register char const *s1, *s2;
  1649. X    register size_t d1, d2;
  1650. X    register int r;
  1651. X
  1652. X        s1=num1==nil?"":num1;
  1653. X        s2=num2==nil?"":num2;
  1654. X
  1655. X    for (;;) {
  1656. X        /* Give precedence to shorter one.  */
  1657. X        if (!*s1)
  1658. X            return (unsigned char)*s2;
  1659. X        if (!*s2)
  1660. X            return -1;
  1661. X
  1662. X        /* Strip leading zeros, then find number of digits.  */
  1663. X        while (*s1=='0') ++s1;  for (d1=0; isdigit(s1[d1]); d1++) ;
  1664. X        while (*s2=='0') ++s2;  for (d2=0; isdigit(s2[d2]); d2++) ;
  1665. X
  1666. X        /* Do not convert to integer; it might overflow!  */
  1667. X        if (d1 != d2)
  1668. X            return d1<d2 ? -1 : 1;
  1669. X        if ((r = memcmp(s1, s2, d1)))
  1670. X            return r;
  1671. X        s1 += d1;
  1672. X        s2 += d1;
  1673. X
  1674. X                /* skip '.' */
  1675. X        if (*s1) s1++;
  1676. X        if (*s2) s2++;
  1677. X    }
  1678. X}
  1679. X
  1680. X
  1681. X
  1682. int cmpnumfld(num1, num2, fld)
  1683. X    char const *num1, *num2;
  1684. X    unsigned fld;
  1685. X/* Compare the two dotted numbers at field fld.
  1686. X * num1 and num2 must have at least fld fields.
  1687. X * fld must be positive.
  1688. X*/
  1689. X{
  1690. X    register char const *s1, *s2;
  1691. X    register size_t d1, d2;
  1692. X
  1693. X    s1 = num1;
  1694. X    s2 = num2;
  1695. X        /* skip fld-1 fields */
  1696. X    while (--fld) {
  1697. X        while (*s1++ != '.')
  1698. X            ;
  1699. X        while (*s2++ != '.')
  1700. X            ;
  1701. X    }
  1702. X        /* Now s1 and s2 point to the beginning of the respective fields */
  1703. X    while (*s1=='0') ++s1;  for (d1=0; isdigit(s1[d1]); d1++) ;
  1704. X    while (*s2=='0') ++s2;  for (d2=0; isdigit(s2[d2]); d2++) ;
  1705. X
  1706. X    return d1<d2 ? -1 : d1==d2 ? memcmp(s1,s2,d1) : 1;
  1707. X}
  1708. X
  1709. X
  1710. X    static void
  1711. cantfindbranch(revno, date, author, state)
  1712. X    char const *revno, date[datesize], *author, *state;
  1713. X{
  1714. X    char datebuf[datesize];
  1715. X
  1716. X    error("No revision on branch %s has%s%s%s%s%s%s.",
  1717. X        revno,
  1718. X        date ? " a date before " : "",
  1719. X        date ? date2str(date,datebuf) : "",
  1720. X        author ? " and author "+(date?0:4) : "",
  1721. X        author ? author : "",
  1722. X        state ? " and state "+(date||author?0:4) : "",
  1723. X        state ? state : ""
  1724. X    );
  1725. X}
  1726. X
  1727. X    static void
  1728. absent(revno, field)
  1729. X    char const *revno;
  1730. X    unsigned field;
  1731. X{
  1732. X    struct buf t;
  1733. X    bufautobegin(&t);
  1734. X    error("%s %s absent", field&1?"revision":"branch",
  1735. X        partialno(&t,revno,field)
  1736. X    );
  1737. X    bufautoend(&t);
  1738. X}
  1739. X
  1740. X
  1741. X    int
  1742. compartial(num1, num2, length)
  1743. X    char const *num1, *num2;
  1744. X    unsigned length;
  1745. X
  1746. X/*   compare the first "length" fields of two dot numbers;
  1747. X     the omitted field is considered to be larger than any number  */
  1748. X/*   restriction:  at least one number has length or more fields   */
  1749. X
  1750. X{
  1751. X    register char const *s1, *s2;
  1752. X    register size_t d1, d2;
  1753. X    register int r;
  1754. X
  1755. X        s1 = num1;      s2 = num2;
  1756. X    if (!s1) return 1;
  1757. X    if (!s2) return -1;
  1758. X
  1759. X    for (;;) {
  1760. X        if (!*s1) return 1;
  1761. X        if (!*s2) return -1;
  1762. X
  1763. X        while (*s1=='0') ++s1;  for (d1=0; isdigit(s1[d1]); d1++) ;
  1764. X        while (*s2=='0') ++s2;  for (d2=0; isdigit(s2[d2]); d2++) ;
  1765. X
  1766. X        if (d1 != d2)
  1767. X            return d1<d2 ? -1 : 1;
  1768. X        if ((r = memcmp(s1, s2, d1)))
  1769. X            return r;
  1770. X        s1 += d1;
  1771. X        s2 += d1;
  1772. X
  1773. X        if (*s1 == '.') s1++;
  1774. X            if (*s2 == '.') s2++;
  1775. X
  1776. X        if ( --length == 0 ) return 0;
  1777. X    }
  1778. X}
  1779. X
  1780. X
  1781. char * partialno(rev1,rev2,length)
  1782. X    struct buf *rev1;
  1783. X    char const *rev2;
  1784. X    register unsigned length;
  1785. X/* Function: Copies length fields of revision number rev2 into rev1.
  1786. X * Return rev1's string.
  1787. X */
  1788. X{
  1789. X    register char *r1;
  1790. X
  1791. X    bufscpy(rev1, rev2);
  1792. X    r1 = rev1->string;
  1793. X        while (length) {
  1794. X        while (*r1!='.' && *r1)
  1795. X            ++r1;
  1796. X        ++r1;
  1797. X                length--;
  1798. X        }
  1799. X        /* eliminate last '.'*/
  1800. X        *(r1-1)='\0';
  1801. X    return rev1->string;
  1802. X}
  1803. X
  1804. X
  1805. X
  1806. X
  1807. X    static void
  1808. store1(store, next)
  1809. X    struct hshentries ***store;
  1810. X    struct hshentry *next;
  1811. X/*
  1812. X * Allocate a new list node that addresses NEXT.
  1813. X * Append it to the list that **STORE is the end pointer of.
  1814. X */
  1815. X{
  1816. X    register struct hshentries *p;
  1817. X
  1818. X    p = ftalloc(struct hshentries);
  1819. X    p->first = next;
  1820. X    **store = p;
  1821. X    *store = &p->rest;
  1822. X}
  1823. X
  1824. struct hshentry * genrevs(revno,date,author,state,store)
  1825. X    char const *revno, *date, *author, *state;
  1826. X    struct hshentries **store;
  1827. X/* Function: finds the deltas needed for reconstructing the
  1828. X * revision given by revno, date, author, and state, and stores pointers
  1829. X * to these deltas into a list whose starting address is given by store.
  1830. X * The last delta (target delta) is returned.
  1831. X * If the proper delta could not be found, nil is returned.
  1832. X */
  1833. X{
  1834. X    unsigned length;
  1835. X        register struct hshentry * next;
  1836. X        int result;
  1837. X    char const *branchnum;
  1838. X    struct buf t;
  1839. X    char datebuf[datesize];
  1840. X
  1841. X    bufautobegin(&t);
  1842. X
  1843. X    if (!(next = Head)) {
  1844. X        error("RCS file empty");
  1845. X        goto norev;
  1846. X        }
  1847. X
  1848. X        length = countnumflds(revno);
  1849. X
  1850. X        if (length >= 1) {
  1851. X                /* at least one field; find branch exactly */
  1852. X        while ((result=cmpnumfld(revno,next->num,1)) < 0) {
  1853. X            store1(&store, next);
  1854. X                        next = next->next;
  1855. X            if (!next) {
  1856. X                error("branch number %s too low", partialno(&t,revno,1));
  1857. X                goto norev;
  1858. X            }
  1859. X                }
  1860. X
  1861. X        if (result>0) {
  1862. X            absent(revno, 1);
  1863. X            goto norev;
  1864. X        }
  1865. X        }
  1866. X        if (length<=1){
  1867. X                /* pick latest one on given branch */
  1868. X                branchnum = next->num; /* works even for empty revno*/
  1869. X                while ((next!=nil) &&
  1870. X                       (cmpnumfld(branchnum,next->num,1)==0) &&
  1871. X                       !(
  1872. X                        (date==nil?1:(cmpnum(date,next->date)>=0)) &&
  1873. X                        (author==nil?1:(strcmp(author,next->author)==0)) &&
  1874. X                        (state ==nil?1:(strcmp(state, next->state) ==0))
  1875. X                        )
  1876. X                       )
  1877. X        {
  1878. X            store1(&store, next);
  1879. X                        next=next->next;
  1880. X                }
  1881. X                if ((next==nil) ||
  1882. X                    (cmpnumfld(branchnum,next->num,1)!=0))/*overshot*/ {
  1883. X            cantfindbranch(
  1884. X                length ? revno : partialno(&t,branchnum,1),
  1885. X                date, author, state
  1886. X            );
  1887. X            goto norev;
  1888. X                } else {
  1889. X            store1(&store, next);
  1890. X                }
  1891. X                *store = nil;
  1892. X                return next;
  1893. X        }
  1894. X
  1895. X        /* length >=2 */
  1896. X        /* find revision; may go low if length==2*/
  1897. X    while ((result=cmpnumfld(revno,next->num,2)) < 0  &&
  1898. X               (cmpnumfld(revno,next->num,1)==0) ) {
  1899. X        store1(&store, next);
  1900. X                next = next->next;
  1901. X        if (!next)
  1902. X            break;
  1903. X        }
  1904. X
  1905. X        if ((next==nil) || (cmpnumfld(revno,next->num,1)!=0)) {
  1906. X        error("revision number %s too low", partialno(&t,revno,2));
  1907. X        goto norev;
  1908. X        }
  1909. X        if ((length>2) && (result!=0)) {
  1910. X        absent(revno, 2);
  1911. X        goto norev;
  1912. X        }
  1913. X
  1914. X        /* print last one */
  1915. X    store1(&store, next);
  1916. X
  1917. X        if (length>2)
  1918. X                return genbranch(next,revno,length,date,author,state,store);
  1919. X        else { /* length == 2*/
  1920. X                if ((date!=nil) && (cmpnum(date,next->date)<0)){
  1921. X            error("Revision %s has date %s.",
  1922. X                next->num,
  1923. X                date2str(next->date, datebuf)
  1924. X            );
  1925. X                        return nil;
  1926. X                }
  1927. X                if ((author!=nil)&&(strcmp(author,next->author)!=0)) {
  1928. X                        error("Revision %s has author %s.",next->num,next->author);
  1929. X                        return nil;
  1930. X                }
  1931. X                if ((state!=nil)&&(strcmp(state,next->state)!=0)) {
  1932. X                        error("Revision %s has state %s.",next->num,
  1933. X                               next->state==nil?"<empty>":next->state);
  1934. X                        return nil;
  1935. X                }
  1936. X                *store=nil;
  1937. X                return next;
  1938. X        }
  1939. X
  1940. X    norev:
  1941. X    bufautoend(&t);
  1942. X    return nil;
  1943. X}
  1944. X
  1945. X
  1946. X
  1947. X
  1948. X    static struct hshentry *
  1949. genbranch(bpoint, revno, length, date, author, state, store)
  1950. X    struct hshentry const *bpoint;
  1951. X    char const *revno;
  1952. X    unsigned length;
  1953. X    char const *date, *author, *state;
  1954. X    struct hshentries **store;
  1955. X/* Function: given a branchpoint, a revision number, date, author, and state,
  1956. X * genbranch finds the deltas necessary to reconstruct the given revision
  1957. X * from the branch point on.
  1958. X * Pointers to the found deltas are stored in a list beginning with store.
  1959. X * revno must be on a side branch.
  1960. X * return nil on error
  1961. X */
  1962. X{
  1963. X    unsigned field;
  1964. X        register struct hshentry * next, * trail;
  1965. X    register struct branchhead const *bhead;
  1966. X        int result;
  1967. X    struct buf t;
  1968. X    char datebuf[datesize];
  1969. X
  1970. X    field = 3;
  1971. X        bhead = bpoint->branches;
  1972. X
  1973. X    do {
  1974. X        if (!bhead) {
  1975. X            bufautobegin(&t);
  1976. X            error("no side branches present for %s", partialno(&t,revno,field-1));
  1977. X            bufautoend(&t);
  1978. X            return nil;
  1979. X        }
  1980. X
  1981. X                /*find branch head*/
  1982. X                /*branches are arranged in increasing order*/
  1983. X        while (0 < (result=cmpnumfld(revno,bhead->hsh->num,field))) {
  1984. X                        bhead = bhead->nextbranch;
  1985. X            if (!bhead) {
  1986. X                bufautobegin(&t);
  1987. X                error("branch number %s too high",partialno(&t,revno,field));
  1988. X                bufautoend(&t);
  1989. X                return nil;
  1990. X            }
  1991. X                }
  1992. X
  1993. X        if (result<0) {
  1994. X            absent(revno, field);
  1995. X            return nil;
  1996. X        }
  1997. X
  1998. X                next = bhead->hsh;
  1999. X                if (length==field) {
  2000. X                        /* pick latest one on that branch */
  2001. X                        trail=nil;
  2002. X                        do { if ((date==nil?1:(cmpnum(date,next->date)>=0)) &&
  2003. X                                 (author==nil?1:(strcmp(author,next->author)==0)) &&
  2004. X                                 (state ==nil?1:(strcmp(state, next->state) ==0))
  2005. X                             ) trail = next;
  2006. X                             next=next->next;
  2007. X                        } while (next!=nil);
  2008. X
  2009. X                        if (trail==nil) {
  2010. X                 cantfindbranch(revno, date, author, state);
  2011. X                             return nil;
  2012. X                        } else { /* print up to last one suitable */
  2013. X                             next = bhead->hsh;
  2014. X                             while (next!=trail) {
  2015. X                  store1(&store, next);
  2016. X                                  next=next->next;
  2017. X                             }
  2018. X                 store1(&store, next);
  2019. X                        }
  2020. X            *store = nil;
  2021. X                        return next;
  2022. X                }
  2023. X
  2024. X                /* length > field */
  2025. X                /* find revision */
  2026. X                /* check low */
  2027. X                if (cmpnumfld(revno,next->num,field+1)<0) {
  2028. X            bufautobegin(&t);
  2029. X            error("revision number %s too low", partialno(&t,revno,field+1));
  2030. X            bufautoend(&t);
  2031. X                        return(nil);
  2032. X                }
  2033. X        do {
  2034. X            store1(&store, next);
  2035. X                        trail = next;
  2036. X                        next = next->next;
  2037. X                } while ((next!=nil) &&
  2038. X                       (cmpnumfld(revno,next->num,field+1) >=0));
  2039. X
  2040. X                if ((length>field+1) &&  /*need exact hit */
  2041. X                    (cmpnumfld(revno,trail->num,field+1) !=0)){
  2042. X            absent(revno, field+1);
  2043. X                        return(nil);
  2044. X                }
  2045. X                if (length == field+1) {
  2046. X                        if ((date!=nil) && (cmpnum(date,trail->date)<0)){
  2047. X                error("Revision %s has date %s.",
  2048. X                    trail->num,
  2049. X                    date2str(trail->date, datebuf)
  2050. X                );
  2051. X                                return nil;
  2052. X                        }
  2053. X                        if ((author!=nil)&&(strcmp(author,trail->author)!=0)) {
  2054. X                                error("Revision %s has author %s.",trail->num,trail->author);
  2055. X                                return nil;
  2056. X                        }
  2057. X                        if ((state!=nil)&&(strcmp(state,trail->state)!=0)) {
  2058. X                                error("Revision %s has state %s.",trail->num,
  2059. X                                       trail->state==nil?"<empty>":trail->state);
  2060. X                                return nil;
  2061. X                        }
  2062. X                }
  2063. X                bhead = trail->branches;
  2064. X
  2065. X    } while ((field+=2) <= length);
  2066. X        * store = nil;
  2067. X        return trail;
  2068. X}
  2069. X
  2070. X
  2071. X    static char const *
  2072. lookupsym(id)
  2073. X    char const *id;
  2074. X/* Function: looks up id in the list of symbolic names starting
  2075. X * with pointer SYMBOLS, and returns a pointer to the corresponding
  2076. X * revision number. Returns nil if not present.
  2077. X */
  2078. X{
  2079. X    register struct assoc const *next;
  2080. X        next = Symbols;
  2081. X        while (next!=nil) {
  2082. X                if (strcmp(id, next->symbol)==0)
  2083. X            return next->num;
  2084. X                else    next=next->nextassoc;
  2085. X        }
  2086. X        return nil;
  2087. X}
  2088. X
  2089. int expandsym(source, target)
  2090. X    char const *source;
  2091. X    struct buf *target;
  2092. X/* Function: Source points to a revision number. Expandsym copies
  2093. X * the number to target, but replaces all symbolic fields in the
  2094. X * source number with their numeric values.
  2095. X * Expand a branch followed by `.' to the latest revision on that branch.
  2096. X * Ignore `.' after a revision.  Remove leading zeros.
  2097. X * returns false on error;
  2098. X */
  2099. X{
  2100. X    return fexpandsym(source, target, (RILE*)0);
  2101. X}
  2102. X
  2103. X    int
  2104. fexpandsym(source, target, fp)
  2105. X    char const *source;
  2106. X    struct buf *target;
  2107. X    RILE *fp;
  2108. X/* Same as expandsym, except if FP is nonzero, it is used to expand KDELIM.  */
  2109. X{
  2110. X    register char const *sp, *bp;
  2111. X    register char *tp;
  2112. X    char const *tlim;
  2113. X        register enum tokens d;
  2114. X    unsigned dots;
  2115. X
  2116. X    sp = source;
  2117. X    bufalloc(target, 1);
  2118. X    tp = target->string;
  2119. X    if (!sp || !*sp) { /*accept nil pointer as a legal value*/
  2120. X                *tp='\0';
  2121. X                return true;
  2122. X        }
  2123. X    if (sp[0] == KDELIM  &&  !sp[1]) {
  2124. X        if (!getoldkeys(fp))
  2125. X            return false;
  2126. X        if (!*prevrev.string) {
  2127. X            error("working file lacks revision number");
  2128. X            return false;
  2129. X        }
  2130. X        bufscpy(target, prevrev.string);
  2131. X        return true;
  2132. X    }
  2133. X    tlim = tp + target->size;
  2134. X    dots = 0;
  2135. X
  2136. X    for (;;) {
  2137. X        switch (ctab[(unsigned char)*sp]) {
  2138. X            case DIGIT:
  2139. X            while (*sp=='0' && isdigit(sp[1]))
  2140. X                                /* skip leading zeroes */
  2141. X                                sp++;
  2142. X            do {
  2143. X                if (tlim <= tp)
  2144. X                    tp = bufenlarge(target, &tlim);
  2145. X            } while (isdigit(*tp++ = *sp++));
  2146. X            --sp;
  2147. X            tp[-1] = '\0';
  2148. X            break;
  2149. X
  2150. X            case LETTER:
  2151. X            case Letter:
  2152. X            {
  2153. X            register char *p = tp;
  2154. X            register size_t s = tp - target->string;
  2155. X            do {
  2156. X                if (tlim <= p)
  2157. X                    p = bufenlarge(target, &tlim);
  2158. X                *p++ = *sp++;
  2159. X            } while ((d=ctab[(unsigned char)*sp])==LETTER ||
  2160. X                  d==Letter || d==DIGIT ||
  2161. X                              (d==IDCHAR));
  2162. X            if (tlim <= p)
  2163. X                p = bufenlarge(target, &tlim);
  2164. X            *p = 0;
  2165. X            tp = target->string + s;
  2166. X            }
  2167. X            bp = lookupsym(tp);
  2168. X                        if (bp==nil) {
  2169. X                error("Symbolic number %s is undefined.", tp);
  2170. X                                return false;
  2171. X                        }
  2172. X            do {
  2173. X                if (tlim <= tp)
  2174. X                    tp = bufenlarge(target, &tlim);
  2175. X            } while ((*tp++ = *bp++));
  2176. X            break;
  2177. X
  2178. X            default:
  2179. X            goto improper;
  2180. X                }
  2181. X        switch (*sp++) {
  2182. X            case '\0': return true;
  2183. X            case '.': break;
  2184. X            default: goto improper;
  2185. X        }
  2186. X        if (!*sp) {
  2187. X            if (dots & 1)
  2188. X                goto improper;
  2189. X            if (!(bp = branchtip(target->string)))
  2190. X                return false;
  2191. X            bufscpy(target, bp);
  2192. X            return true;
  2193. X        }
  2194. X        ++dots;
  2195. X        tp[-1] = '.';
  2196. X        }
  2197. X
  2198. X    improper:
  2199. X    error("improper revision number: %s", source);
  2200. X    return false;
  2201. X}
  2202. X
  2203. X    static char const *
  2204. branchtip(branch)
  2205. X    char const *branch;
  2206. X{
  2207. X    struct hshentry *h;
  2208. X    struct hshentries *hs;
  2209. X
  2210. X    h  =  genrevs(branch, (char*)0, (char*)0, (char*)0, &hs);
  2211. X    return h ? h->num : (char const*)0;
  2212. X}
  2213. X
  2214. X    char const *
  2215. tiprev()
  2216. X{
  2217. X    return Dbranch ? branchtip(Dbranch) : Head ? Head->num : (char const*)0;
  2218. X}
  2219. X
  2220. X
  2221. X
  2222. X#ifdef REVTEST
  2223. X
  2224. char const cmdid[] = "revtest";
  2225. X
  2226. X    int
  2227. main(argc,argv)
  2228. int argc; char * argv[];
  2229. X{
  2230. X    static struct buf numricrevno;
  2231. X    char symrevno[100];       /* used for input of revision numbers */
  2232. X        char author[20];
  2233. X        char state[20];
  2234. X        char date[20];
  2235. X    struct hshentries *gendeltas;
  2236. X        struct hshentry * target;
  2237. X        int i;
  2238. X
  2239. X        if (argc<2) {
  2240. X        aputs("No input file\n",stderr);
  2241. X        exitmain(EXIT_FAILURE);
  2242. X        }
  2243. X    if (!(finptr=Iopen(argv[1], FOPEN_R, (struct stat*)0))) {
  2244. X        faterror("can't open input file %s", argv[1]);
  2245. X        }
  2246. X        Lexinit();
  2247. X        getadmin();
  2248. X
  2249. X        gettree();
  2250. X
  2251. X        getdesc(false);
  2252. X
  2253. X        do {
  2254. X                /* all output goes to stderr, to have diagnostics and       */
  2255. X                /* errors in sequence.                                      */
  2256. X        aputs("\nEnter revision number or <return> or '.': ",stderr);
  2257. X        if (!gets(symrevno)) break;
  2258. X                if (*symrevno == '.') break;
  2259. X        aprintf(stderr,"%s;\n",symrevno);
  2260. X        expandsym(symrevno,&numricrevno);
  2261. X        aprintf(stderr,"expanded number: %s; ",numricrevno.string);
  2262. X        aprintf(stderr,"Date: ");
  2263. X        gets(date); aprintf(stderr,"%s; ",date);
  2264. X        aprintf(stderr,"Author: ");
  2265. X        gets(author); aprintf(stderr,"%s; ",author);
  2266. X        aprintf(stderr,"State: ");
  2267. X        gets(state); aprintf(stderr, "%s;\n", state);
  2268. X        target = genrevs(numricrevno.string, *date?date:(char *)nil, *author?author:(char *)nil,
  2269. X                 *state?state:(char*)nil, &gendeltas);
  2270. X                if (target!=nil) {
  2271. X            while (gendeltas) {
  2272. X                aprintf(stderr,"%s\n",gendeltas->first->num);
  2273. X                gendeltas = gendeltas->next;
  2274. X                        }
  2275. X                }
  2276. X        } while (true);
  2277. X    aprintf(stderr,"done\n");
  2278. X    exitmain(EXIT_SUCCESS);
  2279. X}
  2280. X
  2281. exiting void exiterr() { _exit(EXIT_FAILURE); }
  2282. X
  2283. X#endif
  2284. END_OF_FILE
  2285. if test 21002 -ne `wc -c <'src/rcsrev.c'`; then
  2286.     echo shar: \"'src/rcsrev.c'\" unpacked with wrong size!
  2287. fi
  2288. # end of 'src/rcsrev.c'
  2289. fi
  2290. echo shar: End of archive 5 \(of 11\).
  2291. cp /dev/null ark5isdone
  2292. MISSING=""
  2293. for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
  2294.     if test ! -f ark${I}isdone ; then
  2295.     MISSING="${MISSING} ${I}"
  2296.     fi
  2297. done
  2298. if test "${MISSING}" = "" ; then
  2299.     echo You have unpacked all 11 archives.
  2300.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2301. else
  2302.     echo You still need to unpack the following archives:
  2303.     echo "        " ${MISSING}
  2304. fi
  2305. ##  End of shell archive.
  2306. exit 0
  2307.