home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume24 / rcs / part06 < prev    next >
Text File  |  1991-03-05  |  55KB  |  2,007 lines

  1. Subject:  v24i006:  RCS source control system, Part06/12
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: bc168cce 355493c5 0a2bd2f2 848ef943
  5.  
  6. Submitted-by: Adam Hammer <hammer@cs.purdue.edu>
  7. Posting-number: Volume 24, Issue 6
  8. Archive-name: rcs/part06
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # Contents:  man/rlog.1 src/rcsbase.h src/rcsedit.c
  17. # Wrapped by rsalz@litchi.bbn.com on Thu Feb 21 14:37:00 1991
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. echo If this archive is complete, you will see the following message:
  20. echo '          "shar: End of archive 6 (of 12)."'
  21. if test -f 'man/rlog.1' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'man/rlog.1'\"
  23. else
  24.   echo shar: Extracting \"'man/rlog.1'\" \(5105 characters\)
  25.   sed "s/^X//" >'man/rlog.1' <<'END_OF_FILE'
  26. X.de Id
  27. X.ds Rv \\$3
  28. X.ds Dt \\$4
  29. X..
  30. X.Id $Id: rlog.1,v 5.0 1990/08/22 09:11:00 eggert Exp $
  31. X.ds g \s-1GMT\s0
  32. X.ds r \s-1RCS\s0
  33. X.if n .ds - \%--
  34. X.if t .ds - \(em
  35. X.TH RLOG 1 \*(Dt GNU
  36. X.SH NAME
  37. Xrlog \- print log messages and other information about RCS files
  38. X.SH SYNOPSIS
  39. X.B rlog
  40. X.RI [ " options " ] " file " .\|.\|.
  41. X.SH DESCRIPTION
  42. X.B rlog
  43. Xprints information about \*r files.
  44. XFile names ending in
  45. X.B ,v
  46. Xdenote \*r files; all others denote working files.
  47. XIf a working file is given,
  48. X.B rlog
  49. Xtries to find the corresponding
  50. X\*r file first in an \*r subdirectory and then in the working file's directory,
  51. Xas explained in
  52. X.BR co (1).
  53. X.PP
  54. X.B rlog
  55. Xprints the following information for each
  56. X\*r file: \*r file name, working file name, head (i.e., the number
  57. Xof the latest revision on the trunk), default branch, access list, locks,
  58. Xsymbolic names, suffix, total number of revisions,
  59. Xnumber of revisions selected for printing, and
  60. Xdescriptive text.  This is followed by entries for the selected revisions in
  61. Xreverse chronological order for each branch.  For each revision,
  62. X.B rlog
  63. Xprints revision number, author, date/time, state, number of
  64. Xlines added/deleted (with respect to the previous revision),
  65. Xlocker of the revision (if any), and log message.
  66. XAll times are displayed in \*g.
  67. XWithout options,
  68. X.B rlog
  69. Xprints complete information.
  70. XThe options below restrict this output.
  71. X.nr n \w'\f3\-V\fP\f2n\fP '+1n-1/1n
  72. X.TP \nn
  73. X.B \-L
  74. XIgnore \*r files that have no locks set.
  75. XThis is convenient in combination with
  76. X.BR \-h ,
  77. X.BR \-l ,
  78. Xand
  79. X.BR \-R .
  80. X.TP
  81. X.B \-R
  82. XPrint only the name of the \*r file.
  83. XThis is convenient for translating a
  84. Xworking file name into an \*r file name.
  85. X.TP
  86. X.B \-h
  87. XPrint only the \*r file name, working file name, head,
  88. Xdefault branch, access list, locks,
  89. Xsymbolic names, and suffix.
  90. X.TP
  91. X.B \-t
  92. XPrint the same as
  93. X.BR \-h ,
  94. Xplus the descriptive text.
  95. X.TP
  96. X.B \-b
  97. XPrint information about the revisions on the default branch, normally
  98. Xthe highest branch on the trunk.
  99. X.TP
  100. X.BI \-d "dates"
  101. XPrint information about revisions with a checkin date/time in the ranges given by
  102. Xthe semicolon-separated list of
  103. X.IR dates .
  104. XA range of the form
  105. X.IB d1 < d2
  106. Xor
  107. X.IB d2 > d1
  108. Xselects the revisions that were deposited between
  109. X.I d1
  110. Xand
  111. X.I d2
  112. Xinclusive.
  113. XA range of the form
  114. X.BI < d
  115. Xor
  116. X.IB d >
  117. Xselects
  118. Xall revisions dated
  119. X.I d
  120. Xor earlier.
  121. XA range of the form
  122. X.IB d <
  123. Xor
  124. X.BI > d
  125. Xselects
  126. Xall revisions dated
  127. X.I d
  128. Xor later.
  129. XA range of the form
  130. X.I d
  131. Xselects the single, latest revision dated
  132. X.I d
  133. Xor earlier.
  134. XThe date/time strings
  135. X.IR d ,
  136. X.IR d1 ,
  137. Xand
  138. X.I d2
  139. Xare in the free format explained in
  140. X.BR co (1).
  141. XQuoting is normally necessary, especially for
  142. X.B <
  143. Xand
  144. X.BR > .
  145. XNote that the separator is
  146. Xa semicolon.
  147. X.TP
  148. X.BR \-l [\f2lockers\fP]
  149. XPrint information about locked revisions only.
  150. XIn addition, if the comma-separated list
  151. X.I lockers
  152. Xof login names is given,
  153. Xignore all locks other than those held by the
  154. X.IR lockers .
  155. XFor example,
  156. X.B "rlog\ \-L\ \-R\ \-lwft\ RCS/*,v"
  157. Xprints the name of \*r files locked by the user
  158. X.BR wft .
  159. X.TP
  160. X.BI \-r revisions
  161. Xprints information about revisions given in the comma-separated list
  162. X.I revisions
  163. Xof revisions and ranges.  A range
  164. X.IB rev1 \- rev2
  165. Xmeans revisions
  166. X.I rev1
  167. Xto
  168. X.I rev2
  169. Xon the same branch,
  170. X.BI \- rev
  171. Xmeans revisions from the beginning of the branch up to and including
  172. X.IR rev ,
  173. Xand
  174. X.IB rev \-
  175. Xmeans revisions starting with
  176. X.I rev
  177. Xto the end of the branch containing
  178. X.IR rev .
  179. XAn argument that is a branch means all
  180. Xrevisions on that branch.
  181. XA range of branches means all revisions
  182. Xon the branches in that range.
  183. X.TP
  184. X.BI \-s states
  185. Xprints information about revisions whose state attributes match one of the
  186. Xstates given in the comma-separated list
  187. X.IR states .
  188. X.TP
  189. X.BR \-w [\f2logins\fP]
  190. Xprints information about revisions checked in by users with
  191. Xlogin names appearing in the comma-separated list
  192. X.IR logins .
  193. XIf
  194. X.I logins
  195. Xis omitted, the user's login is assumed.
  196. X.TP
  197. X.BI \-V n
  198. XEmulate \*r version
  199. X.I n
  200. Xwhen generating logs.
  201. XSee
  202. X.BR co (1)
  203. Xfor more.
  204. X.PP
  205. X.B rlog
  206. Xprints the intersection of the revisions selected with
  207. Xthe options
  208. X.BR \-d ,
  209. X.BR \-l ,
  210. X.BR \-s ,
  211. Xand
  212. X.BR \-w ,
  213. Xintersected
  214. Xwith the union of the revisions selected by
  215. X.B \-b
  216. Xand
  217. X.BR \-r .
  218. X.SH EXAMPLES
  219. X.LP
  220. X.nf
  221. X.B "    rlog  \-L  \-R  RCS/*,v"
  222. X.B "    rlog  \-L  \-h  RCS/*,v"
  223. X.B "    rlog  \-L  \-l  RCS/*,v"
  224. X.B "    rlog  RCS/*,v"
  225. X.fi
  226. X.LP
  227. XThe first command prints the names of all \*r files in the subdirectory
  228. X.B RCS
  229. Xthat have locks.  The second command prints the headers of those files,
  230. Xand the third prints the headers plus the log messages of the locked revisions.
  231. XThe last command prints complete information.
  232. X.SH DIAGNOSTICS
  233. XThe exit status is zero if and only if all operations were successful.
  234. X.SH IDENTIFICATION
  235. XAuthor: Walter F. Tichy.
  236. X.br
  237. XRevision Number: \*(Rv; Release Date: \*(Dt.
  238. X.br
  239. XCopyright \(co 1982, 1988, 1989 by Walter F. Tichy.
  240. X.br
  241. XCopyright \(co 1990 by Paul Eggert.
  242. X.SH "SEE ALSO"
  243. Xci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1),
  244. Xrcsfile(5)
  245. X.br
  246. XWalter F. Tichy,
  247. X\*r\*-A System for Version Control,
  248. X.I "Software\*-Practice & Experience"
  249. X.BR 15 ,
  250. X7 (July 1985), 637-654.
  251. END_OF_FILE
  252.   if test 5105 -ne `wc -c <'man/rlog.1'`; then
  253.     echo shar: \"'man/rlog.1'\" unpacked with wrong size!
  254.   fi
  255.   # end of 'man/rlog.1'
  256. fi
  257. if test -f 'src/rcsbase.h' -a "${1}" != "-c" ; then 
  258.   echo shar: Will not clobber existing file \"'src/rcsbase.h'\"
  259. else
  260.   echo shar: Extracting \"'src/rcsbase.h'\" \(23601 characters\)
  261.   sed "s/^X//" >'src/rcsbase.h' <<'END_OF_FILE'
  262. X
  263. X/*
  264. X *                     RCS common definitions and data structures
  265. X */
  266. X#define RCSBASE "$Id: rcsbase.h,v 5.5 1990/12/04 05:18:43 eggert Exp $"
  267. X
  268. X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
  269. X   Copyright 1990 by Paul Eggert
  270. X   Distributed under license by the Free Software Foundation, Inc.
  271. X
  272. XThis file is part of RCS.
  273. X
  274. XRCS is free software; you can redistribute it and/or modify
  275. Xit under the terms of the GNU General Public License as published by
  276. Xthe Free Software Foundation; either version 1, or (at your option)
  277. Xany later version.
  278. X
  279. XRCS is distributed in the hope that it will be useful,
  280. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  281. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  282. XGNU General Public License for more details.
  283. X
  284. XYou should have received a copy of the GNU General Public License
  285. Xalong with RCS; see the file COPYING.  If not, write to
  286. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  287. X
  288. XReport problems and direct all questions to:
  289. X
  290. X    rcs-bugs@cs.purdue.edu
  291. X
  292. X*/
  293. X
  294. X
  295. X
  296. X/*****************************************************************************
  297. X * INSTRUCTIONS:
  298. X * =============
  299. X * See the Makefile for how to define C preprocessor symbols.
  300. X * If you need to change the comment leaders, update the table comtable[]
  301. X * in rcsfnms.c. (This can wait until you know what a comment leader is.)
  302. X *****************************************************************************
  303. X */
  304. X
  305. X
  306. X/* $Log: rcsbase.h,v $
  307. X * Revision 5.5  1990/12/04  05:18:43  eggert
  308. X * Use -I for prompts and -q for diagnostics.
  309. X *
  310. X * Revision 5.4  1990/11/01  05:03:35  eggert
  311. X * Don't assume that builtins are functions; they may be macros.
  312. X * Permit arbitrary data in logs.
  313. X *
  314. X * Revision 5.3  1990/09/26  23:36:58  eggert
  315. X * Port wait() to non-Posix ANSI C hosts.
  316. X *
  317. X * Revision 5.2  1990/09/04  08:02:20  eggert
  318. X * Don't redefine NAME_MAX, PATH_MAX.
  319. X * Improve incomplete line handling.  Standardize yes-or-no procedure.
  320. X *
  321. X * Revision 5.1  1990/08/29  07:13:53  eggert
  322. X * Add -kkvl.  Fix type typos exposed by porting.  Clean old log messages too.
  323. X *
  324. X * Revision 5.0  1990/08/22  08:12:44  eggert
  325. X * Adjust ANSI C / Posix support.  Add -k, -V, setuid.  Don't call access().
  326. X * Remove compile-time limits; use malloc instead.
  327. X * Ansify and Posixate.  Add support for ISO 8859.
  328. X * Remove snoop and v2 support.
  329. X *
  330. X * Revision 4.9  89/05/01  15:17:14  narten
  331. X * botched previous USG fix 
  332. X * 
  333. X * Revision 4.8  89/05/01  14:53:05  narten
  334. X * changed #include <strings.h> -> string.h for USG systems.
  335. X * 
  336. X * Revision 4.7  88/11/08  15:58:45  narten
  337. X * removed defs for functions loaded from libraries
  338. X * 
  339. X * Revision 4.6  88/08/09  19:12:36  eggert
  340. X * Shrink stdio code size; remove lint; permit -Dhshsize=nn.
  341. X * 
  342. X * Revision 4.5  87/12/18  17:06:41  narten
  343. X * made removed BSD ifdef, now uses V4_2BSD
  344. X * 
  345. X * Revision 4.4  87/10/18  10:29:49  narten
  346. X * Updating version numbers
  347. X * Changes relative to 1.1 are actually relative to 4.2
  348. X * 
  349. X * Revision 1.3  87/09/24  14:02:25  narten
  350. X * changes for lint
  351. X * 
  352. X * Revision 1.2  87/03/27  14:22:02  jenkins
  353. X * Port to suns
  354. X * 
  355. X * Revision 4.2  83/12/20  16:04:20  wft
  356. X * merged 3.6.1.1 and 4.1 (SMALLOG, logsize).
  357. X * moved setting of STRICT_LOCKING to Makefile.
  358. X * changed DOLLAR to UNKN (conflict with KDELIM).
  359. X * 
  360. X * Revision 4.1  83/05/04  09:12:41  wft
  361. X * Added markers Id and RCSfile.
  362. X * Added Dbranch for default branches.
  363. X * 
  364. X * Revision 3.6.1.1  83/12/02  21:56:22  wft
  365. X * Increased logsize, added macro SMALLOG.
  366. X * 
  367. X * Revision 3.6  83/01/15  16:43:28  wft
  368. X * 4.2 prerelease
  369. X * 
  370. X * Revision 3.6  83/01/15  16:43:28  wft
  371. X * Replaced dbm.h with BYTESIZ, fixed definition of rindex().
  372. X * Added variants of NCPFN and NCPPN for bsd 4.2, selected by defining V4_2BSD.
  373. X * Added macro DELNUMFORM to have uniform format for printing delta text nodes.
  374. X * Added macro DELETE to mark deleted deltas.
  375. X *
  376. X * Revision 3.5  82/12/10  12:16:56  wft
  377. X * Added two forms of DATEFORM, one using %02d, the other %.2d.
  378. X *
  379. X * Revision 3.4  82/12/04  20:01:25  wft
  380. X * added LOCKER, Locker, and USG (redefinition of rindex).
  381. X *
  382. X * Revision 3.3  82/12/03  12:22:04  wft
  383. X * Added dbm.h, stdio.h, RCSBASE, RCSSEP, RCSSUF, WORKMODE, TMPFILE3,
  384. X * PRINTDATE, PRINTTIME, map, and ctab; removed Suffix. Redefined keyvallength
  385. X * using NCPPN. Changed putc() to abort on write error.
  386. X *
  387. X * Revision 3.2  82/10/18  15:03:52  wft
  388. X * added macro STRICT_LOCKING, removed RCSUMASK.
  389. X * renamed JOINFILE[1,2] to JOINFIL[1,2].
  390. X *
  391. X * Revision 3.1  82/10/11  19:41:17  wft
  392. X * removed NBPW, NBPC, NCPW.
  393. X * added typdef int void to aid compiling
  394. X */
  395. X
  396. X/* GCC */
  397. X#if __GNUC__ && !__STRICT_ANSI__
  398. X#    define exiting volatile
  399. X#else
  400. X#    define exiting
  401. X#endif
  402. X
  403. X
  404. X/* standard include files */
  405. X
  406. X#include "conf.h"
  407. X
  408. X#if !MAKEDEPEND
  409. X
  410. X#include <errno.h>
  411. X#include <signal.h>
  412. X#include <time.h>
  413. X
  414. X
  415. X/* ANSI C library */
  416. X/* These declarations are for the benefit of non-ANSI C hosts.  */
  417. X
  418. X    /* <errno.h> */
  419. X#    ifndef errno
  420. X        extern int errno;
  421. X#    endif
  422. X
  423. X    /* <limits.h> */
  424. X#    ifndef CHAR_BIT
  425. X#        define CHAR_BIT 8
  426. X#    endif
  427. X#    ifndef ULONG_MAX
  428. X#        define ULONG_MAX (-(unsigned long)1)
  429. X#    endif
  430. X
  431. X    /* <signal.h> */
  432. X#    ifndef signal
  433. X        signal_type (*signal P((int,signal_type(*)P((int)))))P((int));
  434. X#    endif
  435. X
  436. X    /* <stdio.h> */
  437. X    /* conf.h declares the troublesome printf family.  */
  438. X#    ifndef L_tmpnam
  439. X#        define L_tmpnam 25 /* sizeof("/usr/tmp/xxxxxxxxxxxxxxx") */
  440. X#    endif
  441. X#    ifndef SEEK_SET
  442. X#        define SEEK_SET 0
  443. X#    endif
  444. X#    ifndef fopen
  445. X        FILE *fopen P((const char*,const char*));
  446. X#    endif
  447. X#    ifndef fread
  448. X        fread_type fread P((void*,size_t,size_t,FILE*));
  449. X#    endif
  450. X#    ifndef fwrite
  451. X        fread_type fwrite P((const void*,size_t,size_t,FILE*));
  452. X#    endif
  453. X#    ifndef fclose
  454. X        int fclose P((FILE*));
  455. X#    endif
  456. X#    ifndef fflush
  457. X        int fflush P((FILE*));
  458. X#    endif
  459. X#    ifndef fputs
  460. X        int fputs P((const char*,FILE*));
  461. X#    endif
  462. X#    ifndef fseek
  463. X        int fseek P((FILE*,long,int));
  464. X#    endif
  465. X#    ifndef perror
  466. X        void perror P((const char*));
  467. X#    endif
  468. X#    ifndef clearerr
  469. X        void clearerr P((FILE*));
  470. X#    endif
  471. X#    ifndef feof
  472. X        int feof P((FILE*));
  473. X#    endif
  474. X#    ifndef ferror
  475. X        int ferror P((FILE*));
  476. X#    endif
  477. X#    if has_rename && !defined(rename)
  478. X        int rename P((const char*,const char*));
  479. X#    endif
  480. X#    if has_tmpnam && !defined(tmpnam)
  481. X        char *tmpnam P((char*));
  482. X#    endif
  483. X
  484. X    /* <stdlib.h> */
  485. X#    ifndef EXIT_FAILURE
  486. X#        define EXIT_FAILURE 1
  487. X#    endif
  488. X#    ifndef EXIT_SUCCESS
  489. X#        define EXIT_SUCCESS 0
  490. X#    endif
  491. X#    ifndef getenv
  492. X        char *getenv P((const char*));
  493. X#    endif
  494. X#    ifndef exit
  495. X        exiting exit_type exit P((int));
  496. X#    endif
  497. X#    ifndef _exit
  498. X        exiting underscore_exit_type _exit P((int));
  499. X#    endif
  500. X#    ifndef free
  501. X        free_type free P((malloc_type));
  502. X#    endif
  503. X#    ifndef atoi
  504. X        int atoi P((const char*));
  505. X#    endif
  506. X#    ifndef malloc
  507. X        malloc_type malloc P((size_t));
  508. X#    endif
  509. X#    ifndef realloc
  510. X        malloc_type realloc P((malloc_type,size_t));
  511. X#    endif
  512. X
  513. X    /* <string.h> */
  514. X#    ifndef strcat
  515. X        char *strcat P((char*,const char*));
  516. X#    endif
  517. X#    ifndef strcpy
  518. X        char *strcpy P((char*,const char*));
  519. X#    endif
  520. X#    ifndef strncpy
  521. X        char *strncpy P((char*,const char*,int));
  522. X#    endif
  523. X#    ifndef strrchr
  524. X        char *strrchr P((const char*,int));
  525. X#    endif
  526. X#    ifndef strcmp
  527. X        int strcmp P((const char*,const char*));
  528. X#    endif
  529. X#    ifndef strncmp
  530. X        int strncmp P((const char*,const char*,int));
  531. X#    endif
  532. X#    ifndef strlen
  533. X        strlen_type strlen P((const char*));
  534. X#    endif
  535. X
  536. X    /* <time.h> */
  537. X#    ifndef time
  538. X        time_t time P((time_t*));
  539. X#    endif
  540. X
  541. X
  542. X/* Posix 1003.1-1988 */
  543. X/* These declarations are for the benefit of non-Posix hosts.  */
  544. X
  545. X    /* <limits.h> */
  546. X#    if !defined(NAME_MAX) && !defined(_POSIX_NAME_MAX)
  547. X#        if has_sys_dir_h
  548. X#            include <sys/dir.h>
  549. X#        endif
  550. X#        ifndef NAME_MAX
  551. X#            ifndef MAXNAMLEN
  552. X#                define MAXNAMLEN 14
  553. X#            endif
  554. X#            define NAME_MAX MAXNAMLEN
  555. X#        endif
  556. X#    endif
  557. X#    if !defined(PATH_MAX) && !defined(_POSIX_PATH_MAX)
  558. X#        if has_sys_param_h
  559. X#            include <sys/param.h>
  560. X#        endif
  561. X#        ifndef PATH_MAX
  562. X#            ifndef MAXPATHLEN
  563. X#                define MAXPATHLEN 256
  564. X#            endif
  565. X#            define PATH_MAX (MAXPATHLEN-1)
  566. X#        endif
  567. X#    endif
  568. X
  569. X    /* <sys/wait.h> */
  570. X#    if has_sys_wait_h
  571. X#        include <sys/wait.h>
  572. X#    endif
  573. X#    ifndef WEXITSTATUS
  574. X#        define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
  575. X#        undef WIFEXITED /* Avoid 4.3BSD incompatibility with Posix.  */
  576. X#    endif
  577. X#    ifndef WIFEXITED
  578. X#        define WIFEXITED(stat_val) (!((stat_val) & 255))
  579. X#    endif
  580. X
  581. X    /* <fcntl.h> */
  582. X    /* conf.h declares fcntl() and open().  */
  583. X#    ifdef F_DUPD
  584. X#        undef dup2
  585. X#        define dup2(a,b) fcntl(a,F_DUPFD,b)
  586. X#    else
  587. X#        ifndef dup2
  588. X            int dup2 P((int,int));
  589. X#        endif
  590. X#    endif
  591. X#    ifdef O_CREAT
  592. X#        define open_can_creat 1
  593. X#        undef creat
  594. X#        define creat(path,mode) open(path,O_CREAT|O_TRUNC|O_WRONLY,mode)
  595. X#    else
  596. X#        define open_can_creat 0
  597. X#        define O_RDONLY 0
  598. X#        define O_WRONLY 1
  599. X#        define O_CREAT 01000
  600. X#        define O_TRUNC 02000
  601. X#        ifndef creat
  602. X            int creat P((const char*,mode_t));
  603. X#        endif
  604. X#    endif
  605. X
  606. X    /* <stdio.h> */
  607. X#    ifndef fdopen
  608. X        FILE *fdopen P((int,const char*));
  609. X#    endif
  610. X
  611. X    /* <sys/stat.h> */
  612. X    /* conf.h declares chmod() and umask().  */
  613. X#    ifndef S_IRUSR
  614. X#        define S_IRUSR 0400
  615. X#        define S_IWUSR 0200
  616. X#        define S_IRGRP 0040
  617. X#        define S_IWGRP 0020
  618. X#        define S_IROTH 0004
  619. X#        define S_IWOTH 0002
  620. X#    endif
  621. X#    ifndef S_ISREG
  622. X#        define S_ISREG(n) (((n) & S_IFMT) == S_IFREG)
  623. X#    endif
  624. X#    ifndef fstat
  625. X        int fstat P((int,struct stat*));
  626. X#    endif
  627. X#    ifndef stat
  628. X        int stat P((const char*,struct stat*));
  629. X#    endif
  630. X
  631. X    /* <unistd.h> */
  632. X#    ifndef STDIN_FILENO
  633. X#        define STDIN_FILENO 0
  634. X#        define STDOUT_FILENO 1
  635. X#        define STDERR_FILENO 2
  636. X#    endif
  637. X#    ifndef getlogin
  638. X        char *getlogin P((void));
  639. X#    endif
  640. X#    ifndef _exit
  641. X        exiting void _exit P((int));
  642. X#    endif
  643. X#    ifndef close
  644. X        int close P((int));
  645. X#    endif
  646. X#    ifndef execv
  647. X        int execv P((const char*,const char*const*));
  648. X#    endif
  649. X#    ifndef execvp
  650. X        int execvp P((const char*,const char*const*));
  651. X#    endif
  652. X#    ifndef isatty
  653. X        int isatty P((int));
  654. X#    endif
  655. X#    ifndef read
  656. X        int read P((int,char*,unsigned));
  657. X#    endif
  658. X#    ifndef write
  659. X        int write P((int,const char*,unsigned));
  660. X#    endif
  661. X#    ifndef unlink
  662. X        int unlink P((const char*));
  663. X#    endif
  664. X#    if has_getuid
  665. X#        ifndef getgid
  666. X            gid_t getgid P((void));
  667. X#        endif
  668. X#        ifndef getuid
  669. X            uid_t getuid P((void));
  670. X#        endif
  671. X#    endif
  672. X#    if has_seteuid
  673. X#        ifndef setegid
  674. X            int setegid P((gid_t));
  675. X#        endif
  676. X#        ifndef seteuid
  677. X            int seteuid P((uid_t));
  678. X#        endif
  679. X#        ifndef getegid
  680. X            gid_t getegid P((void));
  681. X#        endif
  682. X#        ifndef geteuid
  683. X            uid_t geteuid P((void));
  684. X#        endif
  685. X#    endif
  686. X#    if has_vfork
  687. X#        ifndef vfork
  688. X            pid_t vfork P((void));
  689. X#        endif
  690. X#    else
  691. X#        define vfork fork
  692. X#        ifndef fork
  693. X            pid_t fork P((void));
  694. X#        endif
  695. X#    endif
  696. X#    if has_getcwd && !defined(getcwd)
  697. X        char *getcwd P((char*,size_t));
  698. X#    endif
  699. X
  700. X
  701. X/* traditional Unix library */
  702. X#define EXIT_TROUBLE 2 /* code returned by diff(1) if trouble is found */
  703. X#if !has_getcwd && !defined(getwd)
  704. X    char *getwd P((char*));
  705. X#endif
  706. X#if !has_tmpnam && !defined(mktemp)
  707. X    char *mktemp P((char*));
  708. X#endif
  709. X#if !has_sigaction & has_sigblock
  710. X#    ifndef sigblock
  711. X        int sigblock P((int));
  712. X#    endif
  713. X#    ifndef sigsetmask
  714. X        int sigsetmask P((int));
  715. X#    endif
  716. X#endif
  717. X#ifndef _filbuf
  718. X    int _filbuf P((FILE*));
  719. X#endif
  720. X#ifndef _flsbuf
  721. X    int _flsbuf P((int,FILE*));
  722. X#endif
  723. X
  724. X
  725. X#endif /* !MAKEDEPEND */
  726. X
  727. X
  728. X/*
  729. X * Parameters
  730. X */
  731. X
  732. X/* backwards compatibility with old versions of RCS */
  733. X#define VERSION_MIN 3        /* old output RCS format supported */
  734. X#define VERSION_MAX 5        /* newest output RCS format supported */
  735. X#ifndef VERSION_DEFAULT        /* default RCS output format */
  736. X#    define VERSION_DEFAULT VERSION_MAX
  737. X#endif
  738. X#define VERSION(n) ((n) - VERSION_DEFAULT) /* internally, 0 is the default */
  739. X
  740. X#ifndef STRICT_LOCKING
  741. X#define STRICT_LOCKING 1
  742. X#endif
  743. X                  /* 0 sets the default locking to non-strict;  */
  744. X                              /* used in experimental environments.         */
  745. X                              /* 1 sets the default locking to strict;      */
  746. X                              /* used in production environments.           */
  747. X
  748. X#define yearlength       16 /* (good through AD 9,999,999,999,999,999)    */
  749. X#define datesize (yearlength+16) /* size of output of DATEFORM            */
  750. X#define joinlength         20 /* number of joined revisions permitted       */
  751. X#define RCSSUF            'v' /* suffix for RCS files                       */
  752. X#define KDELIM            '$' /* delimiter for keywords                     */
  753. X#define VDELIM            ':' /* separates keywords from values             */
  754. X#define DEFAULTSTATE    "Exp" /* default state of revisions                 */
  755. X
  756. X
  757. X
  758. X#define true     1
  759. X#define false    0
  760. X#define nil      0
  761. X
  762. X
  763. X
  764. X
  765. X/* This version of putc prints a char, but aborts on write error            */
  766. X#if lint
  767. X#    define aputc(c,o) afputc(c,o)
  768. X#    define GETC(i,o,c) afputc(c=getc(i), o)
  769. X#else
  770. X#    define aputc(c,o) do { if (putc(c,o)==EOF) IOerror(); } while(0)
  771. X#    define GETC(i,o,c) do {c=getc(i); if (o) aputc(c,o); } while(0)
  772. X#endif
  773. X/* GETC writes a DEL-character (all ones) on end of file.            */
  774. X
  775. X#define WORKMODE(RCSmode, writable) ((RCSmode)&~(S_IWUSR|S_IWGRP|S_IWOTH) | ((writable)?S_IWUSR:0))
  776. X/* computes mode of working file: same as RCSmode, but write permission     */
  777. X/* determined by writable */
  778. X
  779. X
  780. X/* character classes and token codes */
  781. Xenum tokens {
  782. X/* classes */    DELIM,    DIGIT,    IDCHAR,    NEWLN,    LETTER,    Letter,
  783. X        PERIOD,    SBEGIN,    SPACE,    UNKN,
  784. X/* tokens */    COLON,    EOFILE,    ID,    NUM,    SEMI,    STRING
  785. X};
  786. X
  787. X#define SDELIM  '@'     /* the actual character is needed for string handling*/
  788. X/* SDELIM must be consistent with map[], so that ctab[SDELIM]==SBEGIN.
  789. X * there should be no overlap among SDELIM, KDELIM, and VDELIM
  790. X */
  791. X
  792. X#define isdigit(c) ((unsigned)((c)-'0') <= 9) /* faster than ctab[c]==DIGIT */
  793. X
  794. X
  795. X
  796. X
  797. X
  798. X/***************************************
  799. X * Data structures for the symbol table
  800. X ***************************************/
  801. X
  802. X/* Buffer of arbitrary data */
  803. Xstruct buf {
  804. X    char *string;
  805. X    size_t size;
  806. X};
  807. Xstruct cbuf {
  808. X    const char *string;
  809. X    size_t size;
  810. X};
  811. X
  812. X/* Hash table entry */
  813. Xstruct hshentry {
  814. X    const char      * num;      /* pointer to revision number (ASCIZ) */
  815. X    const char      * date;     /* pointer to date of checkin        */
  816. X    const char      * author;   /* login of person checking in        */
  817. X    const char      * lockedby; /* who locks the revision             */
  818. X    const char      * state;    /* state of revision (Exp by default) */
  819. X    struct cbuf        log;      /* log message requested at checkin   */
  820. X        struct branchhead * branches; /* list of first revisions on branches*/
  821. X    struct cbuf        ig;          /* ignored phrases of revision        */
  822. X        struct hshentry   * next;     /* next revision on same branch       */
  823. X    struct hshentry   * nexthsh;  /* next revision with same hash value */
  824. X    unsigned long        insertlns;/* lines inserted (computed by rlog)  */
  825. X    unsigned long        deletelns;/* lines deleted  (computed by rlog)  */
  826. X    char            selector; /* true if selected, false if deleted */
  827. X};
  828. X
  829. X/* list of hash entries */
  830. Xstruct hshentries {
  831. X    struct hshentries *rest;
  832. X    struct hshentry *first;
  833. X};
  834. X
  835. X/* list element for branch lists */
  836. Xstruct branchhead {
  837. X        struct hshentry   * hsh;
  838. X        struct branchhead * nextbranch;
  839. X};
  840. X
  841. X/* accesslist element */
  842. Xstruct access {
  843. X    const char      * login;
  844. X        struct access     * nextaccess;
  845. X};
  846. X
  847. X/* list element for locks  */
  848. Xstruct lock {
  849. X    const char      * login;
  850. X        struct hshentry   * delta;
  851. X        struct lock       * nextlock;
  852. X};
  853. X
  854. X/* list element for symbolic names */
  855. Xstruct assoc {
  856. X    const char      * symbol;
  857. X    const char      * num;
  858. X        struct assoc      * nextassoc;
  859. X};
  860. X
  861. X
  862. X#define mainArgs (argc,argv) int argc; char **argv;
  863. X
  864. X#if lint
  865. X#    define libId(name,rcsid)
  866. X#    define mainProg(name,cmd,rcsid) int name mainArgs
  867. X#else
  868. X#    define libId(name,rcsid) const char name[] = rcsid;
  869. X#    define mainProg(name,cmd,rcsid) const char copyright[] = "Copyright 1982,1988,1989 by Walter F. Tichy\nPurdue CS\nCopyright 1990 by Paul Eggert", rcsbaseId[] = RCSBASE, cmdid[] = cmd; libId(name,rcsid) int main mainArgs
  870. X#endif
  871. X
  872. X/*
  873. X * Markers for keyword expansion (used in co and ident)
  874. X *    Every byte must have class LETTER or Letter.
  875. X */
  876. X#define AUTHOR          "Author"
  877. X#define DATE            "Date"
  878. X#define HEADER          "Header"
  879. X#define IDH             "Id"
  880. X#define LOCKER          "Locker"
  881. X#define LOG             "Log"
  882. X#define RCSFILE         "RCSfile"
  883. X#define REVISION        "Revision"
  884. X#define SOURCE          "Source"
  885. X#define STATE           "State"
  886. X#define keylength 8 /* max length of any of the above keywords */
  887. X
  888. Xenum markers { Nomatch, Author, Date, Header, Id,
  889. X           Locker, Log, RCSfile, Revision, Source, State };
  890. X    /* This must be in the same order as rcskeys.c's Keyword[] array. */
  891. X
  892. X#define DELNUMFORM      "\n\n%s\n%s\n"
  893. X/* used by putdtext and scanlogtext */
  894. X
  895. X/* main program */
  896. Xextern const char cmdid[];
  897. Xexiting void exiterr P((void));
  898. X
  899. X/* maketime */
  900. Xvoid str2date P((const char*,char[datesize]));
  901. Xvoid time2date P((time_t,char[datesize]));
  902. X
  903. X/* partime */
  904. Xint partime P((const char*,struct tm*,int*));
  905. X
  906. X/* rcsedit */
  907. X#define ciklogsize 23 /* sizeof("checked in with -k by ") */
  908. Xextern FILE *fcopy;
  909. Xextern const char *resultfile;
  910. Xextern const char ciklog[ciklogsize];
  911. Xextern int locker_expansion;
  912. Xextern struct buf dirtfname[];
  913. X#define newRCSfilename (dirtfname[0].string)
  914. XFILE *initeditfiles P((const char*));
  915. XFILE *rcswriteopen P((const char*));
  916. Xconst char *makedirtemp P((const char*,int));
  917. Xint expandline P((FILE*,FILE*,const struct hshentry*,int,FILE*));
  918. Xvoid arewind P((FILE*));
  919. Xvoid copystring P((void));
  920. Xvoid dirtempunlink P((void));
  921. Xvoid editstring P((const struct hshentry*));
  922. Xvoid finishedit P((const struct hshentry*));
  923. Xvoid inittmpeditfiles P((void));
  924. Xvoid keepdirtemp P((const char*));
  925. Xvoid swapeditfiles P((int));
  926. Xvoid xpandstring P((const struct hshentry*));
  927. X
  928. X/* rcsfnms */
  929. X#define bufautobegin(b) ((void) ((b)->size = 0)) /* for auto on block entry */
  930. Xextern char *workfilename;
  931. Xextern const char *RCSfilename;
  932. Xextern int haveworkstat;
  933. Xextern struct stat RCSstat;
  934. Xextern struct stat workstat;
  935. XFILE *rcsreadopen P((const char*));
  936. Xchar *bufenlarge P((struct buf*,const char**));
  937. Xchar *maketemp P((int));
  938. Xconst char *bindex P((const char*,int));
  939. Xconst char *getfullRCSname P((void));
  940. Xconst char *tmp();
  941. Xint getfworkstat P((int));
  942. Xint getworkstat P((void));
  943. Xint pairfilenames P((int,char**,FILE*(*)P((const char*)),int,int));
  944. Xvoid bufalloc P((struct buf*,size_t));
  945. Xvoid bufautoend P((struct buf*));
  946. Xvoid bufrealloc P((struct buf*,size_t));
  947. Xvoid bufscat P((struct buf*,const char*));
  948. Xvoid bufscpy P((struct buf*,const char*));
  949. Xvoid ffclose P((FILE*));
  950. Xvoid tempunlink P((void));
  951. X#if has_rename & !bad_rename
  952. X#    define re_name(x,y) rename(x,y)
  953. X#else
  954. X    int re_name P((const char*,const char*));
  955. X#endif
  956. X
  957. X/* rcsgen */
  958. Xextern int interactiveflag;
  959. Xextern struct cbuf curlogmsg;
  960. Xextern struct buf curlogbuf;
  961. Xconst char *buildrevision P((const struct hshentries*,struct hshentry*,int,int));
  962. Xint getcstdin P((void));
  963. Xint ttystdin P((void));
  964. Xint yesorno P((int,const char*,...));
  965. Xstruct cbuf cleanlogmsg P((char*,size_t));
  966. Xvoid putdesc P((int,const char*));
  967. X
  968. X/* rcskeys */
  969. Xextern const char *const Keyword[];
  970. Xenum markers trymatch P((const char*));
  971. X
  972. X/* rcslex */
  973. Xextern FILE *finptr;
  974. Xextern FILE *foutptr;
  975. Xextern FILE *frewrite;
  976. Xextern const char *NextString;
  977. Xextern enum tokens nexttok;
  978. Xextern int hshenter;
  979. Xextern int nerror;
  980. Xextern int nextc;
  981. Xextern int quietflag;
  982. Xextern unsigned long rcsline;
  983. Xconst char *getid P((void));
  984. Xexiting void efaterror P((const char*));
  985. Xexiting void faterror P((const char*,...));
  986. Xexiting void fatserror P((const char*,...));
  987. Xexiting void IOerror P((void));
  988. Xexiting void unterminatedString P((void));
  989. Xchar *checkid P((char*,int));
  990. Xint getkeyopt P((const char*));
  991. Xint getlex P((enum tokens));
  992. Xstruct cbuf getphrases P((const char*));
  993. Xstruct cbuf savestring P((struct buf*));
  994. Xstruct hshentry *getnum P((void));
  995. Xvoid Lexinit P((void));
  996. Xvoid afputc P((int,FILE*));
  997. Xvoid aprintf P((FILE*,const char*,...));
  998. Xvoid aputs P((const char*,FILE*));
  999. Xvoid checksid P((char*));
  1000. Xvoid diagnose P((const char*,...));
  1001. Xvoid eflush P((void));
  1002. Xvoid error P((const char*,...));
  1003. Xvoid eerror P((const char*));
  1004. Xvoid fvfprintf P((FILE*,const char*,va_list));
  1005. Xvoid getkey P((const char*));
  1006. Xvoid getkeystring P((const char*));
  1007. Xvoid nextlex P((void));
  1008. Xvoid oflush P((void));
  1009. Xvoid printstring P((void));
  1010. Xvoid readstring P((void));
  1011. Xvoid redefined P((int));
  1012. Xvoid warn P((const char*,...));
  1013. Xvoid warnignore P((void));
  1014. X
  1015. X/* rcsmap */
  1016. X#define ctab (&map[1])
  1017. Xextern const enum tokens map[];
  1018. X
  1019. X/* rcsrev */
  1020. Xchar *partialno P((struct buf*,const char*,unsigned));
  1021. Xint cmpnum P((const char*,const char*));
  1022. Xint cmpnumfld P((const char*,const char*,unsigned));
  1023. Xint compartial P((const char*,const char*,unsigned));
  1024. Xint expandsym P((const char*,struct buf*));
  1025. Xstruct hshentry *genrevs P((const char*,const char*,const char*,const char*,struct hshentries**));
  1026. Xunsigned countnumflds P((const char*));
  1027. Xvoid getbranchno P((const char*,struct buf*));
  1028. X
  1029. X/* rcssyn */
  1030. X/* These expand modes must agree with Expand_names[] in rcssyn.c.  */
  1031. X#define KEYVAL_EXPAND 0 /* -kkv `$Keyword: value $' */
  1032. X#define KEYVALLOCK_EXPAND 1 /* -kkvl `$Keyword: value locker $' */
  1033. X#define KEY_EXPAND 2 /* -kk `$Keyword$' */
  1034. X#define VAL_EXPAND 3 /* -kv `value' */
  1035. X#define OLD_EXPAND 4 /* -ko use old string, omitting expansion */
  1036. Xstruct diffcmd {
  1037. X    unsigned long
  1038. X        line1, /* number of first line */
  1039. X        nlines, /* number of lines affected */
  1040. X        adprev, /* previous 'a' line1+1 or 'd' line1 */
  1041. X        dafter; /* sum of previous 'd' line1 and previous 'd' nlines */
  1042. X};
  1043. Xextern const char      * Dbranch;
  1044. Xextern struct access   * AccessList;
  1045. Xextern struct assoc    * Symbols;
  1046. Xextern struct cbuf Comment;
  1047. Xextern struct lock     * Locks;
  1048. Xextern struct hshentry * Head;
  1049. Xextern int         Expand;
  1050. Xextern int               StrictLocks;
  1051. Xextern int               TotalDeltas;
  1052. Xextern const char *const expand_names[];
  1053. Xextern const char Kdesc[];
  1054. Xextern const char Klog[];
  1055. Xextern const char Ktext[];
  1056. Xint getdiffcmd P((FILE*,int,FILE*,struct diffcmd*));
  1057. Xint putdftext P((const char*,struct cbuf,FILE*,FILE*,int));
  1058. Xint putdtext P((const char*,struct cbuf,const char*,FILE*,int));
  1059. Xint str2expmode P((const char*));
  1060. Xvoid getadmin P((void));
  1061. Xvoid getdesc P((int));
  1062. Xvoid gettree P((void));
  1063. Xvoid ignorephrase P((void));
  1064. Xvoid initdiffcmd P((struct diffcmd*));
  1065. Xvoid putadmin P((FILE*));
  1066. Xvoid puttree P((const struct hshentry*,FILE*));
  1067. X
  1068. X/* rcsutil */
  1069. Xextern int RCSversion;
  1070. Xchar *cgetenv P((const char*));
  1071. Xconst char *getcaller P((void));
  1072. Xconst char *fstrsave P((const char*));
  1073. Xconst char *strsave P((const char*));
  1074. Xint addlock P((struct hshentry*));
  1075. Xint addsymbol P((const char*,const char*,int));
  1076. Xint checkaccesslist P((void));
  1077. Xint findlock P((int,struct hshentry**));
  1078. Xint run P((const char*,const char*,...));
  1079. Xint runv P((const char**));
  1080. Xmalloc_type fremember P((malloc_type));
  1081. Xmalloc_type ftestalloc P((size_t));
  1082. Xmalloc_type testalloc P((size_t));
  1083. Xmalloc_type testrealloc P((malloc_type,size_t));
  1084. X#define ftalloc(T) ftnalloc(T,1)
  1085. X#define talloc(T) tnalloc(T,1)
  1086. X#if lint
  1087. X    extern malloc_type lintalloc;
  1088. X#    define ftnalloc(T,n) (lintalloc = ftestalloc(sizeof(T)*(n)), (T*)0)
  1089. X#    define tnalloc(T,n) (lintalloc = testalloc(sizeof(T)*(n)), (T*)0)
  1090. X#    define tfree(p)
  1091. X#else
  1092. X#    define ftnalloc(T,n) ((T*) ftestalloc(sizeof(T)*(n)))
  1093. X#    define tnalloc(T,n) ((T*) testalloc(sizeof(T)*(n)))
  1094. X#    define tfree(p) free((malloc_type)(p))
  1095. X#endif
  1096. Xvoid awrite P((const char*,fread_type,FILE*));
  1097. Xvoid catchints P((void));
  1098. Xvoid fastcopy P((FILE*,FILE*));
  1099. Xvoid ffree P((void));
  1100. Xvoid ffree1 P((const char*));
  1101. Xvoid initid P((void));
  1102. Xvoid ignoreints P((void));
  1103. Xvoid printdate P((FILE*,const char*,const char*));
  1104. Xvoid restoreints P((void));
  1105. Xvoid setRCSversion P((const char*));
  1106. X#define SETID (has_getuid & has_seteuid & DIFF_PATH_HARDWIRED)
  1107. X#if has_getuid
  1108. X    extern uid_t ruid;
  1109. X#    define myself(u) ((u) == ruid)
  1110. X#else
  1111. X#    define myself(u) true
  1112. X#endif
  1113. X#if SETID
  1114. X    void seteid P((void));
  1115. X    void setrid P((void));
  1116. X#else
  1117. X#    define seteid()
  1118. X#    define setrid()
  1119. X#endif
  1120. END_OF_FILE
  1121.   if test 23601 -ne `wc -c <'src/rcsbase.h'`; then
  1122.     echo shar: \"'src/rcsbase.h'\" unpacked with wrong size!
  1123.   fi
  1124.   # end of 'src/rcsbase.h'
  1125. fi
  1126. if test -f 'src/rcsedit.c' -a "${1}" != "-c" ; then 
  1127.   echo shar: Will not clobber existing file \"'src/rcsedit.c'\"
  1128. else
  1129.   echo shar: Extracting \"'src/rcsedit.c'\" \(22247 characters\)
  1130.   sed "s/^X//" >'src/rcsedit.c' <<'END_OF_FILE'
  1131. X/*
  1132. X *                     RCS stream editor
  1133. X */
  1134. X/**********************************************************************************
  1135. X *                       edits the input file according to a
  1136. X *                       script from stdin, generated by diff -n
  1137. X *                       performs keyword expansion
  1138. X **********************************************************************************
  1139. X */
  1140. X
  1141. X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
  1142. X   Copyright 1990 by Paul Eggert
  1143. X   Distributed under license by the Free Software Foundation, Inc.
  1144. X
  1145. XThis file is part of RCS.
  1146. X
  1147. XRCS is free software; you can redistribute it and/or modify
  1148. Xit under the terms of the GNU General Public License as published by
  1149. Xthe Free Software Foundation; either version 1, or (at your option)
  1150. Xany later version.
  1151. X
  1152. XRCS is distributed in the hope that it will be useful,
  1153. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  1154. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1155. XGNU General Public License for more details.
  1156. X
  1157. XYou should have received a copy of the GNU General Public License
  1158. Xalong with RCS; see the file COPYING.  If not, write to
  1159. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  1160. X
  1161. XReport problems and direct all questions to:
  1162. X
  1163. X    rcs-bugs@cs.purdue.edu
  1164. X
  1165. X*/
  1166. X
  1167. X
  1168. X/* $Log: rcsedit.c,v $
  1169. X * Revision 5.5  1990/12/30  05:07:35  eggert
  1170. X * Fix report of busy RCS files when !defined(O_CREAT) | !defined(O_EXCL).
  1171. X *
  1172. X * Revision 5.4  1990/11/01  05:03:40  eggert
  1173. X * Permit arbitrary data in comment leaders.
  1174. X *
  1175. X * Revision 5.3  1990/09/11  02:41:13  eggert
  1176. X * Tune expandline().
  1177. X *
  1178. X * Revision 5.2  1990/09/04  08:02:21  eggert
  1179. X * Count RCS lines better.  Improve incomplete line handling.
  1180. X *
  1181. X * Revision 5.1  1990/08/29  07:13:56  eggert
  1182. X * Add -kkvl.
  1183. X * Fix bug when getting revisions to files ending in incomplete lines.
  1184. X * Fix bug in comment leader expansion.
  1185. X *
  1186. X * Revision 5.0  1990/08/22  08:12:47  eggert
  1187. X * Don't require final newline.
  1188. X * Don't append "checked in with -k by " to logs,
  1189. X * so that checking in a program with -k doesn't change it.
  1190. X * Don't generate trailing white space for empty comment leader.
  1191. X * Remove compile-time limits; use malloc instead.  Add -k, -V.
  1192. X * Permit dates past 1999/12/31.  Make lock and temp files faster and safer.
  1193. X * Ansify and Posixate.  Check diff's output.
  1194. X *
  1195. X * Revision 4.8  89/05/01  15:12:35  narten
  1196. X * changed copyright header to reflect current distribution rules
  1197. X * 
  1198. X * Revision 4.7  88/11/08  13:54:14  narten
  1199. X * misplaced semicolon caused infinite loop
  1200. X * 
  1201. X * Revision 4.6  88/08/09  19:12:45  eggert
  1202. X * Shrink stdio code size; allow cc -R.
  1203. X * 
  1204. X * Revision 4.5  87/12/18  11:38:46  narten
  1205. X * Changes from the 43. version. Don't know the significance of the
  1206. X * first change involving "rewind". Also, additional "lint" cleanup.
  1207. X * (Guy Harris)
  1208. X * 
  1209. X * Revision 4.4  87/10/18  10:32:21  narten
  1210. X * Updating version numbers. Changes relative to version 1.1 actually
  1211. X * relative to 4.1
  1212. X * 
  1213. X * Revision 1.4  87/09/24  13:59:29  narten
  1214. X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  1215. X * warnings)
  1216. X * 
  1217. X * Revision 1.3  87/09/15  16:39:39  shepler
  1218. X * added an initializatin of the variables editline and linecorr
  1219. X * this will be done each time a file is processed.
  1220. X * (there was an obscure bug where if co was used to retrieve multiple files
  1221. X *  it would dump)
  1222. X * fix attributed to  Roy Morris @FileNet Corp ...!felix!roy
  1223. X * 
  1224. X * Revision 1.2  87/03/27  14:22:17  jenkins
  1225. X * Port to suns
  1226. X * 
  1227. X * Revision 4.1  83/05/12  13:10:30  wft
  1228. X * Added new markers Id and RCSfile; added locker to Header and Id.
  1229. X * Overhauled expandline completely() (problem with $01234567890123456789@).
  1230. X * Moved trymatch() and marker table to rcskeys.c.
  1231. X * 
  1232. X * Revision 3.7  83/05/12  13:04:39  wft
  1233. X * Added retry to expandline to resume after failed match which ended in $.
  1234. X * Fixed truncation problem for $19chars followed by@@.
  1235. X * Log no longer expands full path of RCS file.
  1236. X * 
  1237. X * Revision 3.6  83/05/11  16:06:30  wft
  1238. X * added retry to expandline to resume after failed match which ended in $.
  1239. X * Fixed truncation problem for $19chars followed by@@.
  1240. X * 
  1241. X * Revision 3.5  82/12/04  13:20:56  wft
  1242. X * Added expansion of keyword Locker.
  1243. X *
  1244. X * Revision 3.4  82/12/03  12:26:54  wft
  1245. X * Added line number correction in case editing does not start at the
  1246. X * beginning of the file.
  1247. X * Changed keyword expansion to always print a space before closing KDELIM;
  1248. X * Expansion for Header shortened.
  1249. X *
  1250. X * Revision 3.3  82/11/14  14:49:30  wft
  1251. X * removed Suffix from keyword expansion. Replaced fclose with ffclose.
  1252. X * keyreplace() gets log message from delta, not from curlogmsg.
  1253. X * fixed expression overflow in while(c=putc(GETC....
  1254. X * checked nil printing.
  1255. X *
  1256. X * Revision 3.2  82/10/18  21:13:39  wft
  1257. X * I added checks for write errors during the co process, and renamed
  1258. X * expandstring() to xpandstring().
  1259. X *
  1260. X * Revision 3.1  82/10/13  15:52:55  wft
  1261. X * changed type of result of getc() from char to int.
  1262. X * made keyword expansion loop in expandline() portable to machines
  1263. X * without sign-extension.
  1264. X */
  1265. X
  1266. X
  1267. X#include "rcsbase.h"
  1268. X
  1269. XlibId(editId, "$Id: rcsedit.c,v 5.5 1990/12/30 05:07:35 eggert Exp $")
  1270. X
  1271. Xstatic void keyreplace P((enum markers,const struct hshentry*,FILE*));
  1272. X
  1273. X
  1274. XFILE *fcopy;         /* result file descriptor                */
  1275. Xconst char *resultfile;  /* result file name                    */
  1276. Xint locker_expansion;     /* should the locker name be appended to Id val?   */
  1277. Xstatic FILE *fedit;     /* edit   file descriptor                */
  1278. Xstatic const char *editfile;     /* edit file                    */
  1279. Xstatic const char *editdir;  /* edit directory                    */
  1280. Xstatic unsigned long editline; /*fedit line counter; is always #lines+1     */
  1281. Xstatic long linecorr; /* #adds - #deletes in each edit run.            */
  1282. X               /*used to correct editline in case file is not rewound after */
  1283. X               /* applying one delta                                        */
  1284. X
  1285. X#define DIRTEMPNAMES 3
  1286. Xenum maker {notmade, real, effective};
  1287. Xstruct buf dirtfname[DIRTEMPNAMES];        /* unlink these when done */
  1288. Xstatic volatile enum maker dirtfmaker[DIRTEMPNAMES];    /* if these are set */
  1289. X
  1290. X    FILE *
  1291. Xiniteditfiles(dir)
  1292. X    const char *dir;
  1293. X/* Function: Initializes resultfile and editfile with temporary filenames
  1294. X * in directory dir. Opens resultfile for reading and writing, with fcopy
  1295. X * as file descriptor. fedit is set to nil.
  1296. X */
  1297. X{
  1298. X    editline = 0;    /* make sure we start from the beginning*/
  1299. X    linecorr = 0;
  1300. X    editdir = dir;
  1301. X    resultfile = makedirtemp(dir,1);
  1302. X    editfile = nil;
  1303. X        fedit=nil;
  1304. X    errno = 0;
  1305. X    return fcopy = fopen(resultfile,"w+");
  1306. X}
  1307. X
  1308. X    void
  1309. Xinittmpeditfiles()
  1310. X{
  1311. X    if (!initeditfiles(tmp()))
  1312. X        efaterror(resultfile);
  1313. X}
  1314. X
  1315. X
  1316. X    void
  1317. Xarewind(f)
  1318. X    FILE *f;
  1319. X{
  1320. X    if (fseek(f, (long)0, SEEK_SET) == EOF)
  1321. X        IOerror();
  1322. X}
  1323. X
  1324. X    void
  1325. Xswapeditfiles(tostdout)
  1326. X    int tostdout;
  1327. X/* Function: swaps resultfile and editfile, assigns fedit=fcopy,
  1328. X * rewinds fedit for reading, and opens resultfile for reading and
  1329. X * writing, using fcopy. If tostdout, fcopy is set to stdout.
  1330. X */
  1331. X{
  1332. X    const char *tmpptr;
  1333. X        fedit=fcopy;
  1334. X    arewind(fedit);
  1335. X        editline = 1; linecorr=0;
  1336. X        tmpptr=editfile; editfile=resultfile; resultfile=tmpptr;
  1337. X        if (tostdout)
  1338. X                fcopy=stdout;
  1339. X    else {
  1340. X        if (!resultfile)
  1341. X        resultfile = makedirtemp(editdir,2);
  1342. X        errno = 0;
  1343. X        if (!(fcopy = fopen(resultfile,"w+")))
  1344. X        efaterror(resultfile);
  1345. X        }
  1346. X}
  1347. X
  1348. X
  1349. X    void
  1350. Xfinishedit(delta)
  1351. X    const struct hshentry *delta;
  1352. X/* copy the rest of the edit file and close it (if it exists).
  1353. X * if delta!=nil, perform keyword substitution at the same time.
  1354. X */
  1355. X{
  1356. X    register FILE *fe, *fc;
  1357. X
  1358. X    fe = fedit;
  1359. X    if (fe) {
  1360. X        fc = fcopy;
  1361. X                if (delta!=nil) {
  1362. X            while (0 < expandline(fe,fc,delta,false,(FILE*)NULL))
  1363. X                ;
  1364. X                } else {
  1365. X            fastcopy(fe,fc);
  1366. X                }
  1367. X        ffclose(fe);
  1368. X        }
  1369. X}
  1370. X
  1371. X
  1372. X
  1373. X    static exiting void
  1374. XeditEndsPrematurely()
  1375. X{
  1376. X    fatserror("edit script ends prematurely");
  1377. X}
  1378. X
  1379. X    static exiting void
  1380. XeditLineNumberOverflow()
  1381. X{
  1382. X    fatserror("edit script refers to line past end of file");
  1383. X}
  1384. X
  1385. X
  1386. X    static void
  1387. Xcopylines(upto,delta)
  1388. X    register unsigned long upto;
  1389. X    const struct hshentry *delta;
  1390. X/* Function: copies input lines editline..upto-1 from fedit to fcopy.
  1391. X * If delta != nil, keyword expansion is done simultaneously.
  1392. X * editline is updated. Rewinds a file only if necessary.
  1393. X */
  1394. X{
  1395. X    register int c;
  1396. X    register FILE *fe, *fc;
  1397. X
  1398. X    if (upto < editline) {
  1399. X                /* swap files */
  1400. X                finishedit((struct hshentry *)nil); swapeditfiles(false);
  1401. X                /* assumes edit only during last pass, from the beginning*/
  1402. X        }
  1403. X    fe = fedit;
  1404. X    fc = fcopy;
  1405. X    if (editline < upto)
  1406. X        if (delta)
  1407. X        do {
  1408. X            if (expandline(fe,fc,delta,false,(FILE*)NULL) <= 0)
  1409. X                goto unexpected_EOF;
  1410. X        } while (++editline < upto);
  1411. X        else
  1412. X        do {
  1413. X            do {
  1414. X                c = getc(fe);
  1415. X                if (c == EOF)
  1416. X                    goto unexpected_EOF;
  1417. X                aputc(c, fc);
  1418. X            } while (c != '\n');
  1419. X        } while (++editline < upto);
  1420. X    return;
  1421. X
  1422. X    unexpected_EOF:
  1423. X    editLineNumberOverflow();
  1424. X}
  1425. X
  1426. X
  1427. X
  1428. X    void
  1429. Xxpandstring(delta)
  1430. X    const struct hshentry *delta;
  1431. X/* Function: Reads a string terminated by SDELIM from finptr and writes it
  1432. X * to fcopy. Double SDELIM is replaced with single SDELIM.
  1433. X * Keyword expansion is performed with data from delta.
  1434. X * If foutptr is nonnull, the string is also copied unchanged to foutptr.
  1435. X */
  1436. X{
  1437. X    while (0 < expandline(finptr,fcopy,delta,true,foutptr))
  1438. X        ;
  1439. X}
  1440. X
  1441. X
  1442. X    void
  1443. Xcopystring()
  1444. X/* Function: copies a string terminated with a single SDELIM from finptr to
  1445. X * fcopy, replacing all double SDELIM with a single SDELIM.
  1446. X * If foutptr is nonnull, the string also copied unchanged to foutptr.
  1447. X * editline is set to (number of lines copied)+1.
  1448. X * Assumption: next character read is first string character.
  1449. X */
  1450. X{    register c;
  1451. X    register FILE *fin, *frew, *fcop;
  1452. X    register int amidline;
  1453. X
  1454. X    fin=finptr; frew=foutptr; fcop=fcopy;
  1455. X        editline=1;
  1456. X    amidline = false;
  1457. X    for (;;) {
  1458. X        GETC(fin,frew,c);
  1459. X        switch (c) {
  1460. X            case EOF:
  1461. X            unterminatedString();
  1462. X            /*NOTREACHED*/
  1463. X            case '\n':
  1464. X            ++editline;
  1465. X            ++rcsline;
  1466. X            amidline = false;
  1467. X            break;
  1468. X            case SDELIM:
  1469. X            GETC(fin,frew,c);
  1470. X            if (c != SDELIM) {
  1471. X                /* end of string */
  1472. X                nextc = c;
  1473. X                editline += amidline;
  1474. X                return;
  1475. X            }
  1476. X            /* fall into */
  1477. X            default:
  1478. X            amidline = true;
  1479. X            break;
  1480. X                }
  1481. X        aputc(c,fcop);
  1482. X        }
  1483. X}
  1484. X
  1485. X
  1486. X
  1487. X
  1488. X    void
  1489. Xeditstring(delta)
  1490. X    const struct hshentry *delta;
  1491. X/* Function: reads an edit script from finptr and applies it to
  1492. X * file fedit; the result is written to fcopy.
  1493. X * If delta!=nil, keyword expansion is performed simultaneously.
  1494. X * If foutptr is set, the edit script is also copied verbatim to foutptr.
  1495. X * Assumes that all these files are open.
  1496. X * If running out of lines in fedit, fedit and fcopy are swapped.
  1497. X * resultfile and editfile are the names of the files that go with fcopy
  1498. X * and fedit, respectively.
  1499. X * Assumes the next input character from finptr is the first character of
  1500. X * the edit script. Resets nextc on exit.
  1501. X */
  1502. X{
  1503. X        int ed; /* editor command */
  1504. X        register int c;
  1505. X    register FILE *fin, *frew, *f;
  1506. X    register unsigned long i;
  1507. X    unsigned long line_lim;
  1508. X    struct diffcmd dc;
  1509. X
  1510. X        editline += linecorr; linecorr=0; /*correct line number*/
  1511. X    frew = foutptr;
  1512. X    fin = finptr;
  1513. X    line_lim = ULONG_MAX;
  1514. X    initdiffcmd(&dc);
  1515. X    while (0  <=  (ed = getdiffcmd(fin,SDELIM,frew,&dc)))
  1516. X        if (line_lim <= dc.line1)
  1517. X            editLineNumberOverflow();
  1518. X        else if (!ed) {
  1519. X            copylines(dc.line1, delta);
  1520. X                        /* skip over unwanted lines */
  1521. X            i = dc.nlines;
  1522. X            linecorr -= i;
  1523. X            editline += i;
  1524. X            f = fedit;
  1525. X            do {
  1526. X                                /*skip next line*/
  1527. X                while ((c=getc(f))!='\n')
  1528. X                    if (c==EOF) {
  1529. X                        if (i!=1)
  1530. X                        editLineNumberOverflow();
  1531. X                        line_lim = dc.dafter;
  1532. X                        break;
  1533. X                    }
  1534. X            } while (--i);
  1535. X        } else {
  1536. X            copylines(dc.line1+1, delta); /*copy only; no delete*/
  1537. X            i = dc.nlines;
  1538. X            linecorr += i;
  1539. X            f = fcopy;
  1540. X            do {
  1541. X                                /*copy next line from script*/
  1542. X                                if (delta!=nil)
  1543. X                    switch (expandline(fin,f,delta,true,frew)) {
  1544. X                    case 0:
  1545. X                        if (i==1)
  1546. X                        return;
  1547. X                        /* fall into */
  1548. X                    case -1:
  1549. X                        editEndsPrematurely();
  1550. X                    }
  1551. X                                else {
  1552. X                       for (;;) {
  1553. X                        GETC(fin,frew,c);
  1554. X                        if (c == EOF)
  1555. X                        editEndsPrematurely();
  1556. X                        aputc(c, f);
  1557. X                        if (c == '\n')
  1558. X                        break;
  1559. X                        if (c==SDELIM) {
  1560. X                        GETC(fin,frew,c);
  1561. X                        if (c!=SDELIM) {
  1562. X                            if (--i)
  1563. X                            editEndsPrematurely();
  1564. X                            nextc = c;
  1565. X                            return;
  1566. X                        }
  1567. X                       }
  1568. X                       }
  1569. X                       ++rcsline;
  1570. X                }
  1571. X            } while (--i);
  1572. X                }
  1573. X    GETC(fin,frew,c);
  1574. X    nextc = c;
  1575. X}
  1576. X
  1577. X
  1578. X
  1579. X/* The rest is for keyword expansion */
  1580. X
  1581. X
  1582. X
  1583. X    int
  1584. Xexpandline(in, out, delta, delimstuffed, frew)
  1585. X    register FILE *in, *out;
  1586. X    const struct hshentry *delta;
  1587. X    int delimstuffed;
  1588. X    register FILE *frew;
  1589. X/* Function: Reads a line from in and writes it to out.
  1590. X * If DELIMSTUFFED is set, double SDELIM is replaced with single SDELIM.
  1591. X * Keyword expansion is performed with data from delta.
  1592. X * If FREW is set, the line is also copied unchanged to FREW.
  1593. X * DELIMSTUFFED must be set if FREW is set.
  1594. X * Yields -1 if no data is copied, 0 if an incomplete line is copied,
  1595. X * 1 if a complete line is copied.
  1596. X */
  1597. X{
  1598. X    register c;
  1599. X    register char * tp;
  1600. X    register int ds, r;
  1601. X    const char *tlim;
  1602. X    char keystring[keylength+2];
  1603. X    static struct buf keyval;
  1604. X        enum markers matchresult;
  1605. X
  1606. X    ds = delimstuffed;
  1607. X    r = -1;
  1608. X    GETC(in,frew,c);
  1609. X        for (;;) {
  1610. X        switch (c) {
  1611. X            case EOF:
  1612. X                        if(ds) {
  1613. X                unterminatedString();
  1614. X                        }
  1615. X            return r;
  1616. X
  1617. X            case SDELIM:
  1618. X            if (ds) {
  1619. X                GETC(in,frew,c);
  1620. X                if (c != SDELIM) {
  1621. X                                /* end of string */
  1622. X                                nextc=c;
  1623. X                return r;
  1624. X                }
  1625. X            }
  1626. X            /* fall into */
  1627. X            default:
  1628. X            r = 0;
  1629. X            aputc(c,out);
  1630. X            break;
  1631. X
  1632. X            case '\n':
  1633. X            rcsline += ds;
  1634. X            aputc(c,out);
  1635. X            return 1;
  1636. X
  1637. X            case KDELIM:
  1638. X            r = 0;
  1639. X                        /* check for keyword */
  1640. X                        /* first, copy a long enough string into keystring */
  1641. X            tp=keystring;
  1642. X            for (;;) {
  1643. X                GETC(in,frew,c);
  1644. X                if (tp < keystring+keylength)
  1645. X                switch (ctab[c]) {
  1646. X                    case LETTER: case Letter:
  1647. X                    *tp++ = c;
  1648. X                    continue;
  1649. X                    default:
  1650. X                    break;
  1651. X                }
  1652. X                break;
  1653. X                        }
  1654. X            *tp++ = c; *tp = '\0';
  1655. X            matchresult = trymatch(keystring);
  1656. X            if (matchresult==Nomatch) {
  1657. X                tp[-1] = 0;
  1658. X                aprintf(out, "%c%s", KDELIM, keystring);
  1659. X                continue;   /* last c handled properly */
  1660. X            }
  1661. X
  1662. X            /* Now we have a keyword terminated with a K/VDELIM */
  1663. X            if (c==VDELIM) {
  1664. X                  /* try to find closing KDELIM, and replace value */
  1665. X                  bufalloc(&keyval, 1);
  1666. X                  tp = keyval.string;
  1667. X                  tlim = tp + keyval.size;
  1668. X                  for (;;) {
  1669. X                      GETC(in,frew,c);
  1670. X                      if (c==EOF || c=='\n' || c==KDELIM)
  1671. X                    break;
  1672. X                      *tp++ =c;
  1673. X                      if (tlim <= tp)
  1674. X                      tp = bufenlarge(&keyval, &tlim);
  1675. X                      if (c==SDELIM && ds) { /*skip next SDELIM */
  1676. X                        GETC(in,frew,c);
  1677. X                        if (c != SDELIM) {
  1678. X                            /* end of string before closing KDELIM or newline */
  1679. X                            *tp = 0;
  1680. X                            aprintf(out, "%c%s%s", KDELIM, keystring, keyval.string);
  1681. X                            nextc = c;
  1682. X                            return 0;
  1683. X                        }
  1684. X                      }
  1685. X                  }
  1686. X                  if (c!=KDELIM) {
  1687. X                    /* couldn't find closing KDELIM -- give up */
  1688. X                    *tp = 0;
  1689. X                    aprintf(out, "%c%s%s", KDELIM, keystring, keyval.string);
  1690. X                    continue;   /* last c handled properly */
  1691. X                  }
  1692. X            }
  1693. X            /* now put out the new keyword value */
  1694. X            keyreplace(matchresult,delta,out);
  1695. X                }
  1696. X        GETC(in,frew,c);
  1697. X        }
  1698. X}
  1699. X
  1700. X
  1701. Xconst char ciklog[ciklogsize] = "checked in with -k by ";
  1702. X
  1703. X    static void
  1704. Xkeyreplace(marker,delta,out)
  1705. X    enum markers marker;
  1706. X    register const struct hshentry *delta;
  1707. X    register FILE *out;
  1708. X/* function: outputs the keyword value(s) corresponding to marker.
  1709. X * Attributes are derived from delta.
  1710. X */
  1711. X{
  1712. X    register const char *sp, *cp, *date;
  1713. X    register char c;
  1714. X    register size_t cs, cw, ls;
  1715. X    int RCSv;
  1716. X
  1717. X    sp = Keyword[(int)marker];
  1718. X
  1719. X    if (Expand == KEY_EXPAND) {
  1720. X        aprintf(out, "%c%s%c", KDELIM, sp, KDELIM);
  1721. X        return;
  1722. X    }
  1723. X
  1724. X        date= delta->date;
  1725. X    RCSv = RCSversion;
  1726. X
  1727. X    if (Expand == KEYVAL_EXPAND  ||  Expand == KEYVALLOCK_EXPAND)
  1728. X        aprintf(out, "%c%s%c%c", KDELIM, sp, VDELIM,
  1729. X            marker==Log && RCSv<VERSION(5)  ?  '\t'  :  ' '
  1730. X        );
  1731. X
  1732. X        switch (marker) {
  1733. X        case Author:
  1734. X        aputs(delta->author, out);
  1735. X                break;
  1736. X        case Date:
  1737. X        printdate(out, date, " ");
  1738. X                break;
  1739. X        case Id:
  1740. X    case Header:
  1741. X        aprintf(out, "%s %s ",
  1742. X              marker==Id || RCSv<VERSION(4)
  1743. X            ? bindex(RCSfilename,SLASH)
  1744. X            : getfullRCSname(),
  1745. X            delta->num
  1746. X        );
  1747. X        printdate(out, date, " ");
  1748. X        aprintf(out, " %s %s",
  1749. X            delta->author,
  1750. X              RCSv==VERSION(3) && delta->lockedby ? "Locked"
  1751. X            : delta->state
  1752. X        );
  1753. X        if (delta->lockedby!=nil)
  1754. X            if (VERSION(5) <= RCSv) {
  1755. X            if (locker_expansion || Expand==KEYVALLOCK_EXPAND)
  1756. X                aprintf(out, " %s", delta->lockedby);
  1757. X            } else if (RCSv == VERSION(4))
  1758. X            aprintf(out, " Locker: %s", delta->lockedby);
  1759. X                break;
  1760. X        case Locker:
  1761. X        if (delta->lockedby)
  1762. X            if (
  1763. X                locker_expansion
  1764. X            ||    Expand == KEYVALLOCK_EXPAND
  1765. X            ||    RCSv <= VERSION(4)
  1766. X            )
  1767. X            aputs(delta->lockedby, out);
  1768. X                break;
  1769. X        case Log:
  1770. X        case RCSfile:
  1771. X        aputs(bindex(RCSfilename,SLASH), out);
  1772. X                break;
  1773. X        case Revision:
  1774. X        aputs(delta->num, out);
  1775. X                break;
  1776. X        case Source:
  1777. X        aputs(getfullRCSname(), out);
  1778. X                break;
  1779. X        case State:
  1780. X        aputs(delta->state, out);
  1781. X                break;
  1782. X    default:
  1783. X        break;
  1784. X        }
  1785. X    if (Expand == KEYVAL_EXPAND  ||  Expand == KEYVALLOCK_EXPAND) {
  1786. X        afputc(' ', out);
  1787. X        afputc(KDELIM, out);
  1788. X    }
  1789. X    if (marker == Log) {
  1790. X        sp = delta->log.string;
  1791. X        ls = delta->log.size;
  1792. X        if (sizeof(ciklog)-1<=ls && !strncmp(sp,ciklog,sizeof(ciklog)-1))
  1793. X            return;
  1794. X        afputc('\n', out);
  1795. X        cp = Comment.string;
  1796. X        cw = cs = Comment.size;
  1797. X        awrite(cp, cs, out);
  1798. X        aprintf(out, "Revision %s  ", delta->num);
  1799. X        printdate(out, date, "  ");
  1800. X        aprintf(out, "  %s", delta->author);
  1801. X        /* Do not include state: it may change and is not updated.  */
  1802. X        /* Comment is the comment leader.  */
  1803. X        if (VERSION(5) <= RCSv)
  1804. X            for (;  cw && (cp[cw-1]==' ' || cp[cw-1]=='\t');  --cw)
  1805. X            ;
  1806. X        for (;;) {
  1807. X            afputc('\n', out);
  1808. X            awrite(cp, cw, out);
  1809. X            if (!ls)
  1810. X            break;
  1811. X            --ls;
  1812. X            c = *sp++;
  1813. X            if (c != '\n') {
  1814. X            awrite(cp+cw, cs-cw, out);
  1815. X            do {
  1816. X                afputc(c,out);
  1817. X                if (!ls)
  1818. X                break;
  1819. X                --ls;
  1820. X                c = *sp++;
  1821. X            } while (c != '\n');
  1822. X            }
  1823. X        }
  1824. X    }
  1825. X}
  1826. X
  1827. X
  1828. X    FILE *
  1829. Xrcswriteopen(RCSname)
  1830. X    const char *RCSname;
  1831. X/*
  1832. X * Create the lock file corresponding to RCSNAME.
  1833. X * Then try to open RCSNAME for reading and yield its FILE* descriptor.
  1834. X * If all goes well, discard any previously acquired locks,
  1835. X * and set frewrite to the FILE* descriptor of the lock file,
  1836. X * which will eventually turn into the new RCS file.
  1837. X */
  1838. X{
  1839. X    register char *tp;
  1840. X    register const char *sp, *lp;
  1841. X    FILE *f;
  1842. X    int fdesc, r;
  1843. X    struct buf *dirt;
  1844. X
  1845. X    sp = RCSname;
  1846. X    dirt = &dirtfname[frewrite != NULL];
  1847. X    bufalloc(dirt, strlen(sp)+1);
  1848. X    tp = dirt->string;
  1849. X    if ((lp = strrchr(sp,SLASH)))
  1850. X        while (sp<=lp)
  1851. X            *tp++ = *sp++;
  1852. X    *tp++ = RCSSEP ? RCSSEP : RCSSUF;
  1853. X#if RCSSEP
  1854. X    /* Insert `,' and append file name.  */
  1855. X    lp = strrchr(sp, RCSSEP);
  1856. X#else
  1857. X    /* The file system doesn't allow `,'; use `v' as a poor substitute.  */
  1858. X    lp = sp + strlen(sp) - 2;
  1859. X#endif
  1860. X    while (sp<=lp)
  1861. X        *tp++ = *sp++;
  1862. X    *tp = '\0'; /* same length as RCSname */
  1863. X    tp = dirt->string;
  1864. X
  1865. X    f = NULL;
  1866. X
  1867. X    seteid();
  1868. X    ignoreints();
  1869. X#    if !open_can_creat
  1870. X#        define create(f,m) creat(f, m)
  1871. X#    else
  1872. X#        define create(f,m) open(f, O_CREAT|O_WRONLY|o_excltrunc, m)
  1873. X#        ifdef O_EXCL
  1874. X#            define o_excltrunc O_EXCL
  1875. X#        else
  1876. X#            define o_excltrunc O_TRUNC
  1877. X#        endif
  1878. X#    endif
  1879. X    if (0 <= (fdesc = create(tp, S_IRUSR|S_IRGRP|S_IROTH))) {
  1880. X        dirtfmaker[0] = effective;
  1881. X        errno = 0;
  1882. X        f = fopen(RCSname,"r");
  1883. X        if (frewrite)
  1884. X            /* We already have a lock somewhere else.  */
  1885. X            if (f) {
  1886. X            /* Discard the first acquired lock.  */
  1887. X            ffclose(frewrite);  frewrite = NULL;
  1888. X            if (unlink(newRCSfilename) < 0) {
  1889. X                setrid();
  1890. X                efaterror(newRCSfilename);
  1891. X            }
  1892. X            bufscpy(&dirtfname[0], tp);
  1893. X            } else {
  1894. X            /* Prefer the first acquired lock to this one.  */
  1895. X            r = close(fdesc)<0 || unlink(tp)<0;
  1896. X            restoreints();
  1897. X            setrid();
  1898. X            if (r)
  1899. X                efaterror(tp);
  1900. X            return f;
  1901. X            }
  1902. X        if (!(frewrite = fdopen(fdesc,"w"))) {
  1903. X            setrid();
  1904. X            efaterror(newRCSfilename);
  1905. X        }
  1906. X    }
  1907. X#if !open_can_creat | !defined(O_EXCL)
  1908. X    else if (errno != ENOENT) {
  1909. X        /* Set errno=EEXIST if the RCS file is busy.  */
  1910. X        struct stat statbuf;
  1911. X        int old_errno = errno;
  1912. X        errno  =  stat(tp,&statbuf)==0 ? EEXIST : old_errno;
  1913. X    }
  1914. X#endif
  1915. X
  1916. X    restoreints();
  1917. X    setrid();
  1918. X    return f;
  1919. X}
  1920. X
  1921. X    void
  1922. Xkeepdirtemp(name)
  1923. X    const char *name;
  1924. X/* Do not unlink name, either because it's not there any more,
  1925. X * or because it has already been unlinked.
  1926. X */
  1927. X{
  1928. X    register int i;
  1929. X    for (i=DIRTEMPNAMES; 0<=--i; )
  1930. X        if (dirtfname[i].string == name) {
  1931. X            dirtfmaker[i] = notmade;
  1932. X            return;
  1933. X        }
  1934. X    faterror("keepdirtemp");
  1935. X}
  1936. X
  1937. X    const char *
  1938. Xmakedirtemp(name, n)
  1939. X    register const char *name;
  1940. X    int n;
  1941. X/*
  1942. X * Have maketemp() do all the work if name==tmp.
  1943. X * Otherwise, create a unique filename in name's dir using n and name
  1944. X * and store it into the dirtfname[n].
  1945. X * Because of storage in tfnames, dirtempunlink() can unlink the file later.
  1946. X * Return a pointer to the filename created.
  1947. X */
  1948. X{
  1949. X    register char *tp;
  1950. X    register const char *lastslash, *np;
  1951. X
  1952. X    if (name == tmp())
  1953. X        return maketemp(n);
  1954. X    bufalloc(&dirtfname[n], strlen(name)+3);
  1955. X    np = tp = dirtfname[n].string;
  1956. X    if ((lastslash = strrchr(name,SLASH)))
  1957. X        while (name<=lastslash)
  1958. X            *tp++ = *name++;
  1959. X    *tp++ = RCSSEP ? RCSSEP : RCSSUF;
  1960. X    *tp++ = 'A'+n;
  1961. X    while ((*tp++ = *name++))
  1962. X        ;
  1963. X    dirtfmaker[n] = real;
  1964. X    return np;
  1965. X}
  1966. X
  1967. X    void
  1968. Xdirtempunlink()
  1969. X/* Clean up makedirtemp() files.  May be invoked by signal handler. */
  1970. X{
  1971. X    register int i;
  1972. X    enum maker m;
  1973. X
  1974. X    for (i = DIRTEMPNAMES;  0 <= --i;  )
  1975. X        if ((m = dirtfmaker[i]) != notmade) {
  1976. X        if (m == effective)
  1977. X            seteid();
  1978. X        VOID unlink(dirtfname[i].string);
  1979. X        if (m == effective)
  1980. X            setrid();
  1981. X        dirtfmaker[i] = notmade;
  1982. X        }
  1983. X}
  1984. END_OF_FILE
  1985.   if test 22247 -ne `wc -c <'src/rcsedit.c'`; then
  1986.     echo shar: \"'src/rcsedit.c'\" unpacked with wrong size!
  1987.   fi
  1988.   # end of 'src/rcsedit.c'
  1989. fi
  1990. echo shar: End of archive 6 \(of 12\).
  1991. cp /dev/null ark6isdone
  1992. MISSING=""
  1993. for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
  1994.     if test ! -f ark${I}isdone ; then
  1995.     MISSING="${MISSING} ${I}"
  1996.     fi
  1997. done
  1998. if test "${MISSING}" = "" ; then
  1999.     echo You have unpacked all 12 archives.
  2000.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2001. else
  2002.     echo You still must unpack the following archives:
  2003.     echo "        " ${MISSING}
  2004. fi
  2005. exit 0
  2006. exit 0 # Just in case...
  2007.