[comp.sources.amiga] v89i221: rcs - revision control system, Part06/14

page%swap@Sun.COM (Bob Page) (11/19/89)

Submitted-by: rsbx@cbmvax.commodore.com (Raymond S. Brand)
Posting-number: Volume 89, Issue 221
Archive-name: unix/rcs.06

# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
#	doc/rcs.1l
#	doc/rcsclean.1l
#	doc/rcsdiff.1l
#	doc/rcsfile.5l
#	doc/rcsfreeze.1l
#	doc/rcsintro.1l
#	doc/rcsmerge.1l
#	doc/rlog.1l
#	ked/ked.c,v
#	rcs/readme
#	rcs/rcs.rcsfiles/maketime.c,v
# This is archive 6 of a 14-part kit.
# This archive created: Sun Nov 19 01:12:07 1989
if `test ! -d doc`
then
  mkdir doc
  echo "mkdir doc"
fi
echo "extracting doc/rcs.1l"
sed 's/^X//' << \SHAR_EOF > doc/rcs.1l
X.TH RCS 1L "" "Purdue University"
X.SH NAME
Xrcs \- change RCS file attributes
X.SH SYNOPSIS
X.B rcs
X[ options ]
Xfile ... 
X.SH DESCRIPTION
X.I Rcs
Xcreates new RCS files or changes attributes of existing ones.
XAn RCS file contains multiple revisions of text,
Xan access list, a change log, 
Xdescriptive text,
Xand some control attributes.
XFor \fIrcs\fR to work, the caller's login name must be on the access list,
Xexcept if the access list is empty, the caller is the owner of the file
Xor the superuser, or
Xthe \fB\-i\fR option is present. 
X.PP
XFiles ending in `,v' are RCS files, all others are working files. If
Xa working file is given, \fIrcs\fR tries to find the corresponding
XRCS file first in directory ./RCS and then in the current directory,
Xas explained in
X.IR co (1L).
X.TP 11
X.B \-i
Xcreates and initializes a new RCS file, but does not deposit any revision.
XIf the RCS file has no path prefix, \fIrcs\fR tries to place it
Xfirst into the subdirectory ./RCS, and then into the current directory.
XIf the RCS file
Xalready exists, an error message is printed.
X.TP
X.BI \-a "logins"
Xappends the login names appearing in the comma-separated list \fIlogins\fR
Xto the access list of the RCS file.
X.TP
X.BI \-A "oldfile"
Xappends the access list of \fIoldfile\fR to the access list of the RCS file. 
X.TP
X.BR \-e [\fIlogins\fR]
Xerases the login names appearing in the comma-separated list \fIlogins\fR
Xfrom the access list of the RCS file.
XIf \fIlogins\fR is omitted, the entire access list is erased.
X.TP
X.BR \-b [\fIrev\fR]
Xsets the default branch to \fIrev\fR. If \fIrev\fR is omitted, the default
Xbranch is reset to the (dynamically) highest branch on the trunk.
X.TP
X.BI \-c "string"
Xsets the comment leader to \fIstring\fR. The comment leader
Xis printed before every log message line generated by the keyword 
X$\&Log$  during checkout (see
X.IR co (1L)).
XThis is useful for programming 
Xlanguages without multi-line comments. During \fBrcs -i\fR or initial 
X\fBci\fR, the comment leader is guessed from the suffix of the working file. 
X.TP
X.BR \-l [\fIrev\fR]
Xlocks the revision with number \fIrev\fR.
XIf a branch is given, the latest revision on that branch is locked.
XIf \fIrev\fR is omitted, the latest revision on the default branch is locked.
XLocking prevents overlapping changes.
XA lock is removed with \fBci\fR or \fBrcs -u\fR (see below).
X.TP
X.BR \-u [\fIrev\fR]
Xunlocks the revision with number \fIrev\fR.
XIf a branch is given, the latest revision on that branch is unlocked.
XIf \fIrev\fR is omitted, the latest lock held by the caller is removed.
XNormally, only the locker of a revision may unlock it.
XSomebody else unlocking a revision breaks the lock. 
XThis causes a mail message to be sent to the original locker.
XThe message contains a commentary solicited from the breaker.
XThe commentary is terminated with a line containing a single `.' or
Xcontrol-D.
X.TP
X.B \-L
Xsets locking to \fIstrict\fR. Strict locking means that the owner
Xof an RCS file is not exempt from locking for checkin.
XThis option should be used for files that are shared.
X.TP
X.B \-U
Xsets locking to non-strict. Non-strict locking means that the owner of
Xa file need not lock a revision for checkin. 
XThis option should NOT be used for files that are shared.
XThe default (\fB\-L\fR or \fB\-U\fR) is determined by your system administrator.
X.TP
X.B \-n\fIname\fR[:\fIrev\fR]
Xassociates the symbolic name \fIname\fR with the branch or
Xrevision \fIrev\fR. 
X\fIRcs\fR prints an error message if \fIname\fR is already associated with
Xanother number.
XIf \fIrev\fR is omitted, the symbolic name is deleted.
X.TP
X.B \-N\fIname\fR[:\fIrev\fR]
Xsame as \fB\-n\fR, except that it overrides a previous assignment of 
X\fIname\fR.
X.TP
X.BI \-o "range"
Xdeletes ("outdates") the revisions given by \fIrange\fR.
XA range consisting of a single revision number means that revision.
XA range consisting of a branch number means the latest revision on that
Xbranch.
XA range of the form \fIrev1-rev2\fR means 
Xrevisions \fIrev1\fR to \fIrev2\fR on the same branch, 
X\fI-rev\fR means from the beginning of the branch containing
X\fIrev\fR up to and including \fIrev\fR, and \fIrev-\fR means
Xfrom revision \fIrev\fR to the end of the branch containing \fIrev\fR.
XNone of the outdated revisions may have branches or locks.
X.TP
X.B \-q
Xquiet mode; diagnostics are not printed.
X.TP
X.B \-s\fIstate\fR[:\fIrev\fR]
Xsets the state attribute of the revision \fIrev\fR to \fIstate\fR. 
XIf \fIrev\fR is a branch number, the latest revision on that branch is
Xassumed.
XIf \fIrev\fR is omitted, the latest revision on the default branch is assumed.
XAny identifier is acceptable for \fIstate\fR.
XA useful set of states
Xis \fIExp\fR (for experimental), \fIStab\fR (for stable), and \fIRel\fR (for
Xreleased).
XBy default,
X.IR ci (1L)
Xsets the state of a revision to \fIExp\fR.
X.TP
X.BR \-t [\fItxtfile\fR]
Xwrites descriptive text into the RCS file (deletes the existing text).
XIf \fItxtfile\fR is omitted, 
X\fIrcs\fR prompts the user for text supplied from the standard input,
Xterminated with a line containing a single `.' or control-D.
XOtherwise, the descriptive text is copied from the file \fItxtfile\fR.
XIf the \fB\-i\fR option is present, descriptive text is requested
Xeven if \fB\-t\fR is not given.
XThe prompt is suppressed if the standard input is not a terminal.
X.SH DIAGNOSTICS
XThe RCS file name and the revisions outdated are written to
Xthe diagnostic output.
XThe exit status always refers to the last RCS file operated upon,
Xand is 0 if the operation was successful, 1 otherwise.
X.SH FILES
XThe caller of the command
Xmust have read/write permission for the directory containing
Xthe RCS file and read permission for the RCS file itself.
X.I Rcs
Xcreates a semaphore file in the same directory as the RCS
Xfile to prevent simultaneous update.
XFor changes, \fIrcs\fR always creates a new file. On successful completion,
X\fIrcs\fR deletes the old one and renames the new one.
XThis strategy makes links to RCS files useless.
X.SH IDENTIFICATION
X.de VL
X\\$2
X..
XAuthor: Walter F. Tichy,
XPurdue University, West Lafayette, IN, 47907.
X.sp 0
XRevision Number:
X.VL $Revision: 1.3 $
X; Release Date:
X.VL $Date: 89/05/02 11:14:37 $
X\&.
X.sp 0
XCopyright \(co 1982, 1988, 1989 by Walter F. Tichy.
X.SH SEE ALSO
Xco(1L), ci(1L), ident(1L), rcsdiff(1L), rcsintro(1L), rcsmerge(1L), rlog(1L),
Xrcsfile(5L)
X.sp 0
XWalter F. Tichy, "Design, Implementation, and Evaluation of a Revision Control
XSystem," in \fIProceedings of the 6th International Conference on Software
XEngineering\fR, IEEE, Tokyo, Sept. 1982.
SHAR_EOF
echo "extracting doc/rcsclean.1l"
sed 's/^X//' << \SHAR_EOF > doc/rcsclean.1l
X.TH RCSCLEAN 1L "" "Purdue University"
X.SH NAME
Xrcsclean \- clean up working files
X.SH SYNOPSIS
X\fBrcsclean\fR [ \fB-r\fIrev\fR ] [ \fB-q\fIrev\fR ] file...
X.SH DESCRIPTION
X.I Rcsclean
Xremoves working files that were checked out and never modified.
XFor each file given, \fIrcsclean\fR
Xcompares the working file and a revision in the corresponding
XRCS file. If it finds no difference, it removes the working file, and,
Xif the revision was locked by the caller, unlocks the revision.
X.PP
XA file name ending in ',v' is an RCS file name, otherwise a
Xworking file name. \fIRcsclean\fR derives the working file name from the RCS
Xfile name and vice versa, as explained in
X.IR co (1L).
XPairs consisting
Xof both an RCS and a working file name may also be specified.
X.PP
X\fIRev\fR specifies with which revision the working file is compared.
XIf \fIrev\fR is omitted, \fIrcsclean\fR compares the working file with
Xthe latest revision
Xon the default branch (normally the highest branch on the trunk).
XThe option \fB-q\fR suppresses diagnostics.
X.PP
X\fIRcsclean\fR is useful for "clean" targets in Makefiles.
XNote that
X.IR rcsdiff (1L)
Xprints out the differences.
XAlso,
X.IR ci (1L)
Xnormally asks whether to check in a file
Xif it was not changed.
X.SH EXAMPLES
X.nf
XThe command
X
X	rcsclean *.c *.h
X
X.fi
Xremoves all working files ending in ".c" or ".h" that were not changed
Xsince their checkout.
X.SH DIAGNOSTICS
XThe exit status is 0 if there were no differences
Xduring the last comparison or if the last working file did not exist,
X1 if there were differences, and 2 if there were errors.
X.SH IDENTIFICATION
X.de VL
X\\$2
X..
XAuthor: Walter F. Tichy,
XPurdue University, West Lafayette, IN, 47907.
X.sp 0
XRevision Number:
X.VL $Revision: 1.2 $
X; Release Date:
X.VL $Date: 89/05/02 11:15:26 $
X\&.
X.sp 0
XCopyright \(co 1982, 1988, 1989 by Walter F. Tichy.
X.SH SEE ALSO
Xco(1L), ci(1L), ident(1L), rcs(1L), rcsdiff(1L), rcsintro(1L), rcsmerge(1L),
Xrlog(1L), rcsfile(5L).
SHAR_EOF
echo "extracting doc/rcsdiff.1l"
sed 's/^X//' << \SHAR_EOF > doc/rcsdiff.1l
X.TH RCSDIFF 1L "" "Purdue University"
X.SH NAME
Xrcsdiff \- compare RCS revisions
X.SH SYNOPSIS
X\fBrcsdiff\fR [ \fB\-biwt\fR ] [ \fB\-cefhn\fR ] [ \fB\-q\fR ] [ \fB\-r\fIrev1\fR ] [ \fB\-r\fIrev2\fR ] file ...
X.SH DESCRIPTION
X.I Rcsdiff
Xruns
X.IR diff (1)
Xto compare two revisions of each RCS file given.
XA file name ending in ',v' is an RCS file name, otherwise a
Xworking file name. \fIRcsdiff\fR derives the working file name from the RCS
Xfile name and vice versa, as explained in
X.IR co (1L).
XPairs consisting
Xof both an RCS and a working file name may also be specified.
X.PP
XThe options \fB\-b\fR, \fB\-i\fR, \fB\-w\fR, \fB\-t\fR,
X\fB\-c\fR, \fB\-e\fR, \fB\-f\fR, and \fB\-h\fR,
Xhave the same effect as described in
X.IR diff (1);
Xoption
X\fB\-n\fR generates an edit script of the format used by RCS.
XThe option \fB\-q\fR suppresses diagnostic output.
X.PP
XIf both \fIrev1\fR and \fIrev2\fR
Xare omitted, \fIrcsdiff\fR compares the latest revision on the
Xdefault branch (normally the highest branch on the trunk)
Xwith the contents of the corresponding working file. This is useful
Xfor determining what you changed since the last checkin.
X.PP
XIf \fIrev1\fR is given, but \fIrev2\fR is omitted,
X\fIrcsdiff\fR compares revision \fIrev1\fR of the RCS file with
Xthe contents of the corresponding working file.
X.PP
XIf both \fIrev1\fR and \fIrev2\fR are given,
X\fIrcsdiff\fR compares revisions \fIrev1\fR and \fIrev2\fR of the RCS file.
X.PP
XBoth \fIrev1\fR and \fIrev2\fR may be given numerically or symbolically,
Xand may actually be attached to any of the options.
X.SH EXAMPLES
X.nf
XThe command
X
X.B "        rcsdiff  f.c
X
X.fi
Xruns \fIdiff\fR on the latest revision on the default branch of RCS file f.c,v
Xand the contents of working file f.c.
X.SH DIAGNOSTICS
XThe exit status is 0 if there were no differences during the last comparison,
X1 if there were differences, and 2 if there were errors.
X.SH IDENTIFICATION
X.de VL
X\\$2
X..
XAuthor: Walter F. Tichy,
XPurdue University, West Lafayette, IN, 47907.
X.sp 0
XRevision Number:
X.VL $Revision: 1.3 $
X; Release Date:
X.VL $Date: 89/05/02 11:16:01 $
X\&.
X.sp 0
XCopyright \(co 1982, 1988, 1989 by Walter F. Tichy.
X.SH SEE ALSO
Xci(1L), co(1L), diff(1), ident(1L), rcs(1L), rcsintro(1L), rcsmerge(1L), rlog(1L)
X.br
XWalter F. Tichy, "Design, Implementation, and Evaluation of a Revision Control
XSystem," in \fIProceedings of the 6th International Conference on Software
XEngineering\fR, IEEE, Tokyo, Sept. 1982.
SHAR_EOF
echo "extracting doc/rcsfile.5l"
sed 's/^X//' << \SHAR_EOF > doc/rcsfile.5l
X.TH RCSFILE 5L "" "Purdue University"
X.SH NAME
Xrcsfile \- format of RCS file
X.SH DESCRIPTION
XAn RCS file is an ASCII file. Its contents are described by the grammar
Xbelow. The text is free format, i.e., spaces, tabs and new lines have
Xno significance except in strings. Strings are enclosed by `@'.
XIf a string contains a `@', it must be doubled.
X.PP
XThe meta syntax uses the following conventions: `|' (bar) separates
Xalternatives; `{' and `}' enclose optional phrases; `{' and `}*' enclose
Xphrases that may be repeated zero or more times;
X`{' and '}+' enclose phrases that must appear at least once and may be
Xrepeated;
X`<' and `>' enclose nonterminals.
X.PP
X.ta 1.5i 2.0i 3i
X.fc ~
X.nf
X
X 
X<rcstext>  ~~::=~~<admin> {<delta>}* <desc> {<deltatext>}*
X           
X<admin>    ~~::=~~\fBhead\fR     ~~{<num>};
X           ~~   ~~\fBbranch\fR   ~~{<num>};
X           ~~   ~~\fBaccess\fR   ~~{<id>}*;
X           ~~   ~~\fBsymbols\fR  ~~{<id> : <num>}*;  
X           ~~   ~~\fBlocks\fR    ~~{<id> : <num>}*;
X           ~~   ~~\fBcomment\fR  ~~{<string>};
X           
X<delta>    ~~::=~~<num>
X           ~~   ~~\fBdate\fR     ~~<num>;
X           ~~   ~~\fBauthor\fR   ~~<id>;
X           ~~   ~~\fBstate\fR    ~~{<id>};
X           ~~   ~~\fBbranches\fR ~~{<num>}*;
X           ~~   ~~\fBnext\fR     ~~{<num>};
X           
X<desc>     ~~::=~~\fBdesc\fR     ~~<string>
X
X<deltatext>~~::=~~<num>   
X           ~~   ~~\fBlog\fR      ~~<string>
X           ~~   ~~\fBtext\fR     ~~<string>
X
X
X<num>      ~~::=~~{<digit>{.}}+
X             
X<digit>    ~~::=~~0 | 1 | ... | 9
X             
X<id>       ~~::=~~<letter>{<idchar>}*
X
X<letter>   ~~::=~~A | B | ... | Z | a | b | ... | z
X
X<idchar>   ~~::=~~Any printing ASCII character except space,
X           ~~   ~~tab, carriage return, new line, and <special>.
X
X<special>  ~~::=~~; | : | , | @
X
X<string>   ~~::=~~@{any ASCII character, with `@' doubled}*@
X
X.fi
X.PP
XIdentifiers are case sensitive. Keywords are in lower case only.
XThe sets of keywords and identifiers may overlap.
X.PP
XThe <delta> nodes form a tree. All nodes whose numbers
Xconsist of a single pair
X(e.g., 2.3, 2.1, 1.3, etc.)
Xare on the "trunk", and are linked through the \fBnext\fR
Xfield in order of decreasing numbers. The \fBhead\fR field in the
X<admin> node points to the head of that sequence (i.e., contains
Xthe highest pair). 
XThe \fBbranch\fR node in the admin node indicates the default
Xbranch (or revision) for most RCS operations. If empty, the default
Xbranch is the highest branch on the trunk.
X.PP
XAll <delta> nodes whose numbers consist of 2n fields (n\(>=2)
X(e.g., 3.1.1.1, 2.1.2.2, etc.)
Xare linked as follows. All nodes whose first (2n)-1 number fields are identical
Xare linked through the \fBnext\fR field in order of increasing numbers.
XFor each such sequence, 
Xthe <delta> node whose number is identical to the first 
X2(n-1) number fields of the deltas on that sequence is called the branchpoint.
XThe \fBbranches\fR field of a node contains a list of the
Xnumbers of the first nodes of all sequences for which it is a branchpoint.
XThis list is ordered in increasing numbers.
X.sp 1
X.ne 38
XExample:
X.eo
X.nf
X.vs 12pts
X.cs 1 20
X.if t .in +0.5i
X                           Head
X                             |
X                             |
X                             v
X                         ---------
X   / \          / \      |       |      / \           / \     
X  /   \        /   \     |  2.1  |     /   \         /   \
X /     \      /     \    |       |    /     \      /       \
X/1.2.1.3\    /1.3.1.1\   |       |   /1.2.2.2\   /1.2.2.1.1.1\
X---------    ---------   ---------   ---------   -------------
X    ^            ^           |           ^             ^
X    |            |           |           |             |
X    |            |           v           |             |
X   / \           |       ---------      / \            |
X  /   \          |       \  1.3  /     /   \           |
X /     \         ---------\     /     /     \-----------
X/1.2.1.1\                  \   /     /1.2.2.1\           
X---------                   \ /      --------- 
X    ^                        |           ^     
X    |                        |           |     
X    |                        v           |     
X    |                    ---------       |     
X    |                    \  1.2  /       |     
X    ----------------------\     /---------     
X                           \   /               
X                            \ /                
X                             |                 
X                             |                 
X                             v                 
X                         ---------             
X                         \  1.1  /             
X                          \     /              
X                           \   /               
X                            \ /                
X                                               
X
X.if t .in -0.5i
X.cs 1
X.ec
X.ce
XFig. 1: A revision tree
X.fi
X.PP
X.SH IDENTIFICATION
X.de VL
X\\$2
X..
XAuthor: Walter F. Tichy,
XPurdue University, West Lafayette, IN, 47907.
X.sp 0
XRevision Number:
X.VL $Revision: 1.2 $
X; Release Date:
X.VL $Date: 89/05/02 11:16:56 $
X\&.
X.sp 0
XCopyright \(co 1982, 1988, 1989 by Walter F. Tichy.
X.SH SEE ALSO
Xci(1L), co(1L), ident(1L), rcs(1L), rcsdiff(1L), rcsmerge(1L), rlog(1L),
X.br
XWalter F. Tichy, "Design, Implementation, and Evaluation of a Revision Control
XSystem," in \fIProceedings of the 6th International Conference on Software
XEngineering\fR, IEEE, Tokyo, Sept. 1982.
SHAR_EOF
echo "extracting doc/rcsfreeze.1l"
sed 's/^X//' << \SHAR_EOF > doc/rcsfreeze.1l
X.TH RCSFREEZE 1L "" "Purdue University"
X.SH NAME
Xrcsfreeze \- freeze a configuration of sources checked in under RCS
X.SH SYNOPSIS
X.B rcsfreeze
X[symbolic revision name]
X.SH DESCRIPTION
XThe
X.I rcsfreeze
Xcommand has the purpose of assigning a symbolic revision
Xnumber to a set of RCS files, which form a valid configuration.
X.PP
XThe idea is to run
X.I rcsfreeze
Xeach time a new version is checked
Xin. A unique symbolic revision number (\c
X.BI C_ number,
Xwhere
X.I number
Xis increased each time rcsfreeze is run) is then assigned to the most
Xrecent revision of each RCS file of the main trunk.
X.PP
XIf the command is invoked with an argument, then this
Xargument is used as the symbolic name to freeze a configuration.
XThe unique identifier is still generated
Xand is listed in the log file but it will not appear as
Xpart of the symbolic revision name in the actual RCS files.
X.PP
XA log message is requested from the user which is saved for future
Xreferences.
X.PP
XThe shell script works only on all RCS files at one time.
XIt is important that all changed files are checked in (there are
Xno precautions against any error in this respect). Run
X.IR rcsclean (1L)
Xfirst and see whether any sources remain in the current directory.
X.SH FILES
X.TP 2.5i
X[RCS/]rcsfreeze.version
Xfor the version number
X.TP
X[RCS/]rscfreeze.log
Xfor the log messages, most recent log message first.
X.SH AUTHOR
XStephan v. Bechtolsheim
X.SH "SEE ALSO"
Xrcs(1L), rlog(1L), rcsclean(1L)
X.SH BUGS
XThe program does not check whether there are any sources checked out
Xand modified.
SHAR_EOF
echo "extracting doc/rcsintro.1l"
sed 's/^X//' << \SHAR_EOF > doc/rcsintro.1l
X.TH RCSINTRO 1L "May 11, 1983" "Purdue University"
X.SH NAME
Xrcsintro - introduction to RCS commands
X.SH DESCRIPTION
XThe Revision Control System (RCS) manages multiple revisions of text files.
XRCS automates the storing, retrieval, logging, identification, and merging
Xof revisions. RCS is useful for text that is revised frequently, for example
Xprograms, documentation, graphics, papers, form letters, etc.
X.PP
XThe basic user interface is extremely simple. The novice only needs
Xto learn two commands:
X.IR ci (1L)
Xand
X.IR co (1L).
X\fICi\fR, short for "check in", deposits the contents of a
Xtext file into an archival file called an RCS file. An RCS file
Xcontains all revisions of a particular text file.
X\fICo\fR, short for "check out", retrieves revisions from an RCS file.
X.PP
X.B "Functions of RCS"
X.PP
X.IP \(bu
XStorage and retrieval of multiple revisions of text. RCS saves all old
Xrevisions in a space efficient way.
XChanges no longer destroy the original, because the
Xprevious revisions remain accessible. Revisions can be retrieved according to
Xranges of revision numbers, symbolic names, dates, authors, and
Xstates.
X.IP \(bu
XMaintenance of a complete history of changes. RCS logs all changes automatically.
XBesides the text of each revision, RCS stores the author, the date and time of
Xcheck-in, and a log message summarizing the change.
XThe logging makes it easy to find out
Xwhat happened to a module, without having to compare
Xsource listings or having to track down colleagues.
X.IP \(bu
XResolution of access conflicts. When two or more programmers wish to
Xmodify the same revision, RCS alerts the programmers and prevents one
Xmodification from corrupting the other.
X.IP \(bu
XMaintenance of a tree of Revisions. RCS can maintain separate lines of development
Xfor each module. It stores a tree structure that represents the
Xancestral relationships among revisions.
X.IP \(bu
XMerging of revisions and resolution of conflicts.
XTwo separate lines of development of a module can be coalesced by merging.
XIf the revisions to be merged affect the same sections of code, RCS alerts the
Xuser about the overlapping changes.
X.IP \(bu
XRelease and configuration control. Revisions can be assigned symbolic names
Xand marked as released, stable, experimental, etc.
XWith these facilities, configurations of modules can be
Xdescribed simply and directly.
X.IP \(bu
XAutomatic identification of each revision with name, revision number,
Xcreation time, author, etc.
XThe identification is like a stamp that can be embedded at an appropriate place
Xin the text of a revision.
XThe identification makes it simple to determine which
Xrevisions of which modules make up a given configuration.
X.IP \(bu
XMinimization of secondary storage. RCS needs little extra space for
Xthe revisions (only the differences). If intermediate revisions are
Xdeleted, the corresponding deltas are compressed accordingly.
X.sp
X.PP
X.B "Getting Started with RCS"
X.PP
XSuppose you have a file f.c that you wish to put under control of RCS. 
XInvoke the check-in command
X.PP
X.ti 1.5i
X.B "ci  f.c 
X.PP
XThis command creates the RCS file f.c,v, stores f.c into it as revision 1.1, and
Xdeletes f.c.  It also asks you for a description. The description
Xshould be a synopsis of the contents of the file. All later check-in
Xcommands will ask you for a log entry, which should summarize the
Xchanges that you made.
X.PP
XFiles ending in ,v are called RCS files (`v' stands for `versions'),
Xthe others are called working files.
XTo get back the working file f.c in the previous example, use the check-out
Xcommand
X.PP
X.ti 1.5i
X.B "co  f.c
X.PP
XThis command extracts the latest revision from f.c,v and writes
Xit into f.c. You can now edit f.c and check it back in by invoking
X.PP
X.ti 1.5i
X.B "ci  f.c
X.PP
X\fICi\fR increments the revision number properly. 
XIf \fIci\fR complains with the message
X.PP
X		ci error: no lock set by <your login>
X.PP
Xthen your system administrator has decided to create all RCS files
Xwith the locking attribute set to `strict'. In this case, you should
Xhave locked the revision during the previous check-out. Your last check-out
Xshould have been
X.PP
X.ti 1.5i
X.B "co  \-l  f.c
X.PP
XOf course, it is too late now to do the check-out with locking, because you
Xprobably modified f.c already, and a second check-out would
Xoverwrite your modifications. Instead, invoke
X.PP
X.ti 1.5i
X.B "rcs  \-l  f.c
X.PP
XThis command will lock the latest revision for you, unless somebody
Xelse got ahead of you already. In this case, you'll have to negotiate with 
Xthat person.
X.PP
XLocking assures that you, and only you, can check in the next update, and
Xavoids nasty problems if several people work on the same file.
XEven if a revision is locked, it can still be checked out for
Xreading, compiling, etc. All that locking
Xprevents is a CHECK-IN by anybody but the locker.
X.PP
XIf your RCS file is private, i.e., if you are the only person who is going
Xto deposit revisions into it, strict locking is not needed and you
Xcan turn it off.
XIf strict locking is turned off,
Xthe owner of the RCS file need not have a lock for check-in; all others
Xstill do. Turning strict locking off and on is done with the commands
X.PP
X.ti 1.5i
X.BR "rcs  \-U  f.c" "     and     " "rcs  \-L  f.c"
X.PP
XIf you don't want to clutter your working directory with RCS files, create 
Xa subdirectory called RCS in your working directory, and move all your RCS 
Xfiles there. RCS commands will look first into that directory to find 
Xneeded files. All the commands discussed above will still work, without any 
Xmodification. 
X(Actually, pairs of RCS and working files can be specified in 3 ways:
X(a) both are given, (b) only the working file is given, (c) only the
XRCS file is given. Both RCS and working files may have arbitrary path prefixes;
XRCS commands pair them up intelligently).
X.PP
XTo avoid the deletion of the working file during check-in (in case you want to
Xcontinue editing), invoke
X.PP
X.ti 1.5i
X.BR "ci  \-l  f.c" "     or     " "ci  \-u  f.c"
X.PP
XThese commands check in f.c as usual, but perform an implicit
Xcheck-out. The first form also locks the checked in revision, the second one
Xdoesn't. Thus, these options save you one check-out operation.
XThe first form is useful if locking is strict, the second one if not strict.
XBoth update the identification markers in your working file (see below).
X.PP
XYou can give \fIci\fR the number you want assigned to a checked in
Xrevision. Assume all your revisions were numbered 1.1, 1.2, 1.3, etc.,
Xand you would like to start release 2.
XThe command
X.PP
X.ti 1.5i
X.BR "ci  \-r2  f.c" "     or     " "ci  \-r2.1  f.c"
X.PP
Xassigns the number 2.1 to the new revision.
XFrom then on, \fIci\fR will number the subsequent revisions
Xwith 2.2, 2.3, etc. The corresponding \fIco\fR commands
X.PP
X.ti 1.5i
X.BR "co  \-r2  f.c" "     and     " "co  \-r2.1  f.c"
X.PP
Xretrieve the latest revision numbered 2.x and the revision 2.1,
Xrespectively. \fICo\fR without a revision number selects
Xthe latest revision on the "trunk", i.e., the highest
Xrevision with a number consisting of 2 fields. Numbers with more than 2
Xfields are needed for branches.
XFor example, to start a branch at revision 1.3, invoke
X.PP
X.ti 1.5i
X.B "ci  \-r1.3.1  f.c
X.PP
XThis command starts a branch numbered 1 at revision 1.3, and assigns
Xthe number 1.3.1.1 to the new revision. For more information about
Xbranches, see \fIrcsfile\fR(5L).
X.sp
X.PP
X.B "Automatic Identification"
X.PP
XRCS can put special strings for identification into your source and object
Xcode. To obtain such identification, place the marker
X.PP
X.ti 1.5i
X$\&Header$
X.PP
Xinto your text, for instance inside a comment.
XRCS will replace this marker with a string of the form
X.PP
X.ti 1.5i
X$\&Header:  filename  revision_number  date  time  author  state $
X.PP
XWith such a marker on the first page of each module, you can
Xalways see with which revision you are working.
XRCS keeps the markers up to date automatically.
XTo propagate the markers into your object code, simply put
Xthem into literal character strings. In C, this is done as follows:
X.PP
X.ti 1.5i
Xstatic char rcsid[] = "$\&Header$";
X.PP
XThe command \fIident\fR extracts such markers from any file, even object code
Xand dumps.
XThus, \fIident\fR lets you find out
Xwhich revisions of which modules were used in a given program. 
X.PP
XYou may also find it useful to put the marker $\&Log$
Xinto your text, inside a comment. This marker accumulates
Xthe log messages that are requested during check-in.
XThus, you can maintain the complete history of your file directly inside it.
XThere are several additional identification markers; see \fIco\fR(1L) for
Xdetails.
X.SH IDENTIFICATION
X.de VL
X\\$2
X..
XAuthor: Walter F. Tichy,
XPurdue University, West Lafayette, IN, 47907.
X.br
XRevision Number:
X.VL $Revision: 1.2 $
X; Release Date:
X.VL $Date: 89/05/02 11:17:54 $
X\&.
X.br
XCopyright \(co 1982, 1988, 1989 by Walter F. Tichy.
X.SH SEE ALSO
Xci(1L), co(1L), ident(1L), merge(1L), rcs(1L), rcsdiff(1L), rcsmerge(1L), rlog(1L),
Xrcsfile(5L),
X.br
XWalter F. Tichy, "Design, Implementation, and Evaluation of a Revision Control
XSystem," in \fIProceedings of the 6th International Conference on Software
XEngineering\fR, IEEE, Tokyo, Sept. 1982.
SHAR_EOF
echo "extracting doc/rcsmerge.1l"
sed 's/^X//' << \SHAR_EOF > doc/rcsmerge.1l
X.TH RCSMERGE 1L "" "Purdue University"
X.SH NAME
Xrcsmerge \- merge RCS revisions
X.SH SYNOPSIS
X\fBrcsmerge\fR \fB\-r\fIrev1\fR [ \fB\-r\fIrev2\fR ] [ \fB\-p\fR ] file
X.SH DESCRIPTION
X.I Rcsmerge
Xincorporates the changes between \fIrev1\fR and \fIrev2\fR of an
XRCS file into the corresponding working file. If \fB\-p\fR is given, the result
Xis printed on the standard output, otherwise the result overwrites the
Xworking file.
X.PP
XA file name ending in ',v' is an RCS file name, otherwise a
Xworking file name. \fIMerge\fR derives the working file name from the RCS
Xfile name and vice versa, as explained in
X.IR co (1L).
XA pair consisting
Xof both an RCS and a working file name may also be specified.
X.PP
X\fIRev1\fR may not be omitted. If \fIrev2\fR is omitted, the latest
Xrevision on the default branch (normally the highest branch on the trunk)
Xis assumed.
XBoth \fIrev1\fR and \fIrev2\fR may be given numerically or symbolically.
X.PP
X\fIRcsmerge\fR prints a warning if there are overlaps, and delimits
Xthe overlapping regions as explained in \fIco \-j\fR.
XThe command is useful for incorporating changes into a checked-out revision.
X.SH EXAMPLES
XSuppose you have released revision 2.8 of f.c. Assume
Xfurthermore that you just completed revision 3.4, when you receive
Xupdates to release 2.8 from someone else.
XTo combine the updates to 2.8 and your changes between 2.8 and 3.4,
Xput the updates to 2.8 into file f.c and execute
X.sp
X.B "        rcsmerge  \-p  \-r2.8  \-r3.4  f.c  >f.merged.c
X.sp
XThen examine f.merged.c.
XAlternatively, if you want to save the updates to 2.8 in the RCS file,
Xcheck them in as revision 2.8.1.1 and execute \fIco \-j\fR:
X.sp
X.B "        ci  \-r2.8.1.1  f.c
X.br
X.B "        co  \-r3.4  \-j2.8:2.8.1.1  f.c
X.sp
XAs another example, the following command undoes the changes
Xbetween revision 2.4 and 2.8 in your currently checked out revision
Xin f.c.
X.sp
X.B "        rcsmerge  \-r2.8  \-r2.4  f.c
X.sp
XNote the order of the arguments, and that f.c will be
Xoverwritten.
X.SH IDENTIFICATION
X.de VL
X\\$2
X..
XAuthor: Walter F. Tichy,
XPurdue University, West Lafayette, IN, 47907.
X.sp 0
XRevision Number:
X.VL $Revision: 1.2 $
X; Release Date:
X.VL $Date: 89/05/02 11:18:34 $
X\&.
X.sp 0
XCopyright \(co 1982, 1988, 1989 by Walter F. Tichy.
X.SH SEE ALSO
Xci(1L), co(1L), merge(1L), ident(1L), rcs(1L), rcsdiff(1L), rlog(1L), rcsfile(5L),
X.br
XWalter F. Tichy, "Design, Implementation, and Evaluation of a Revision Control
XSystem," in \fIProceedings of the 6th International Conference on Software
XEngineering\fR, IEEE, Tokyo, Sept. 1982.
X.SH BUGS
X\fIRcsmerge\fR does not work on
Xfiles that contain lines with a single `.'.
SHAR_EOF
echo "extracting doc/rlog.1l"
sed 's/^X//' << \SHAR_EOF > doc/rlog.1l
X.TH RLOG 1L "" "Purdue University"
X.SH NAME
Xrlog \- print log messages and other information about RCS files
X.SH SYNOPSIS
X.B rlog
X[ options ]
Xfile ...
X.SH DESCRIPTION
X.I Rlog
Xprints information about RCS files.
XFiles ending in `,v' are RCS files, all others are working files. If
Xa working file is given, \fIrlog\fR tries to find the corresponding
XRCS file first in directory ./RCS and then in the current directory,
Xas explained in
X.IR co (1L).
X.PP
X\fIRlog\fR prints the following information for each
XRCS file: RCS file name, working file name, head (i.e., the number
Xof the latest revision on the trunk), default branch, access list, locks,
Xsymbolic names, suffix, total number of revisions, 
Xnumber of revisions selected for printing, and 
Xdescriptive text. This is followed by entries for the selected revisions in
Xreverse chronological order for each branch. For each revision,
X\fIrlog\fR prints revision number, author, date/time, state, number of
Xlines added/deleted (with respect to the previous revision),
Xlocker of the revision (if any), and log message.
XWithout options, \fIrlog\fR prints complete information.
XThe options below restrict this output.
X.TP 10
X.B \-L
Xignores RCS files that have no locks set; convenient in combination with
X\fB\-R\fR, \fB\-h\fR, or \fB\-l\fR.
X.TP 10
X.B \-R
Xonly prints the name of the RCS file; convenient for translating a
Xworking file name into an RCS file name.
X.TP 10
X.B \-h
Xprints only RCS file name, working file name, head, 
Xdefault branch, access list, locks,
Xsymbolic names, and suffix.
X.TP 10
X.B \-t
Xprints the same as \fB\-h\fR, plus the descriptive text.
X.TP 10
X.B \-b
Xprints information about the revisions on the default branch (normally
Xthe highest branch on the trunk).
X.TP 10
X.BI \-d "dates"
Xprints information about revisions with a checkin date/time in the ranges given by
Xthe semicolon-separated list of \fIdates\fR.
XA range of the form \fId1<d2\fR or \fId2>d1\fR
Xselects the revisions that were deposited between
X\fId1\fR and \fId2\fR, (inclusive).
XA range of the form \fI<d\fR or \fId>\fR selects
Xall revisions dated
X\fId\fR or earlier.
XA range of the form \fId<\fR or \fI>d\fR selects
Xall revisions dated \fId\fR or later.
XA range of the form \fId\fR selects the single, latest revision dated \fId\fR or
Xearlier.
XThe date/time strings \fId, d1, \fRand \fId2\fR
Xare in the free format explained in
X.IR co (1L). 
XQuoting is normally necessary, especially for \fI<\fR and \fI>\fR. Note that the separator is
Xa semicolon.
X.TP 10
X.B \-l\fR[\fIlockers\fR]
Xprints information about locked revisions.
XIf the comma-separated list \fIlockers\fR of login names is given,
Xonly the revisions locked by the given login names are printed.
XIf the list is omitted, all locked revisions are printed.
X.TP 10
X.BI \-r "revisions"
Xprints information about revisions given in the comma-separated list
X\fIrevisions\fR of revisions and ranges. A range \fIrev1-rev2\fR means revisions
X\fIrev1\fR to \fIrev2\fR on the same branch, \fI-rev\fR means revisions
Xfrom the beginning of the branch up to and including \fIrev\fR,
Xand \fIrev-\fR means revisions starting with \fIrev\fR to the end of the
Xbranch containing \fIrev\fR. An argument that is a branch means all
Xrevisions on that branch. A range of branches means all revisions
Xon the branches in that range.
X.TP 10
X.BI \-s "states"
Xprints information about revisions whose state attributes match one of the
Xstates given in the comma-separated list \fIstates\fR.
X.TP 10
X.B \-w\fR[\fIlogins\fR]
Xprints information about revisions checked in by users with 
Xlogin names appearing in the comma-separated list \fIlogins\fR.
XIf \fIlogins\fR is omitted, the user's login is assumed.
X.PP
X\fIRlog\fR prints the intersection of the revisions selected with
Xthe options \fB\-d\fR, \fB\-l\fR, \fB\-s\fR, \fB\-w\fR, intersected
Xwith the union of the revisions selected by \fB\-b\fR and \fB\-r\fR.
X.SH EXAMPLES
X.nf
X.sp
X        rlog  \-L  \-R  RCS/*,v
X        rlog  \-L  \-h  RCS/*,v
X        rlog  \-L  \-l  RCS/*,v
X        rlog  RCS/*,v
X.sp
X.fi
XThe first command prints the names of all RCS files in the subdirectory `RCS'
Xwhich have locks. The second command prints the headers of those files,
Xand the third prints the headers plus the log messages of the locked revisions.
XThe last command prints complete information.
X.SH DIAGNOSTICS
XThe exit status always refers to the last RCS file operated upon,
Xand is 0 if the operation was successful, 1 otherwise.
X.SH IDENTIFICATION
X.de VL
X\\$2
X..
XAuthor: Walter F. Tichy,
XPurdue University, West Lafayette, IN, 47907.
X.sp 0
XRevision Number:
X.VL $Revision: 1.3 $
X; Release Date:
X.VL $Date: 89/05/02 11:19:20 $
X\&.
X.sp 0
XCopyright \(co 1982, 1988, 1989 by Walter F. Tichy.
X.SH SEE ALSO
Xci(1L), co(1L), ident(1L), rcs(1L), rcsdiff(1L), rcsintro(1L), rcsmerge(1L),
Xrcsfile(5L)
X.br
XWalter F. Tichy, "Design, Implementation, and Evaluation of a Revision Control
XSystem," in \fIProceedings of the 6th International Conference on Software
XEngineering\fR, IEEE, Tokyo, Sept. 1982.
SHAR_EOF
if `test ! -d ked`
then
  mkdir ked
  echo "mkdir ked"
fi
echo "extracting ked/ked.c,v"
sed 's/^X//' << \SHAR_EOF > ked/ked.c,v
Xhead     1.5;
Xbranch   ;
Xaccess   ;
Xsymbols  ;
Xlocks    ; strict;
Xcomment  @ * @;
X
X
X1.5
Xdate     89.09.17.10.58.39;  author rick;  state Exp;
Xbranches ;
Xnext     1.4;
X
X1.4
Xdate     89.09.04.18.52.56;  author rick;  state Exp;
Xbranches ;
Xnext     1.3;
X
X1.3
Xdate     89.09.01.11.02.22;  author rick;  state Exp;
Xbranches ;
Xnext     1.2;
X
X1.2
Xdate     89.08.27.19.01.04;  author rick;  state Exp;
Xbranches ;
Xnext     1.1;
X
X1.1
Xdate     89.08.27.17.44.11;  author rick;  state Exp;
Xbranches ;
Xnext     ;
X
X
Xdesc
X@Initial checkin
X@
X
X
X1.5
Xlog
X@Cleanup so no errors when compiled with Lattice C
X@
Xtext
X@/* ed - standard editor		Authors: Brian Beattie, Kees Bot, and others */
X
X/* Modifications for Amiga made by Rick Schaeffer */
X
X/*
X * Copyright 1987 Brian Beattie Rights Reserved.
X *
X * Permission to copy and/or distribute granted under the
X * following conditions:
X *
X * 1). No charge may be made other than reasonable charges
X *	for reproduction.
X *
X * 2). This notice must remain intact.
X *
X * 3). No further restrictions may be added.
X *
X */
X
X/*	This program used to be in many little pieces, with this makefile:
X.SUFFIXES:	.c .s
X
XCFLAGS = -F 
X
XOBJS =	append.s catsub.s ckglob.s deflt.s del.s docmd.s doglob.s\
X	doprnt.s doread.s dowrite.s ed.s egets.s find.s getfn.s getlst.s\
X	getnum.s getone.s getptr.s getrhs.s gettxt.s ins.s join.s maksub.s\
X	move.s optpat.s set.s setbuf.s subst.s getpat.s matchs.s amatch.s\
X	unmkpat.s omatch.s makepat.s bitmap.s dodash.s esc.s system.s
X
Xed:	$(OBJS)
X	cc -T. -i -o ed $(OBJS)
X*/
X
X#include <stdio.h>
X#include <ios1.h>
X/****************************/
X
X/*	tools.h	*/
Xstatic char	tools_h[] =
X"$Header: Rodime:ricks/rcs2/src/ked/ked.c,v 1.4 89/09/04 18:52:56 rick Exp Locker: rick $";
X/*
X *	#defines for non-printing ASCII characters
X */
X
X#define NUL	0x00	/* ^@@ */
X#define EOS	0x00	/* end of string */
X#define SOH	0x01	/* ^A */
X#define STX	0x02	/* ^B */
X#define ETX	0x03	/* ^C */
X#define EOT	0x04	/* ^D */
X#define ENQ	0x05	/* ^E */
X#define ACK	0x06	/* ^F */
X#define BEL	0x07	/* ^G */
X#define BS	0x08	/* ^H */
X#define HT	0x09	/* ^I */
X#define LF	0x0a	/* ^J */
X#define NL	'\n'
X#define VT	0x0b	/* ^K */
X#define FF	0x0c	/* ^L */
X#define CR	0x0d	/* ^M */
X#define SO	0x0e	/* ^N */
X#define SI	0x0f	/* ^O */
X#define DLE	0x10	/* ^P */
X#define DC1	0x11	/* ^Q */
X#define DC2	0x12	/* ^R */
X#define DC3	0x13	/* ^S */
X#define DC4	0x14	/* ^T */
X#define NAK	0x15	/* ^U */
X#define SYN	0x16	/* ^V */
X#define ETB	0x17	/* ^W */
X#define CAN	0x18	/* ^X */
X#define EM	0x19	/* ^Y */
X#define SUB	0x1a	/* ^Z */
X#define ESC	0x1b	/* ^[ */
X#define FS	0x1c	/* ^\ */
X#define GS	0x1d	/* ^] */
X#define RS	0x1e	/* ^^ */
X#define US	0x1f	/* ^_ */
X#define SP	0x20	/* space */
X#define DEL	0x7f	/* DEL*/
X
X
X#define TRUE	1
X#define FALSE	0
X#define ERR	-2
X
X
X/*	Definitions of meta-characters used in pattern matching
X *	routines.  LITCHAR & NCCL are only used as token identifiers;
X *	all the others are also both token identifier and actual symbol
X *	used in the regular expression.
X */
X
X
X#define BOL	'^'
X#define EOL	'$'
X#define ANY	'.'
X#define LITCHAR	'L'
X#define	ESCAPE	'\\'
X#define CCL	'['	/* Character class: [...] */
X#define CCLEND	']'
X#define NEGATE	'~'
X#define NCCL	'!'	/* Negative character class [^...] */
X#define CLOSURE	'*'
X#define OR_SYM	'|'
X#define DITTO	'&'
X#define OPEN	'('
X#define CLOSE	')'
X
X/* Largest permitted size for an expanded character class.  (i.e. the class
X * [a-z] will expand into 26 symbols; [a-z0-9] will expand into 36.)
X */
X#define CLS_SIZE	128
X
X/*
X *	Tokens are used to hold pattern templates. (see makepat())
X */
Xtypedef	char	BITMAP;
X
Xtypedef struct token {
X	char		tok;
X	char		lchar;
X	BITMAP		*bitmap;
X	struct token	*next;
X} TOKEN;
X
X#define TOKSIZE sizeof (TOKEN)
X
X/*
X *	An absolute maximun for strings.
X */
X
X#define MAXSTR	132	/* Maximum numbers of characters in a line */
X
X
Xextern	char	*matchs();
Xextern	char	*amatch();
Xextern	char	*in_string();
Xextern	TOKEN	*getpat();
Xextern	int	esc();
Xextern	char	*dodash();
Xextern	TOKEN	*makepat();
Xextern	void	unmakepat();
Xextern	int	insert();
Xextern	int	delete();
Xextern	int	isalphanum();
Xextern	char	*stoupper();
Xextern	int	pr_tok();
Xextern	int	pr_line();
Xextern	BITMAP	*makebitmap();
X
X/* macros */
X#define toupper(c)	(c>='a'&&c<='z'?c-32:c)
X
X/*	ed.h	*/
X#define FATAL	(ERR-1)
Xstruct	line {
X	int		l_stat;		/* empty, mark */
X	struct line	*l_prev;
X	struct line	*l_next;
X	char		l_buff[1];
X};
X
Xtypedef struct line	LINE;
X
X#define LINFREE	1	/* entry not in use */
X#define LGLOB	2       /* line marked global */
X
X#define MAXLINE	256	/* max number of chars per line */
X#define MAXPAT	256	/* max number of chars per replacement pattern */
X#define MAXFNAME 256	/* max file name size */
X
Xextern LINE	line0;
Xextern int	curln, lastln, line1, line2, nlines;
Xextern int	nflg;		/* print line number flag */
Xextern int	lflg;		/* print line in verbose mode */
Xextern int	pflg;		/* print current line after each command */
Xextern char	*inptr;			/* tty input buffer */
Xextern char	linbuf[], *linptr;	/* current line */
Xextern int	truncflg;	/* truncate long line flag */
Xextern int	eightbit;	/* save eighth bit */
Xextern int	nonascii;	/* count of non-ascii chars read */
Xextern int	nullchar;	/* count of null chars read */
Xextern int	truncated;	/* count of lines truncated */
Xextern int	fchanged;	/* file changed */
X
X#define nextln(l)	((l)+1 > lastln ? 0 : (l)+1)
X#define prevln(l)	((l)-1 < 0 ? lastln : (l)-1)
X
Xextern char	*getfn();
Xextern LINE	*getptr();
Xextern char	*gettxt();
Xextern char	*maksub();
Xextern TOKEN	*optpat();
X
Xextern char	*catsub();
X
Xextern char	*strcpy();
Xextern int	*malloc();
Xextern void putcntl(),prntln(),relink(),clrbuf(),edsetbuf();
X
X/*	amatch.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X
X/*     Scans throught the pattern template looking for a match
X * with lin.  Each element of lin is compared with the template
X * until either a mis-match is found or the end of the template
X * is reached.  In the former case a 0 is returned; in the latter,
X * a pointer into lin (pointing to the character following the
X * matched pattern) is returned.
X *
X *	"lin"	is a pointer to the line being searched.
X *	"pat"	is a pointer to a template made by makepat().
X *	"boln"	is a pointer into "lin" which points at the
X *			character at the beginning of the line.
X */
X
Xchar *paropen[9], *parclose[9];
Xint between, parnum;
Xstatic char *match();
X
Xchar	*
Xamatch(lin, pat, boln)
Xchar	*lin;
XTOKEN	*pat;
Xchar	*boln;
X{
X
X	between=0;
X	parnum=0;
X
X	lin=match(lin, pat, boln);
X
X	if (between) return 0;
X
X	while (parnum<9) {
X		paropen[parnum] = parclose[parnum] = "";
X		parnum++;
X	}
X	return lin;
X}
X
Xstatic char	*
Xmatch(lin, pat, boln)
Xchar	*lin;
XTOKEN	*pat;
Xchar	*boln;
X{
X	register char	*bocl, *rval, *strstart;
X
X	if(pat == 0)
X		return 0;
X
X	strstart = lin;
X
X	while(pat)
X	{
X		if(pat->tok == CLOSURE && pat->next)
X		{
X				/* Process a closure:
X				 * first skip over the closure token to the
X				 * object to be repeated.  This object can be
X				 * a character class.
X				 */
X
X			pat = pat->next;
X
X				/* Now match as many occurrences of the
X				 * closure pattern as possible.
X				 */
X			bocl = lin;
X
X			while( *lin && omatch(&lin, pat))
X				;
X
X				/* 'Lin' now points to the character that made
X				 * made us fail.  Now go on to process the
X				 * rest of the string.  A problem here is
X				 * a character following the closure which
X				 * could have been in the closure.
X				 * For example, in the pattern "[a-z]*t" (which
X				 * matches any lower-case word ending in a t),
X				 * the final 't' will be sucked up in the while
X				 * loop.  So, if the match fails, we back up a
X				 * notch and try to match the rest of the
X				 * string again, repeating this process
X				 * recursively until we get back to the
X				 * beginning of the closure.  The recursion
X				 * goes, at most two levels deep.
X				 */
X
X			if(pat = pat->next)
X			{
X				int savbtwn=between;
X				int savprnm=parnum;
X
X				while(bocl <= lin)
X				{
X					if(rval = match(lin, pat, boln))
X					{
X							/* success */
X						return(rval);
X					} else {
X						--lin;
X						between=savbtwn;
X						parnum=savprnm;
X					}
X				}
X				return (0);	/* match failed */
X			}
X		} else
X		if (pat->tok == OPEN)
X		{
X			if (between || parnum>=9) return 0;
X			paropen[parnum] = lin;
X			between=1;
X			pat = pat->next;
X		} else
X		if (pat->tok == CLOSE)
X		{
X			if (!between) return 0;
X			parclose[parnum++] = lin;
X			between=0;
X			pat = pat->next;
X		} else
X		if (omatch(&lin, pat, boln))
X		{
X			pat = pat->next;
X		} else {
X			return (0);
X		}
X	}
X		/* Note that omatch() advances lin to point at the next
X		 * character to be matched.  Consequently, when we reach
X		 * the end of the template, lin will be pointing at the
X		 * character following the last character matched.  The
X		 * exceptions are templates containing only a BOLN or EOLN
X		 * token.  In these cases omatch doesn't advance.
X		 *
X		 * A philosophical point should be mentioned here.  Is $
X		 * a position or a character? (i.e. does $ mean the EOL
X		 * character itself or does it mean the character at the end
X		 * of the line.)  I decided here to make it mean the former,
X		 * in order to make the behavior of match() consistent.  If
X		 * you give match the pattern ^$ (match all lines consisting
X		 * only of an end of line) then, since something has to be
X		 * returned, a pointer to the end of line character itself is
X		 * returned.
X		 */
X
X	return ((char *)max(strstart , lin));
X}
X
X/*	append.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xappend(line, glob)
Xint	line, glob;
X{
X	int	stat;
X	char	lin[MAXLINE];
X
X	if(glob)
X		return(ERR);
X	curln = line;
X	while(1)
X	{
X		if(nflg)
X			printf("%d\t",curln+1);
X
X		if(fgets(lin, MAXLINE, stdin) == NULL)
X			return( EOF );
X		if(lin[0] == '.' && lin[1] == '\n')
X			return(0);
X		stat = ins(lin);
X		if(stat < 0)
X			return( ERR );
X		
X	}
X}
X
X/*	bitmap.c	*/
X/*
X *	BITMAP.C -	makebitmap, setbit, testbit
X *			bit-map manipulation routines.
X *
X *	Copyright (c) Allen I. Holub, all rights reserved.  This program may
X *		for copied for personal, non-profit use only.
X *
X */
X 
X#ifdef DEBUG
X/* #include <stdio.h> */
X#endif
X 
X/* #include "tools.h" */
X 
X
XBITMAP	*makebitmap( size )
Xunsigned size;
X{
X	/*	Make a bit map with "size" bits.  The first entry in
X	 *	the map is an "unsigned int" representing the maximum
X	 *	bit.  The map itself is concatenated to this integer.
X	 *	Return a pointer to a map on success, 0 if there's
X	 *	not enough memory.
X	 */
X
X	unsigned *map, numbytes;
X
X	numbytes = (size >> 3) + ((size & 0x07) ? 1 : 0 );
X
X#ifdef DEBUG
X	printf("Making a %d bit map (%d bytes required)\n", size, numbytes);
X#endif
X
X	if( map = (unsigned *) malloc( numbytes + sizeof(unsigned) ))
X		*map = size;
X
X	return ((BITMAP *)map);
X}
X
Xsetbit( c, map, val )
Xunsigned	c, val;
Xchar		*map;
X{
X	/*	Set bit c in the map to val.
X	 *	If c > map-size, 0 is returned, else 1 is returned.
X	 */
X
X	if( c >= *(unsigned *)map )	/* if c >= map size */
X		return 0;
X
X	map += sizeof(unsigned);	/* skip past size */
X	
X	if( val )
X		map[c >> 3] |= 1 << (c & 0x07);
X	else
X		map[c >> 3] &= ~(1 << (c & 0x07));
X
X	return( 1 );
X}
X
Xtestbit( c, map )
Xunsigned	c;
Xchar		*map;
X{
X	/*	Return 1 if the bit corresponding to c in map is set.
X	 *	0 if it is not.
X	 */
X
X	if( c >= *(unsigned *)map )
X		return 0;
X
X	map += sizeof(unsigned);
X	
X	return(map[ c >> 3 ] & (1 << (c & 0x07)));
X}
X
X/*	catsub.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xextern char *paropen[9], *parclose[9];
X
Xchar	*
Xcatsub(from, to, sub, new, newend)
Xchar	*from, *to, *sub, *new, *newend;
X{
X	char	*cp, *cp2;
X
X	for(cp = new; *sub != EOS && cp < newend;)
X	{
X		if(*sub == DITTO)
X			for(cp2 = from; cp2 < to;)
X			{
X				*cp++ = *cp2++;
X				if(cp >= newend)
X					break;
X			}
X		else
X		if (*sub == ESCAPE) {
X			sub++;
X			if ('1' <= *sub && *sub <= '9') {
X				char *parcl = parclose[*sub - '1'];
X
X				for (cp2 = paropen[*sub - '1']; cp2 < parcl;)
X				{
X					*cp++ = *cp2++;
X					if (cp >= newend) break;
X				}
X			} else
X				*cp++ = *sub;
X		} else
X			*cp++ = *sub;
X
X		sub++;
X	}
X
X	return(cp);
X}
X
X/*	ckglob.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xckglob()
X{
X	TOKEN	*glbpat;
X	char	c, delim, *lin;
X	int	num;
X	LINE	*ptr;
X
X	c = *inptr;
X
X	if(c != 'g' && c != 'v')
X		return(0);
X
X	if (deflt(1, lastln) < 0)
X		return(ERR);
X
X	delim = *++inptr;
X	if(delim <= ' ')
X		return(ERR);
X
X	glbpat = optpat();
X
X	if(*inptr == delim)
X		inptr++;
X
X	for (num=1; num<=lastln; num++)
X	{
X		ptr = getptr(num);
X		ptr->l_stat &= ~LGLOB;
X		if (line1 <= num && num <= line2) {
X			lin = gettxt(num);
X			if(matchs(lin, glbpat, 0)) {
X				if (c=='g') ptr->l_stat |= LGLOB;
X			} else {
X				if (c=='v') ptr->l_stat |= LGLOB;
X			}
X		}
X	}
X	return(1);
X}
X
X/*	deflt.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xdeflt(def1, def2)
Xint	def1, def2;
X{
X	if(nlines == 0)
X	{
X		line1 = def1;
X		line2 = def2;
X	}
X	if(line1 > line2 || line1 <= 0)
X		return (ERR);
X}
X
X/*	del.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xdel(from, to)
Xint	from, to;
X{
X	LINE	*first, *last, *next, *tmp;
X
X	if(from < 1)
X		from = 1;
X	first = getptr(prevln(from));
X	last = getptr(nextln(to));
X	next = first->l_next;
X	while(next != last && next != &line0)
X	{
X		tmp = next->l_next;
X		free(next);
X		next = tmp;
X	}
X	relink(first, last, first, last);
X	lastln -= (to - from)+1;
X	curln = prevln(from);
X	return(1);
X}
X
X/*	docmd.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xchar	fname[MAXFNAME];
Xint	fchanged;
Xextern int nofname;
Xextern int prompt;
Xextern	int mark[];
X
Xdocmd(glob)
Xint	glob;
X{
X	static char	rhs[MAXPAT];
X	TOKEN	*subpat;
X	int	c, err, line3;
X	int	apflg, pflag, gflag;
X	int	nchng;
X	char	*fptr;
X
X	pflag = FALSE;
X	while(*inptr == SP && *inptr == HT)
X		inptr++;
X
X	c = *inptr++;
X
X	switch(c)
X	{
X	case NL:					/* print next line */
X		if(nlines == 0)
X		{
X			if ((line2 = nextln(curln))==0)
X				return(ERR);
X		}
X		curln = line2;
X		return (1);
X		break;
X
X	case '=':					/* print current line number */
X		printf("%d\n",line2);
X		break;
X
X	case 'a':					/* append lines */
X		if(*inptr != NL || nlines > 1)
X			return(ERR);
X
X		if(append(line1, glob) < 0)
X			return(ERR);;
X		fchanged = TRUE;
X		break;
X
X	case 'c':					/* changed lines */
X		if(*inptr != NL)
X			return(ERR);
X
X		if(deflt(curln, curln) < 0)
X			return(ERR);
X
X		if(del(line1, line2) < 0)
X			return(ERR);
X		if(append(curln, glob) < 0)
X			return(ERR);
X		fchanged = TRUE;
X		break;
X
X	case 'd':					/* delete lines */
X		if(*inptr != NL)
X			return(ERR);
X
X		if(deflt(curln, curln) < 0)
X			return(ERR);
X
X		if(del(line1, line2) < 0)
X			return(ERR);
X		if(nextln(curln) != 0)
X			curln = nextln(curln);
X		fchanged = TRUE;
X		break;
X
X	case 'e':					/* edit new file with change check */
X		if(nlines > 0)
X			return(ERR);
X		if(fchanged) {
X			fchanged = FALSE;
X			return(ERR);
X		}
X		/*FALL THROUGH*/
X	case 'E':					/* edit new file no check */
X		if(nlines > 0)
X			return(ERR);
X
X		if(*inptr != ' ' && *inptr != HT && *inptr != NL)
X			return(ERR);
X
X		if((fptr = getfn()) == NULL)
X			return(ERR);
X
X		clrbuf();
X		if((err = doread(0, fptr)) < 0)
X			return(err);
X
X		strcpy(fname, fptr);
X		fchanged = FALSE;
X		break;
X
X	case 'f':					/* set or display current file name */
X		if(nlines > 0)
X			return(ERR);
X
X		if(*inptr != ' ' && *inptr != HT && *inptr != NL)
X			return(ERR);
X
X		if((fptr = getfn()) == NULL)
X			return(ERR);
X
X		if (nofname)
X			printf("%s\n", fname);
X		else
X			strcpy(fname, fptr);
X		break;
X
X	case 'H':
X	case 'h':					/* print last error */
X		return(ERR);
X		break;
X
X	case 'i':					/* insert lines */
X		if(*inptr != NL || nlines > 1)
X			return(ERR);
X
X		if(append(prevln(line1), glob) < 0)
X			return(ERR);
X		fchanged = TRUE;
X		break;
X
X	case 'j':					/* join lines */
X		if (*inptr != NL || deflt(curln, curln+1)<0)
X			return(ERR);
X
X		if (join(line1, line2) < 0)
X			return(ERR);
X		break;
X
X	case 'k':					/* mark line address */
X		while (*inptr == ' ' || *inptr == HT) inptr++;
X
X		if (*inptr < 'a' || *inptr > 'z')
X			return ERR;
X		c= *inptr++;
X
X		if(*inptr != ' ' && *inptr != HT && *inptr != NL)
X			return(ERR);
X
X		mark[c-'a'] = line1;
X		break;
X
X	case 'L':					/* toggle verbose print */
X		lflg = ~lflg;
X		break;
X
X	case 'l':					/* print lines verbose */
X		if(*inptr != NL)
X			return(ERR);
X		if(deflt(curln,curln) < 0)
X			return(ERR);
X		if (dolst(line1,line2) < 0)
X			return(ERR);
X		break;
X
X	case 'm':					/* move lines */
X		if((line3 = getone()) < 0)
X			return(ERR);
X		if(deflt(curln,curln) < 0)
X			return(ERR);
X		if(move(line3) < 0)
X			return(ERR);
X		fchanged = TRUE;
X		break;
X
X	case 'N':					/* toggle print line numbers */
X		nflg = ~nflg;
X		break;
X
X	case 'n':					/* print lines with numbers */
X		if(*inptr != NL)
X			return(ERR);
X		if(deflt(curln,curln) < 0)
X			return(ERR);
X		if (donum(line1,line2) < 0)
X			return(ERR);
X		break;
X
X	case 'P':					/* toggle prompt */
X		prompt = ~prompt;
X		break;
X
X	case 'p':					/* print lines */
X		if(*inptr != NL)
X			return(ERR);
X		if(deflt(curln,curln) < 0)
X			return(ERR);
X		if(doprnt(line1,line2) < 0)
X			return(ERR);
X		break;
X
X	case 'q':					/* quit, check changed */
X		if(fchanged) {
X			fchanged = FALSE;
X			return(ERR);
X		}
X		/*FALL THROUGH*/
X	case 'Q':					/* quit, no check for change */
X		if(*inptr == NL && nlines == 0 && !glob)
X			return(EOF);
X		else
X			return(ERR);
X
X	case 'r':					/* read in file */
X		if(nlines > 1)
X			return(ERR);
X
X		if(nlines == 0)
X			line2 = lastln;
X
X		if(*inptr != ' ' && *inptr != HT && *inptr != NL)
X			return(ERR);
X
X		if((fptr = getfn()) == NULL)
X			return(ERR);
X
X		if((err = doread(line2, fptr)) < 0)
X			return(err);
X		fchanged = TRUE;
X		break;
X
X	case 's':					/* substitute, set */
X		if(*inptr == 'e')
X			return(set());
X		while(*inptr == SP || *inptr == HT)
X			inptr++;
X		if((subpat = optpat()) == NULL)
X			return(ERR);
X		if((gflag = getrhs(rhs)) < 0)
X			return(ERR);
X		if(*inptr == 'p')
X			pflag++;
X		if(deflt(curln, curln) < 0)
X			return(ERR);
X		if((nchng = subst(subpat, rhs, gflag, pflag)) < 0)
X			return(ERR);
X		if(nchng)
X			fchanged = TRUE;
X		break;
X
X	case 't':					/* copy lines */
X		if((line3 = getone()) < 0)
X			return(ERR);
X		if(deflt(curln,curln) < 0)
X			return(ERR);
X		if(transfer(line3) < 0)
X			return(ERR);
X		fchanged = TRUE;
X		break;
X
X	case 'u':					/* undo last command */
X		return(ERR);
X		break;
X
X	case 'W':					/* write append */
X	case 'w':					/* write */ 
X		apflg = (c=='W');
X
X		if(*inptr != ' ' && *inptr != HT && *inptr != NL)
X			return(ERR);
X
X		if((fptr = getfn()) == NULL)
X			return(ERR);
X
X		if(deflt(1, lastln) < 0)
X			return(ERR);
X		if(dowrite(line1, line2, fptr, apflg) < 0)
X			return(ERR);
X		fchanged = FALSE;
X		break;
X
X	case 'x':					/* write then quit */
X		if(*inptr == NL && nlines == 0 && !glob)
X		{
X			if((fptr = getfn()) == NULL)
X				return(ERR);
X			if(dowrite(1, lastln, fptr, 0) >= 0)
X				return(EOF);
X		}
X		return(ERR);
X
X	case 'z':					/* print +21, -21, -11.+10 lines */
X		if(deflt(curln,curln) < 0)
X			return(ERR);
X
X		switch(*inptr)
X		{
X		case '-':
X			if(doprnt(line1-21,line1) < 0)
X				return(ERR);
X			break;
X
X		case '.':
X			if(doprnt(line1-11,line1+10) < 0)
X				return(ERR);
X			break;
X
X		case '+':
X		case '\n':
X			if(doprnt(line1,line1+21) < 0)
X				return(ERR);
X			break;
X		}
X		break;
X
X	default:
X		return(ERR);
X	}
X	return (0);
X}
X
Xint dolst(line1, line2) int line1, line2;
X{
X	int oldlflg=lflg, p;
X
X	lflg=1;
X	p=doprnt(line1, line2);
X	lflg=oldlflg;
X
X	return p;
X}
X
Xint donum(line1, line2) int line1, line2;
X{
X	int oldnflg=nflg, p;
X
X	nflg=1;
X	p=doprnt(line1, line2);
X	nflg=oldnflg;
X
X	return p;
X}
X
X/*	dodash.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X
X/*	Expand the set pointed to by *src into dest.
X *	Stop at delim.  Return 0 on error or size of
X *	character class on success.  Update *src to
X *	point at delim.  A set can have one element
X *	{x} or several elements ( {abcdefghijklmnopqrstuvwxyz}
X *	and {a-z} are equivalent ).  Note that the dash
X *	notation is expanded as sequential numbers.
X *	This means (since we are using the ASCII character
X *	set) that a-Z will contain the entire alphabet
X *	plus the symbols: [\]^_`.  The maximum number of
X *	characters in a character class is defined by maxccl.
X */
Xchar *
Xdodash(delim, src, map)
X
Xint	delim;
Xchar	*src, *map;
X{
X
X	register int	first,	last;
X	char		*start;
X
X	start = src;
X
X	while( *src && *src != delim )
X	{
X		if( *src != '-')
X			setbit( esc( &src ), map, 1 );
X
X		else if( src == start || *(src + 1) == delim )
X			setbit( '-', map, 1 );
X		else {
X			src++;
X
X			if( *src < *(src - 2))
X			{
X				first = *src;
X				last = *(src - 2);
X			} else {
X				first = *(src - 2);
X				last = *src;
X			}
X
X			while( ++first <= last )
X				setbit( first, map, 1);
X
X		}
X		src++;
X	}
X	return( src );
X}
X
X/*	doglob.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xdoglob()
X{
X	int	lin, stat;
X	char	*cmd;
X	LINE	*ptr;
X
X	cmd = inptr;
X
X	while(1)
X	{
X		for (lin=1; lin<=lastln; lin++) {
X			ptr = getptr(lin);
X			if (ptr->l_stat & LGLOB) break;
X		}
X		if (lin>lastln) break;
X
X		ptr->l_stat &= ~LGLOB;
X		curln = lin;
X		inptr = cmd;
X		if((stat = getlst()) < 0)
X			return(stat);
X		if((stat = docmd(1)) < 0)
X			return(stat);
X	}
X	return(0);
X}
X
X/*	doprnt.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xdoprnt(from, to)
Xint	from, to;
X{
X	int	i;
X
X	from = from < 1 ? 1 : from;
X	to = to > lastln ? lastln : to;
X		
X	if(to != 0)
X	{
X		for(i = from; i <= to; i++)
X			prntln(gettxt(i), lflg, (nflg ? i : 0));
X		curln = to;
X	}
X
X	return(0);
X}
X
Xvoid prntln(str, vflg, lin)
Xchar	*str;
Xint	vflg, lin;
X{
X	if(lin)
X		printf("%d\t",lin);
X	while(*str && *str != NL)
X	{
X		if(*str < ' ' || *str >= 0x7f)
X		{
X			switch(*str)
X			{
X			case '\t':
X				if(vflg)
X					putcntl(*str, stdout);
X				else
X					putc(*str, stdout);
X				break;
X
X			case DEL:
X				putc('^', stdout);
X				putc('?', stdout);
X				break;
X
X			default:
X				putcntl(*str, stdout);
X				break;
X			}
X		} else
X			putc(*str, stdout);
X		str++;
X	}
X	if(vflg)
X		putc('$',stdout);
X	putc('\n', stdout);
X}
X
Xvoid putcntl(c, stream)
Xchar	c;
XFILE	*stream;
X{
X	putc('^', stream);
X	putc((c&31)|'@@', stream);
X}
X
X/*	doread.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xextern int diag;
X
Xdoread(lin, fname)
Xint	lin;
Xchar	*fname;
X{
X	extern FILE	*fopen();
X	FILE	*fp;
X	int	err;
X	long	bytes;
X	int	lines;
X	static char	str[MAXLINE];
X
X	err = 0;
X	nonascii = nullchar = truncated = 0;
X
X	if (diag) printf("\"%s\" ",fname);
X	if((fp = fopen(fname, "r")) == NULL)
X	{
X		printf("file open err\n");
X		return( ERR );
X	}
X	curln = lin;
X	for(lines = 0, bytes = 0;(err = egets(str,MAXLINE,fp)) > 0;)
X	{
X		bytes += strlen(str);
X		if(ins(str) < 0)
X		{
X			printf("file insert error\n");
X			err++;
X			break;
X		}
X		lines++;
X	}
X	fclose(fp);
X	if(err < 0)
X		return(err);
X	if (diag) {
X		printf("%d lines %d bytes",lines,bytes);
X		if(nonascii)
X			printf(" [%d non-ascii]",nonascii);
X		if(nullchar)
X			printf(" [%d nul]",nullchar);
X		if(truncated)
X			printf(" [%d lines truncated]",truncated);
X		printf("\n");
X	}
X	return( err );
X}
X
X/*	dowrite.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xdowrite(from, to, fname, apflg)
Xint	from, to;
Xchar	*fname;
Xint	apflg;
X{
X	extern FILE	*fopen();
X	FILE	*fp;
X	int	lin, err;
X	int	lines, bytes;
X	char	*str;
X
X	err = 0;
X
X	lines = bytes = 0;
X	if (diag)
X		printf("\"%s\" ",fname);
X	
X	if((fp = fopen(fname,(apflg?"a":"w"))) == NULL)
X	{
X		printf("file open error\n");
X		return( ERR );
X	}
X	for(lin = from; lin <= to; lin++)
X	{
X		str = gettxt(lin);
X		lines++;
X		bytes += strlen(str);
X		if(fputs(str, fp) == EOF)
X		{
X			printf("file write error\n");
X			err++;
X			break;
X		}
X	}
X	if (diag)
X		printf("%d lines %d bytes\n",lines,bytes);
X
X	fclose(fp);
X	return( err );
X}
X
X/*	ed.c	*/
X/*
X * Copyright 1987 Brian Beattie Rights Reserved.
X *
X * Permission to copy and/or distribute granted under the
X * following conditions:
X *
X * 1). No charge may be made other than resonable charges
X *	for reproduction.
X *
X * 2). This notice must remain intact.
X *
X * 3). No further restrictions may be added.
X *
X */
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X#include <setjmp.h>
Xjmp_buf	env;
X
XLINE	line0;
Xint	curln = 0;
Xint	lastln = 0;
Xchar	*inptr;
Xstatic char	inlin[MAXLINE];
Xint	nflg, lflg, pflg, pflag, prompt;
Xint	line1, line2, nlines;
Xextern char	fname[];
Xint	version = 103;
Xint	diag=1;
X
Xvoid intr()
X{
X	printf("?\n");
X	longjmp(env, 1);
X}
X
Xvoid main(argc,argv)
Xint	argc;
Xchar	**argv;
X{
X	int	stat, i, doflush;
X
X	edsetbuf();
X	doflush=isatty(1);
X
X	if (argc>1 && argv[1][0]=='-' && argv[1][1]==0) {
X		diag=0;
X		argc--;
X		argv++;
X	}
X	if(argc > 1)
X	{
X		for(i = 1; i < argc; i++)
X		{
X			if(doread(0,argv[i])==0) {
X				curln = 1;
X				strcpy(fname, argv[i]);
X				break;
X			}
X		}
X	}
X	while(1)
X	{
X		setjmp(env);
X		signal(2, intr);
X
X		if (prompt)
X		{
X			if (nflg) printf("%d",curln);
X			printf("*");
X		}
X
X		if (doflush) fflush(stdout);
X
X		if (fgets(inlin, sizeof(inlin),stdin) == NULL)
X		{
X			break;
X		}
X/*
X		if(*inlin == '!')
X		{
X			for(inptr = inlin; *inptr != NL; inptr++)
X				;
X			*inptr = EOS;
X			system(inlin+1);
X			continue;
X		}
X*/
X		inptr = inlin;
X		if(getlst() >= 0)
X			if((stat = ckglob()) != 0)
X			{
X				if(stat >= 0 && (stat = doglob()) >= 0)
X				{
X					curln = stat;
X					continue;
X				}
X			} else {
X				if((stat = docmd(0)) >= 0)
X				{
X					if(stat == 1)
X						doprnt(curln, curln);
X					continue;
X				}
X			}
X		if(stat == EOF)
X		{
X			exit(0);
X		}
X		if(stat == FATAL)
X		{
X			fputs("FATAL ERROR\n",stderr);
X			exit(1);
X		}
X		printf("?\n");
X	}
X}
X
X/*	egets.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xint	truncflg = 1;	/* truncate long line flag */
Xint	eightbit = 1;	/* save eight bit */
Xint	nonascii, nullchar, truncated;
Xegets(str,size,stream)
Xchar	*str;
Xint	size;
XFILE	*stream;
X{
X	int	c, count;
X	char	*cp;
X
X	for(count = 0, cp = str; size > count;)
X	{
X		c = getc(stream);
X		if(c == EOF)
X		{
X			*cp++ = '\n';
X			*cp = EOS;
X			if(count)
X			{
X				printf("[Incomplete last line]\n");
X			}
X			return(count);
X		}
X		if(c == NL)
X		{
X			*cp++ = c;
X			*cp = EOS;
X			return(++count);
X		}
X		if(c > 127)
X		{
X			if(!eightbit)		/* if not saving eighth bit */
X				c = c&127;	/* strip eigth bit */
X			nonascii++;		/* count it */
X		}
X		if(c)
X		{
X			*cp++ = c;	/* not null, keep it */
X			count++;
X		} else 
X			nullchar++;	/* count nulls */
X	}
X	str[count-1] = EOS;
X	if(c != NL)
X	{
X		printf("truncating line\n");
X		truncated++;
X		while((c = getc(stream)) != EOF)
X			if(c == NL)
X				break;
X	}
X	return(count);
X}
X
X/*	esc.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X
X/* Map escape sequences into their equivalent symbols.  Returns the
X * correct ASCII character.  If no escape prefix is present then s
X * is untouched and *s is returned, otherwise **s is advanced to point
X * at the escaped character and the translated character is returned.
X */
Xesc(s)
Xchar	**s;
X{
X	register int	rval;
X
X	
X	if (**s != ESCAPE)
X	{
X		rval = **s;
X	} else {
X		(*s)++;
X
X		switch(toupper(**s))
X		{
X		case '\000':
X			rval = ESCAPE;	break;
X		case 'S':
X			rval = ' ';	break;
X		case 'N':
X			rval = '\n';	break;
X		case 'T':
X			rval = '\t';	break;
X		case 'B':
X			rval = '\b';	break;
X		case 'R':
X			rval = '\r';	break;
X		default:
X			rval = **s;	break;
X		}
X	}
X
X	return (rval);
X}
X
X/*	find.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xfind(pat, dir)
XTOKEN	*pat;
Xint	dir;
X{
X	int	i, num;
X	char	*lin;
X
X	num=curln;
X	for(i=0; i<lastln; i++)
X	{
X		lin = gettxt(num);
X		if(matchs(lin, pat, 0))
X		{
X			return(num);
X		}
X		num = (dir ? nextln(num) : prevln(num));
X	}
X	return ( ERR );
X}
X
X/*	getfn.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xextern char	fname[MAXFNAME];
Xint nofname;
X
Xchar	*
Xgetfn()
X{
X	static char	file[256];
X	char	*cp;
X
X	if(*inptr == NL)
X	{
X		nofname=TRUE;
X		strcpy(file, fname);
X	} else {
X		nofname=FALSE;
X		while(*inptr == SP || *inptr == HT)
X			inptr++;
X
X		cp = file;
X		while(*inptr && *inptr != NL && *inptr != SP && *inptr != HT)
X		{
X			*cp++ = *inptr++;
X		}
X		*cp = '\0';
X
X		if(strlen(file) == 0)
X		{
X			printf("bad file name\n");
X			return( NULL );
X		}
X	}
X
X	if(strlen(file) == 0)
X	{
X		printf("no file name\n");
X		return(NULL);
X	}
X	return( file );
X}
X
X/*	getlst.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xgetlst()
X{
X	int	num;
X
X	line2 = 0;
X	for(nlines = 0; (num = getone()) >= 0;)
X	{
X		line1 = line2;
X		line2 = num;
X		nlines++;
X		if(*inptr != ',' && *inptr != ';')
X			break;
X		if(*inptr == ';')
X			curln = num;
X		inptr++;
X	}
X	nlines = min(nlines, 2);
X	if(nlines == 0)
X		line2 = curln;
X	if(nlines <= 1)
X		line1 = line2;
X
X	if(num == ERR)
X		return(num);
X	else
X		return(nlines);
X}
X
X/*	getnum.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xint mark['z'-'a'+1];
X
Xgetnum(first) int first;
X{
X	TOKEN	*srchpat;
X	int	num;
X	char	c;
X
X	while(*inptr == SP || *inptr == HT)
X		inptr++;
X
X	if(*inptr >= '0' && *inptr <= '9')	/* line number */
X	{
X		for(num = 0; *inptr >= '0' && *inptr <= '9';)
X		{
X			num = (num * 10) + *inptr - '0';
X			inptr++;
X		}
X		return num;
X	}
X
X	switch(c = *inptr)
X	{
X	case '.':
X		inptr++;
X		return (curln);
X
X	case '$':
X		inptr++;
X		return (lastln);
X
X	case '/':
X	case '?':
X		srchpat = optpat();
X		if(*inptr == c)
X			inptr++;
X		return(find(srchpat,c == '/'?1:0));
X
X	case '-':
X	case '+':
X		return(first ? curln : 1);
X
X	case '\'':
X		inptr++;
X		if (*inptr < 'a' || *inptr > 'z')
X			return(EOF);
X
X		return mark[ *inptr++ - 'a' ];
X
X	default:
X		return ( first ? EOF : 1 );	/* unknown address */
X	}
X}
X
X/*	getone.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
X#define FIRST 1
X#define NOTFIRST 0
X
Xgetone()
X{
X	int	c, i, num;
X
X	if((num = getnum(FIRST)) >= 0)
X	{
X		while(1)
X		{
X			while(*inptr == SP || *inptr == HT)
X				inptr++;
X
X			if(*inptr != '+' && *inptr != '-')
X				break;
X                        c = *inptr++;
X
X			if((i = getnum(NOTFIRST)) < 0)
X				return ( i );
X
X			if(c == '+')
X			{
X				num += i;
X			} else {
X				num -= i;
X			}
X		}
X	}
X	return ( num>lastln ? ERR : num );
X}
X
X/*	getpat.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X
X/* Translate arg into a TOKEN string */
XTOKEN	*
Xgetpat (arg)
Xchar	*arg;
X{
X	
X	return (makepat(arg, '\000'));
X}
X
X/*	getptr.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
XLINE	*
Xgetptr(num)
Xint	num;
X{
X	LINE	*ptr;
X	int	j;
X
X	if (2*num>lastln && num<=lastln) {	/* high line numbers */
X		ptr = line0.l_prev;
X		for (j = lastln; j>num; j--)
X			ptr = ptr->l_prev;
X	} else {				/* low line numbers */
X		ptr = &line0;
X		for(j = 0; j < num; j++)
X			ptr = ptr->l_next;
X	}
X	return(ptr);
X}
X
X/*	getrhs.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xgetrhs(sub)
Xchar	*sub;
X{
X	if(inptr[0] == NL || inptr[1] == NL)	/* check for eol */
X		return( ERR );
X
X	if(maksub(sub, MAXPAT) == NULL)
X		return( ERR );
X	
X	inptr++;		/* skip over delimter */
X	while(*inptr == SP || *inptr == HT)
X			inptr++;
X	if(*inptr == 'g')
X	{
X		inptr++;
X		return( 1 );
X	}
X	return( 0 );
X}
X
X/*	gettxt.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xchar	*
Xgettxt(num)
Xint	num;
X{
X	LINE	*lin;
X	static char	txtbuf[MAXLINE];
X
X	lin = getptr(num);
X	strcpy(txtbuf,lin->l_buff);
X	strcat(txtbuf,"\n");
X	return(txtbuf);
X}
X
X/*	ins.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xins(str)
Xchar	*str;
X{
X	char	buf[MAXLINE], *cp;
X	LINE	*new, *cur, *nxt;
X
X	cp = buf;
X	while(1)
X	{
X		if((*cp = *str++) == NL)
X			*cp = EOS;
X		if(*cp)
X		{
X			cp++;
X			continue;
X		}
X		if((new = (LINE *)malloc(sizeof(LINE)+strlen(buf))) == NULL)
X			return( ERR ); 	/* no memory */
X
X		new->l_stat=0;
X		strcpy(new->l_buff,buf);	/* build new line */
X		cur = getptr(curln);		/* get current line */
X		nxt = getptr(nextln(curln));	/* get next line */
X		relink(cur, new, new, nxt);	/* add to linked list */
X		relink(new, nxt, cur, new);
X		lastln++;
X		curln++;
X
X		if(*str == EOS)		/* end of line ? */
X			return( 1 );
X
X		cp = buf;
X	}
X}
X
X/*	join.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xextern int fchanged;
X
Xjoin(first, last)
Xint first, last;
X{
X	char buf[MAXLINE];
X	char *cp=buf, *str;
X	int num;
X
X	if (first<=0 || first>last || last>lastln)
X		return(ERR);
X	if (first==last) {
X		curln=first;
X		return 0;
X	}
X	for (num=first; num<=last; num++) {
X		str=gettxt(num);
X
X		while (*str!=NL && cp<buf+MAXLINE-1) *cp++ = *str++;
X
X		if (cp==buf+MAXLINE-1) {
X			printf("line too long\n");
X			return(ERR);
X		}
X	}
X	*cp++ = NL;
X	*cp = EOS;
X	del(first, last);
X	curln=first-1;
X	ins(buf);
X	fchanged = TRUE;
X	return 0;
X}
X
X/*	makepat.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X
X/*
X * Make a pattern template from the strinng pointed to by arg.  Stop
X * when delim or '\000' or '\n' is found in arg.  Return a pointer to
X * the pattern template.
X *
X * The pattern template used here are somewhat different than those
X * used in the "Software Tools" book; each token is a structure of
X * the form TOKEN (see tools.h).  A token consists of an identifier,
X * a pointer to a string, a literal character and a pointer to another
X * token.  This last is 0 if there is no subsequent token.
X *
X * The one strangeness here is caused (again) by CLOSURE which has
X * to be put in front of the previous token.  To make this insertion a
X * little easier, the 'next' field of the last to point at the chain
X * (the one pointed to by 'tail) is made to point at the previous node.
X * When we are finished, tail->next is set to 0.
X */
XTOKEN *
Xmakepat(arg, delim)
Xchar	*arg;
Xint	delim;
X{
X	 TOKEN	*head, *tail, *ntok;
X	 int	error;
X
X	/*
X	 * Check for characters that aren't legal at the beginning of
X	 * a template.
X	 */
X
X	if (*arg=='\0' || *arg==delim || *arg=='\n' || *arg==CLOSURE)
X		return(0);
X
X	error = 0;
X	tail = head = NULL;
X
X	while (*arg && *arg != delim && *arg != '\n' && !error)
X	{
X		ntok = (TOKEN *)malloc(TOKSIZE);
X		ntok->lchar = '\000';
X		ntok->next = 0;
X
X		switch(*arg)
X		{
X		case ANY:
X			ntok->tok = ANY;
X			break;
X
X		case BOL:
X			if (head == 0)	/* then this is the first symbol */
X				ntok->tok = BOL;
X			else
X				ntok->tok = LITCHAR;
X				ntok->lchar = BOL;
X			break;
X
X		case EOL:
X			if(*(arg+1) == delim || *(arg+1) == '\000' ||
X					*(arg+1) == '\n')
X			{
X				ntok->tok = EOL;
X			} else {
X				ntok->tok = LITCHAR;
X				ntok->lchar = EOL;
X			}
X			break;
X
X		case CLOSURE:
X			if (head != 0)
X			{
X				switch (tail->tok)
X				{
X				case BOL:
X				case EOL:
X				case CLOSURE:
X					return (0);
X				
X				default:
X					ntok->tok = CLOSURE;
X				}
X			}
X			break;
X
X		case CCL:
X
X			if(*(arg + 1) == NEGATE)
X			{
X				ntok->tok = NCCL;
X				arg += 2;
X			} else {
X				ntok->tok = CCL;
X				arg++;
X			}
X
X			if( ntok->bitmap = makebitmap(CLS_SIZE) )
X				arg = dodash(CCLEND, arg, ntok->bitmap );
X			else {
X				fprintf(stderr,"Not enough memory for pat\n");
X				error = 1;
X			}
X			break;
X
X		default:
X			if (*arg == ESCAPE && *(arg+1) == OPEN) {
X				ntok->tok = OPEN;
X				arg++;
X			} else
X			if (*arg == ESCAPE && *(arg+1) == CLOSE) {
X				ntok->tok = CLOSE;
X				arg++;
X			} else {
X				ntok->tok = LITCHAR;
X				ntok->lchar = esc(&arg);
X			}
X		}
X
X		if (error || ntok == 0)
X		{
X			unmakepat(head);
X			return (0);
X		} else if (head == 0)
X		{
X				/* This is the first node in the chain. */
X			
X			ntok->next = 0;
X			head = tail = ntok;
X		} else if (ntok->tok != CLOSURE)
X		{
X			/* Insert at end of list (after tail) */
X
X			tail->next = ntok;
X			ntok->next = tail;
X			tail = ntok;
X		} else if (head != tail)
X		{
X			/*
X			 * More than one node in the chain.  Insert the
X			 * CLOSURE node immediately in front of tail.
X			 */
X			
X			(tail->next)->next = ntok;
X			ntok->next = tail;
X		} else {
X			/*
X			 * Only one node in the chain,  Insert the CLOSURE
X			 * node at the head of the linked list.
X			 */
X			
X			ntok->next = head;
X			tail->next = ntok;
X			head = ntok;
X		}
X		arg++;
X	}
X
X	tail->next = 0;
X	return (head);
X}
X
X/*	maksub.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xchar	*
Xmaksub(sub, subsz)
Xchar	*sub;
Xint	subsz;
X{
X	int	size;
X	char	delim, *cp;
X
X	size = 0;
X	cp = sub;
X
X	delim = *inptr++;
X	for(size = 0; *inptr != delim && *inptr != NL && size < subsz; size++)
X	{
X		if(*inptr == '&')
X		{
X			*cp++ = DITTO;
X			inptr++;
X		} else
X		if((*cp++ = *inptr++) == ESCAPE)
X		{
X			if (size>=subsz) return(NULL);
X
X			switch(toupper(*inptr))
X			{
X			case NL:
X				*cp++ = ESCAPE;
X				break;
X			case 'S':
X				*cp++ = SP;
X				inptr++;
X				break;
X			case 'N':
X				*cp++ = NL;
X				inptr++;
X				break;
X			case 'T':
X				*cp++ = HT;
X				inptr++;
X				break;
X			case 'B':
X				*cp++ = BS;
X				inptr++;
X				break;
X			case 'R':
X				*cp++ = CR;
X				inptr++;
X				break;
X			case '0': {
X				int i=3;
X				*cp = 0;
X				do {
X					if (*++inptr<'0' || *inptr >'7')
X						break;
X
X					*cp = (*cp<<3) | (*inptr-'0');
X				} while (--i!=0);
X				cp++;
X				} break;
X			default:
X				*cp++ = *inptr++;
X				break;
X			}
X		}
X	}
X	if(size >= subsz)
X		return( NULL );
X
X	*cp = EOS;
X	return( sub );
X}
X
X/*	matchs.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X
X/*
X * Compares line and pattern.  Line is a character string while pat
X * is a pattern template made by getpat().
X * Returns:
X *	1. A zero if no match was found.
X *
X *	2. A pointer to the last character satisfing the match
X *	   if ret_endp is non-zero.
X *
X *	3. A pointer to the beginning of the matched string if
X *	   ret_endp is zero.
X *
X * e.g.:
X *
X *	matchs ("1234567890", getpat("4[0-9]*7), 0);
X * will return a pointer to the '4', while:
X *
X *	matchs ("1234567890", getpat("4[0-9]*7), 1);
X * will return a pointer to the '7'.
X */
Xchar	*
Xmatchs(line, pat, ret_endp)
Xchar	*line;
XTOKEN	*pat;
Xint	ret_endp;
X{
X
X	char	*rval, *bptr;
X
X	bptr = line;
X
X	while(*line)
X	{
X		if ((rval = amatch(line, pat, bptr)) == 0)
X		{
X			line++;
X		} else {
X			if(rval > bptr && rval > line)
X				rval--;	/* point to last char matched */
X			rval = ret_endp ? rval : line;
X			break;
X		}
X	}
X	return (rval);
X}
X
X/*	move.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xmove(num)
Xint	num;
X{
X	LINE	*k0, *k1, *k2, *k3;
X
X	if(line1 <= 0 || line2 < line1 || line1 <= num && num <= line2)
X		return( ERR );
X	k0 = getptr(prevln(line1));
X	k1 = getptr(line1);
X	k2 = getptr(line2);
X	k3 = getptr(nextln(line2));
X 	lastln -= line2-line1+1;
X
X	relink(k0, k3, k0, k3);
X
X	if (num > line1)
X		num -= line2-line1+1;
X
X	curln = num + (line2 - line1 + 1);
X
X	k0 = getptr(num);
X	k3 = getptr(nextln(num));
X 	lastln += line2-line1+1;
X
X	relink(k0, k1, k2, k3);
X	relink(k2, k3, k0, k1);
X
X	return( 1 );
X}
X
Xint transfer(num)
Xint num;
X{
X	int mid, lin, ntrans;
X
X	if (line1<=0 || line1>line2)
X		return(ERR);
X
X	mid= num<line2 ? num : line2;
X
X	curln=num;
X	ntrans=0;
X
X	for (lin=line1; lin<=mid; lin++) {
X		ins(gettxt(lin));
X		ntrans++;
X	}
X	lin+=ntrans;
X	line2+=ntrans;
X
X	for ( ; lin<=line2; lin+=2) {
X		ins(gettxt(lin));
X		line2++;
X	}
X	return(1);
X}
X
X/*	omatch.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X
X/*
X * Match one pattern element, pointed at by pat, with the character at
X * **linp.  Return non-zero on match.  Otherwise, return 0.  *Linp is
X * advanced to skip over the matched character; it is not advanced on
X * failure.  The amount of advance is 0 for patterns that match null
X * strings, 1 otherwise.  "boln" should point at the position that will
X * match a BOL token.
X */
Xomatch(linp, pat, boln)
Xchar	**linp;
XTOKEN	*pat;
Xchar	*boln;
X{
X	
X	register int	advance;
X
X	advance = -1;
X
X	if (**linp)
X	{
X		switch (pat->tok)
X		{
X		case LITCHAR:
X			if (**linp == pat->lchar)
X				advance = 1;
X			break;
X
X		case BOL:
X			if (*linp = boln)
X				advance = 0;
X			break;
X
X		case ANY:
X			if (**linp != '\n')
X				advance = 1;
X			break;
X
X		case EOL:
X			if (**linp == '\n')
X				advance = 0;
X			break;
X
X		case CCL:
X			if( testbit( **linp, pat->bitmap))
X				advance = 1;
X			break;
X
X		case NCCL:
X			if (!testbit (**linp, pat->bitmap))
X				advance = 1;
X			break;
X		}
X	}
X	if (advance >= 0)
X		*linp += advance;
X
X	return (++advance);
X}
X
X/*	optpat.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
XTOKEN	*oldpat;
X
XTOKEN	*
Xoptpat()
X{
X	char	delim, str[MAXPAT], *cp;
X
X	delim = *inptr++;
X	cp = str;
X	while(*inptr != delim && *inptr != NL)
X	{
X		if(*inptr == ESCAPE && inptr[1] != NL)
X			*cp++ = *inptr++;
X		*cp++ = *inptr++;
X	}
X
X	*cp = EOS;
X	if(*str == EOS)
X		return(oldpat);
X	if(oldpat)
X		unmakepat(oldpat);
X	oldpat=getpat(str);
X	return(oldpat);
X}
X
X/*	set.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xstruct tbl {
X	char	*t_str;
X	int	*t_ptr;
X	int	t_val;
X} *t, tbl[] = {
X	"number",	&nflg,		TRUE,
X	"nonumber",	&nflg,		FALSE,
X	"list",		&lflg,		TRUE,
X	"nolist",	&lflg,		FALSE,
X	"eightbit",	&eightbit,	TRUE,
X	"noeightbit",	&eightbit,	FALSE,
X	"prompt",	&prompt,	TRUE,
X	"noprompt",	&prompt,	FALSE,
X	0
X};
X
Xset()
X{
X	char	word[16];
X	int	i;
X
X	inptr++;
X	if(*inptr != 't')
X	{
X		if(*inptr != SP && *inptr != HT && *inptr != NL)
X			return(ERR);
X	} else
X		inptr++;
X
X	if(*inptr == NL)
X		return(show("all"));
X		/* skip white space */
X	while(*inptr == SP || *inptr == HT)
X		inptr++;
X
X	for(i = 0; *inptr != SP && *inptr != HT && *inptr != NL;)
X		word[i++] = *inptr++;
X	word[i] = EOS;
X	for(t = tbl; t->t_str; t++)
X	{
X		if(strcmp(word,t->t_str) == 0)
X		{
X			*t->t_ptr = t->t_val;
X			return(0);
X		}
X	}
X}
X
Xshow()
X{
X	extern int	version;
X
X	printf("ed version %d.%d\n",version/100,version%100);
X	printf("number %s, ",nflg?"ON":"OFF");
X	printf("list %s, ",lflg?"ON":"OFF");
X	printf("prompt %s,\n",prompt?"ON":"OFF");
X	return(0);
X}
X
X/*	setbuf.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xvoid relink(a, x, y, b)
XLINE	*a, *x, *y, *b;
X{
X	x->l_prev = a;
X	y->l_next = b;
X}
X
Xvoid clrbuf()
X{
X	del(1, lastln);
X}
X
Xvoid edsetbuf()
X{
X	relink(&line0, &line0, &line0, &line0);
X	curln = lastln = 0;
X}
X
X/*	subst.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X/* #include "ed.h" */
X
Xsubst(pat, sub, gflg, pflag)
XTOKEN	*pat;
Xchar	*sub;
Xint	gflg, pflag;
X{
X	int	lin, chngd, nchngd;
X	char	*txtptr, *txt;
X	char	*lastm, *m, *new, buf[MAXLINE];
X
X	if(line1 <= 0)
X		return( ERR );
X	nchngd = 0;		/* reset count of lines changed */
X	for(lin = line1; lin <= line2; lin++)
X	{
X		txt = txtptr = gettxt(lin);
X		new = buf;
X		chngd = 0;
X		lastm = NULL;
X		while(*txtptr)
X		{
X			if(gflg || !chngd)
X				m = amatch(txtptr, pat, txt);
X			else
X				m = NULL;
X			if(m != NULL && lastm != m)
X			{
X				chngd++;
X				new = catsub(txtptr, m, sub, new,
X						buf+MAXLINE);
X				lastm = m;
X			}
X			if(m == NULL || m == txtptr)
X			{
X				*new++ = *txtptr++;
X			} else {
X				txtptr = m;
X			}
X		}
X		if(chngd)
X		{
X			if(new >= buf+MAXLINE)
X				return( ERR );
X			*new++ = EOS;
X			del(lin,lin);
X			ins(buf);
X			nchngd++;
X			if(pflag)
X				doprnt(curln, curln);
X		}
X	}
X	if(nchngd == 0 && !gflg)
X	{
X		return(ERR);
X	}
X	return( nchngd );
X}
X
X#if 0
X/*	system.c	*/
X#define SHELL	"/bin/sh"
X
Xsystem(c)
Xchar *c; {
X	int pid, status;
X	
X	switch (pid = fork()) {
X	case -1:
X		return -1;
X	case 0:
X		execl(SHELL, "sh", "-c", c, (char *) 0);
X		exit(-1);
X	default:
X		while (wait(&status) != pid)
X			;
X	}
X	return status;
X}
X#endif
X
X/*	unmkpat.c	*/
X/* #include <stdio.h> */
X/* #include "tools.h" */
X
X/* Free up the memory usde for token string */
Xvoid unmakepat(head)
XTOKEN	*head;
X{
X
X	register TOKEN	*old_head;
X
X	while (head)
X	{
X		switch (head->tok)
X		{
X		case CCL:
X		case NCCL:
X			free(head->bitmap);
X				/* fall through to default */
X
X		default:
X			old_head = head;
X			head = head->next;
X			free (old_head);
X			break;
X		}
X	}
X}
X
Xisatty(fd)
Xint		fd;
X{
X	long IsInteractive();
X	struct UFB	*ufb;
X
X	ufb = chkufb(fd);
X	if (ufb == NULL)
X		return(-1);
X	return(IsInteractive(ufb->ufbfh) != 0);
X}
X@
X
X
X1.4
Xlog
X@More amiga changes
X@
Xtext
X@d3 2
Xd36 1
Xd41 1
Xa41 1
X"$Header: Rodime:ricks/ked2/ked2.c,v 1.3 89/09/01 11:02:22 rick Exp Locker: rick $";
Xd144 1
Xa144 1
Xextern	int	unmakepat();
Xa153 2
X#define max(a,b)	((a>b)?a:b)
X#define min(a,b)	((a<b)?a:b)
Xd201 1
Xa229 1
X	register i;
Xd594 1
Xd614 1
Xa614 1
X	int	i, apflg, pflag, gflag;
Xd1056 1
Xa1056 1
Xprntln(str, vflg, lin)
Xd1093 1
Xa1093 1
Xputcntl(c, stream)
Xd1234 1
Xa1234 1
Xintr()
Xd1240 1
Xa1240 1
Xmain(argc,argv)
Xd1244 1
Xa1244 1
X	int	stat, i, j, doflush;
Xd1246 1
Xa1246 1
X	setbuf();
Xa1809 1
X	 char	buf[CLS_SIZE];
Xd2297 1
Xa2297 1
Xrelink(a, x, y, b)
Xd2304 1
Xa2304 1
Xclrbuf()
Xd2309 1
Xa2309 1
Xint setbuf()
Xd2404 1
Xa2404 1
Xunmakepat(head)
Xd2428 5
Xd2434 5
X@
X
X
X1.3
Xlog
X@Amiga changes
X@
Xtext
X@d38 1
Xa38 1
X"$Header: Quantum:ricks/ked2/ed.c,v 1.1 89/08/27 17:44:11 rick Exp Locker: rick $";
Xd1309 1
Xa1309 1
X			_cleanup(); exit(0);
Xd1314 1
Xa1314 1
X			_cleanup(); exit(1);
X@
X
X
X1.2
Xlog
X@No changes
X@
Xtext
X@d1280 1
Xd1289 1
Xd2308 1
Xa2308 1
Xvoid setbuf()
Xd2376 1
Xd2396 1
X@
X
X
X1.1
Xlog
X@Initial revision
X@
Xtext
X@d38 1
Xa38 1
X"$Header: ed.c,v 1.6 88/05/23 16:47:56 dnix Exp $";
X@
SHAR_EOF
if `test ! -d rcs`
then
  mkdir rcs
  echo "mkdir rcs"
fi
echo "extracting rcs/readme"
sed 's/^X//' << \SHAR_EOF > rcs/readme
XThe source code for RCS is distrubuted as RCSfiles. This is so that you will
Xhave the original sources and the current Amiga sources (and intermediate
Xversions). It also provides a collection of RCSfiles that newcommers to RCS
Xcan play with to learn what RCS does.
X
X
X					Ray
SHAR_EOF
if `test ! -d rcs/rcs.rcsfiles`
then
  mkdir rcs/rcs.rcsfiles
  echo "mkdir rcs/rcs.rcsfiles"
fi
echo "extracting rcs/rcs.rcsfiles/maketime.c,v"
sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/maketime.c,v
Xhead     1.8;
Xbranch   1.8.2;
Xaccess   ;
Xsymbols  amiga_rcs:1.8.2 cbmvax_source:1.8.1 uunet_june89_dist:1.8;
Xlocks    ; strict;
Xcomment  @ * @;
X
X
X1.8
Xdate     88.11.08.13.54.53;  author narten;  state Exp;
Xbranches 1.8.1.1 1.8.2.1;
Xnext     ;
X
X1.8.1.1
Xdate     89.08.11.01.41.52;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X1.8.2.1
Xdate     89.10.13.19.17.37;  author rsbx;  state Exp;
Xbranches ;
Xnext     1.8.2.2;
X
X1.8.2.2
Xdate     89.10.15.15.43.22;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X
Xdesc
X@derive 32-bit time value from TM structure.
X@
X
X
X
X1.8
Xlog
X@checked in with -k by rsbx at 89.08.10.16.02.32.
X@
Xtext
X@#
X/*
X * MAKETIME		derive 32-bit time value from TM structure.
X *
X * Usage:
X *	long t,maketime();
X *	struct tm *tp;	Pointer to TM structure from <time.h>
X *			NOTE: this must be extended version!!!
X *	t = maketime(tp);
X *
X * Returns:
X *	0 if failure; parameter out of range or nonsensical.
X *	else long time-value.
X * Notes:
X *	This code is quasi-public; it may be used freely in like software.
X *	It is not to be sold, nor used in licensed software without
X *	permission of the author.
X *	For everyone's benefit, please report bugs and improvements!
X * 	Copyright 1981 by Ken Harrenstien, SRI International.
X *	(ARPANET: KLH @@ SRI)
X */
X#ifndef lint
Xstatic char rcsid[]= "$Id: maketime.c,v 1.8 88/11/08 13:54:53 narten Exp $";
X#endif
X/* $Log:	maketime.c,v $
X * Revision 1.8  88/11/08  13:54:53  narten
X * allow negative timezones (-24h <= x <= 24h)
X * 
X * Revision 1.7  88/11/08  12:02:24  narten
X * changes from  eggert@@sm.unisys.com (Paul Eggert)
X * 
X * Revision 1.7  88/08/28  14:47:52  eggert
X * Allow cc -R.  Remove unportable "#endif XXX"s.
X * 
X * Revision 1.6  87/12/18  17:05:58  narten
X * include rcsparam.h
X * 
X * Revision 1.5  87/12/18  11:35:51  narten
X * maketime.c: fixed USG code - you have tgo call "tzset" in order to have
X * "timezone" set. ("localtime" calls it, but it's probably better not to 
X * count on "localtime" having been called.)
X * 
X * Revision 1.4  87/10/18  10:26:57  narten
X * Updating version numbers. Changes relative to 1.0 are actually 
X * relative to 1.2
X * 
X * Revision 1.3  87/09/24  13:58:45  narten
X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
X * warnings)
X * 
X * Revision 1.2  87/03/27  14:21:48  jenkins
X * Port to suns
X * 
X * Revision 1.1  84/01/23  14:50:04  kcs
X * Initial revision
X * 
X * Revision 1.2  83/12/05  10:12:56  wft
X * added cond. compilation for USG Unix; long timezone;
X * 
X * Revision 1.1  82/05/06  11:38:00  wft
X * Initial revision
X * 
X */
X
X
X#include "rcsbase.h"
X#include "time.h"
X
Xint daytb[] = {   /* # days in year thus far, indexed by month (0-12!!) */
X	0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
X};
X
Xstruct tm *localtime();
Xlong	time();
X
Xlong maketime(atm)
Xstruct tm *atm;
X{	register struct tm *tp;
X	register int i;
X	int year, yday, mon, day, hour, min, sec, zone, dst, leap;
X	long tres, curtim;
X
X	VOID time(&curtim);
X	tp = localtime(&curtim);        /* Get breakdowns of current time */
X	year = tp->tm_year;		/* Use to set up defaults */
X	mon = tp->tm_mon;
X	day = tp->tm_mday;
X
X
X#ifdef DEBUG
Xprintf("first YMD: %d %d %d, T=%ld\n",year,mon,day,tres);
X#endif
X	tp = atm;
X
X	/* First must find date, using specified year, month, day.
X	 * If one of these is unspecified, it defaults either to the
X	 * current date (if no more global spec was given) or to the
X	 * zero-value for that spec (i.e. a more global spec was seen).
X	 * Start with year... note 32 bits can only handle 135 years.
X	 */
X	if(tp->tm_year != TMNULL)
X	  {	if((year = tp->tm_year) >= 1900)	/* Allow full yr # */
X	  		year -= 1900;			/* by making kosher */
X		mon = 0;		/* Since year was given, default */
X		day = 1;		/* for remaining specs is zero */
X	  }
X	if(year < 70 || 70+134 < year )	/* Check range */
X		return(0);		/* ERR: year out of range */
X	leap = year&03 ? 0 : 1;		/* See if leap year */
X	year -= 70;			/* UNIX time starts at 1970 */
X
X	/*
X	 * Find day of year.
X	 * YDAY is used only if it exists and either the month or day-of-month
X	 * is missing.
X	 */
X	if (tp->tm_yday != TMNULL
X	 && (tp->tm_mon == TMNULL || tp->tm_mday == TMNULL))
X		yday = tp->tm_yday;
X	else
X	  {	if(tp->tm_mon  != TMNULL)
X		  {	mon = tp->tm_mon;	/* Month was specified */
X			day = 1;		/* so set remaining default */
X		  }
X		if(mon < 0 || 11 < mon) return(0);	/* ERR: bad month */
X		if(tp->tm_mday != TMNULL) day = tp->tm_mday;
X		if(day < 1
X		 || (((daytb[mon+1]-daytb[mon]) < day)
X			&& (day!=29 || mon!=1 || !leap) ))
X				return(0);		/* ERR: bad day */
X		yday = daytb[mon]	/* Add # of days in months so far */
X		  + ((leap		/* Leap year, and past Feb?  If */
X		      && mon>1)? 1:0)	/* so, add leap day for this year */
X		  + day-1;		/* And finally add # days this mon */
X
X                if (tp->tm_yday != TMNULL       /* Confirm that YDAY correct */
X                 && tp->tm_yday != yday) return(0);     /* ERR: conflict */
X	  }
X	if(yday < 0 || (leap?366:365) <= yday)
X		return(0);		/* ERR: bad YDAY or maketime bug */
X
X	tres = year*365			/* Get # days of years so far */
X		+ ((year+1)>>2)		/* plus # of leap days since 1970 */
X		+ yday;			/* and finally add # days this year */
X
X        if((i = tp->tm_wday) != TMNULL) /* Check WDAY if present */
X                if(i < 0 || 6 < i       /* Ensure within range */
X                  || i != (tres+4)%7)   /* Matches? Jan 1,1970 was Thu = 4 */
X                        return(0);      /* ERR: bad WDAY */
X
X#ifdef DEBUG
Xprintf("YMD: %d %d %d, T=%ld\n",year,mon,day,tres);
X#endif
X	/*
X	 * Now determine time.  If not given, default to zeros
X	 * (since time is always the least global spec)
X	 */
X	tres *= 86400L;			/* Get # seconds (24*60*60) */
X	hour = min = sec = 0;
X	if(tp->tm_hour != TMNULL) hour = tp->tm_hour;
X	if(tp->tm_min  != TMNULL) min  = tp->tm_min;
X	if(tp->tm_sec  != TMNULL) sec  = tp->tm_sec;
X	if( min < 0 || 60 <= min
X	 || sec < 0 || 60 <= sec) return(0);	/* ERR: MS out of range */
X	if(hour < 0 || 24 <= hour)
X		if(hour != 24 || (min+sec) !=0)	/* Allow 24:00 */
X			return(0);		/* ERR: H out of range */
X
X	/* confirm AM/PM if there */
X	switch(tp->tm_ampm)
X	  {	case 0: case TMNULL:	/* Ignore these values */
X			break;
X		case 1:			/* AM */
X		case 2:			/* PM */
X			if(hour > 12) return(0);  /* ERR: hrs 13-23 bad */
X			if(hour ==12) hour = 0;	/* Modulo 12 */
X			if(tp->tm_ampm == 2)	/* If PM, then */
X				hour += 12;	/*   get 24-hour time */
X			break;
X		default: return(0);	/* ERR: illegal TM_AMPM value */
X	  }
X
X	tres += sec + 60L*(min + 60L*hour);	/* Add in # secs of time */
X
X#ifdef DEBUG
Xprintf("HMS: %d %d %d T=%ld\n",hour,min,sec,tres);
X#endif
X	/*
X	 * We now have the GMT date/time and must make final
X	 * adjustment for the specified time zone.  If none is specified,
X	 * the local time-zone is assumed.
X	 */
X	if((zone = tp->tm_zon) == TMNULL	/* If unspecified */
X	 || (zone == 1))			/* or local-zone requested */
X		zone = localzone();		/* then set to local zone */
X	if(zone < -24*60 || 24*60 <= zone)
X		return(0);			/* ERR: zone out of range */
X
X	/* See if must apply Daylight Saving Time shift.
X	 * Note that if DST is specified, validity is not checked.
X	 */
X	if((dst = tp->tm_isdst) == TMNULL)	/* Must we figure it out? */
X	  {	curtim = tres +localzone()*60L;	/* Yuck.  Get equiv local */
X		dst = localtime(&curtim)->tm_isdst;     /* time, and ask. */
X	  }
X	tres += zone*60L -(dst?3600:0);	/* Add in # seconds of zone adj */
X
X	return(tres);
X}
X
X
X/* LOCALZONE		return local timezone in # mins west of GMT
X *
X */
X
X#if defined(V6) || defined(USG)
Xextern long timezone;
X#else
X#include <sys/types.h>
X#include <sys/timeb.h>
X#endif
X
Xstatic int lclzon;
Xlocalzone()
X{
X    if (!lclzon) {
X#if defined(V6) || defined(USG)
X#ifdef USG
X	tzset();
X#endif
X	lclzon = timezone/60 + 1;
X#else
X	struct timeb tb;
X
X	ftime(&tb);
X	lclzon = tb.timezone + 1;
X
X#endif
X    }
X    return lclzon - 1;
X}
X@
X
X
X1.8.2.1
Xlog
X@Start of Amiga RCS port branch.
X@
Xtext
X@d23 1
Xa23 5
X<<<<<<< maketime.c
Xstatic char rcsid[]= "$Id: maketime.c,v 1.8.1.1 89/08/11 01:41:52 rsbx Exp Locker: rsbx $";
X=======
Xstatic char rcsid[]= "$Id: maketime.c,v 1.2 89/09/17 13:34:45 rick Exp $";
X>>>>>>> 1.2
Xa25 11
X<<<<<<< maketime.c
X * Revision 1.8.1.1  89/08/11  01:41:52  rsbx
X * Start of cbmvax RCS source branch.
X=======
X * Revision 1.2  89/09/17  13:34:45  rick
X * Port to AmigaDos done by Rick Schaeffer (ricks@@iscuva.iscs.com)
X * All changes done with conditional compile (#ifdef AMIGA).  This version
X * compiles correctly with Lattice C version 5.02 or later.
X>>>>>>> 1.2
X * 
X<<<<<<< maketime.c
Xa26 3
X * checked in with -k by rsbx at 89.08.10.16.02.32.
X * 
X * Revision 1.8  88/11/08  13:54:53  narten
Xa34 8
X=======
X * Revision 1.3  89/09/16  09:42:31  rick
X * Modified AMIGA changes to work with Lattice C
X * 
X * Revision 1.2  88/09/03  15:08:05  rick
X * Port to AmigaDos.  All done with conditional compiles
X * 
X>>>>>>> 1.2
Xd89 2
Xa90 1
X#ifdef MYDEBUG
Xa91 1
X<<<<<<< maketime.c
Xa92 3
X=======
X#endif MYDEBUG
X>>>>>>> 1.2
Xa106 3
X#ifdef AMIGA
X	if(year < 78 || 78+134 < year ) /* Check range */
X#else
Xa107 1
X#endif
Xa109 3
X#ifdef AMIGA
X	year -= 78;			/* AMIGA time starts at 1978 */
X#else
Xa110 1
X#endif
Xa116 1
X
Xa135 1
X#ifndef AMIGA			/* Manx's localtime messes up yday */
Xa137 1
X#endif
Xd143 1
Xa143 1
X		+ ((year+1)>>2)		/* plus # of leap days since 1970 (1980)*/
Xa147 3
X#ifdef AMIGA
X                  || i != (tres+0)%7)   /* Matches? Jan 1,1978 was Sun = 0 */
X#else
Xa148 1
X#endif
Xd151 1
Xa151 1
X#ifdef MYDEBUG
Xa152 1
X<<<<<<< maketime.c
Xa153 3
X=======
X#endif MYDEBUG
X>>>>>>> 1.2
Xd163 4
Xa166 4
X	if( (min < 0) || (60 <= min)
X	 || (sec < 0) || (60 <= sec) ) return(0);	/* ERR: MS out of range */
X	if((hour < 0) || (24 <= hour))
X		if((hour != 24) || ((min+sec) !=0))	/* Allow 24:00 */
Xa169 1
X#ifndef AMIGA
Xa181 1
X#endif
Xd185 1
Xa185 1
X#ifdef MYDEBUG
Xa186 1
X<<<<<<< maketime.c
Xa187 3
X=======
X#endif MYDEBUG
X>>>>>>> 1.2
Xa192 1
X#ifndef AMIGA
Xd207 1
Xa207 1
X#endif
Xa214 1
X<<<<<<< maketime.c
Xa216 4
X=======
X#ifndef AMIGA
X#ifdef V6
X>>>>>>> 1.2
Xa241 1
X#endif AMIGA
X@
X
X
X1.8.2.2
Xlog
X@Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
Xsources I have here (and are later than the ones Rick used).
X@
Xtext
X@d1 1
Xd23 5
Xa27 1
Xstatic char rcsid[]= "$Id: maketime.c,v 1.8.2.1 89/10/13 19:17:37 rsbx Exp Locker: rsbx $";
Xd30 1
Xa30 3
X * Revision 1.8.2.1  89/10/13  19:17:37  rsbx
X * Start of Amiga RCS port branch.
X * 
Xd33 6
Xd40 1
Xd53 8
Xd106 1
Xa106 4
X	int year, yday, mon, day, hour, min, sec, leap;
X#ifndef AMIGA
X	int zone, dst;
X#endif
Xd117 1
Xd119 3
Xd197 1
Xd199 3
Xd237 1
Xd239 3
Xd270 4
Xd275 2
Xa276 1
X#if defined(V6) || defined(USG)
X@
X
X
X1.8.1.1
Xlog
X@Start of cbmvax RCS source branch.
X@
Xtext
X@a26 3
X * checked in with -k by rsbx at 89.08.10.16.02.32.
X * 
X * Revision 1.8  88/11/08  13:54:53  narten
X@
SHAR_EOF
echo "End of archive 6 (of 14)"
# if you want to concatenate archives, remove anything after this line
exit