/* Copyright (c) 1979 Regents of the University of California */
* Command mode subroutines implementing
* append, args, copy, delete, join, move, put,
* shift, tag, yank, z and undo
* Append after line a lines returned by function f.
* Be careful about intermediate states to avoid scramble
* if an interrupt comes in.
register line
*a1
, *a2
, *rdot
;
if (!inglobal
&& !inopen
&& f
!= getsub
) {
undap1
= undap2
= dot
+ 1;
if (truedol
>= endcore
) {
if (!inglobal
&& f
== getsub
) {
error("Out of memory@- too many lines in file");
for (rdot
= dot
; a1
> rdot
;)
if (!inglobal
|| inopen
> 0) {
* Print out the argument list, with []'s around the current name.
register char **av
= argv0
, *as
= args0
;
for (ac
= 0; ac
< argc0
; ac
++) {
if (ac
+ argc
== argc0
- 1)
if (ac
+ argc
== argc0
- 1)
as
= av
? *++av
: strend(as
) + 1;
* Delete lines; two cases are if we are really deleting,
* more commonly we are just moving lines to the undo save area.
if (!inglobal
|| inopen
> 0) {
register int (*dsavint
)();
dsavint
= signal(SIGINT
, SIG_IGN
);
if (!inglobal
|| inopen
> 0) {
* Crush out the undo save area, moving the open/visual
* save area down in its place.
register line
*a1
= dol
+ 1, *a2
= unddol
+ 1, *a3
= truedol
+ 1;
* Join lines. Special hacks put in spaces, two spaces if
* preceding line ends with '.', or no spaces if next line starts with ).
static int jcount
, jnoop();
for (a1
= addr1
; a1
<= addr2
; a1
++) {
if (a1
!= addr1
&& c
== 0) {
while (*cp1
== ' ' || *cp1
== '\t')
if (*cp1
&& cp
> genbuf
&& cp
[-1] != ' ' && cp
[-1] != '\t') {
if (cp
> &genbuf
[LBSIZE
-2])
error("Line overflow|Result line of join would be too long");
ignore(append(jnoop
, --addr1
));
* Move and copy lines. Hard work is done by move1 which
* is also called by undo.
markpr(addr2
== dot
? addr1
- 1 : addr2
+ 1);
serror("%s where?|%s requires a trailing address", Command
);
register line
*adt
, *ad1
, *ad2
;
lines
= (addr2
- addr1
) + 1;
ignore(append(getcopy
, ad1
++));
for (ad1
= addr1
; ad1
<= ad2
;)
if (adt
+ 1 == ad1
&& !cflag
&& !inglobal
)
error("That move would do nothing!");
error("Move to a moved line");
* Put lines in the buffer from the undo save area.
if (cnt
&& inopen
&& pkill
[0] && pkill
[1]) {
ignore(append(getput
, addr2
));
* A tricky put, of a group of lines in the middle
* of an existing line. Only from open/visual.
* Argument says pkills have meaning, e.g. called from
* put; it is 0 on calls from putreg.
register char *gp
= &genbuf
[cursor
- linebuf
];
* This kind of stuff is TECO's forte.
* We just grunge along, since it cuts
* across our line-oriented model of the world
* almost scrambling our addled brain.
* Shift lines, based on c.
* If c is neither < nor >, then this is a lisp aligning =.
save12(), undkind
= UNDCHANGE
;
cnt
*= value(SHIFTWIDTH
);
for (addr
= addr1
; addr
<= addr2
; addr
++) {
if (c
== '=' && addr
== addr1
&& addr
!= addr2
)
cp
= i
> 0 ? genindent(i
) : genbuf
;
if (cp
+ strlen(dp
= vpastwh(linebuf
)) >= &genbuf
[LBSIZE
- 2])
error("Line too long|Result line after shift would be too long");
* Find a tag in the tags file.
* Most work here is in parsing the tags file itself.
register char *lp
= lasttag
;
while (!iswhite(peekchar()) && !endcmd(peekchar()))
if (lp
< &lasttag
[sizeof lasttag
- 2])
error("Bad tag|Give one tag per line");
} else if (lasttag
[0] == 0)
error("No previous tag");
io
= open(master
? "tags" : MASTERTAGS
, 0);
register char *cp
= linebuf
;
register char *lp
= lasttag
;
while (*cp
&& *lp
== *cp
)
while (*cp
&& iswhite(*cp
))
serror("%s: Bad tags file entry", lasttag
);
while (*cp
&& *cp
!= ' ' && *cp
!= '\t') {
if (lp
< &file
[sizeof file
- 2])
* Save current position in 't for ^^ in visual.
names
['t'-'a'] = *dot
&~ 01;
extern char *ncols
['z'-'a'+1];
if (strcmp(file
, savedfile
) || !edited
) {
char cmdbuf2
[sizeof file
+ 10];
error("No write@since last change (tag! overrides)");
serror("%s: No such tag@in tags file", lasttag
);
* Save lines from addr1 thru addr2 as though
killcnt(addr2
- addr1
+ 1);
* z command; print windows of text in the file.
* If this seems unreasonably arcane, the reasons
* are historical. This is one of the first commands
* added to the first ex (then called en) and the
* number of facilities here were the major advantage
* of en over ed since they allowed more use to be
* made of fast terminals w/o typing .,.22p all the time.
register int c
, lines
, op
;
switch (c
= op
= getchar()) {
while (peekchar() == op
) {
if (lines
< value(WINDOW
))
lines
= op
== EOF
? value(SCROLL
) : excl
? LINES
- 1 : value(WINDOW
);
if (inopen
|| c
!= EOF
) {
addr2
+= lines
* zweight
;
addr2
-= lines
* zweight
;
if (op
== EOF
&& zhadpr
) {
} else if (znoclear
== 0 && CL
!= NOSTR
&& !inopen
) {
plines(addr1
, split
- 1, 0);
for (l
= COLUMNS
> 80 ? 40 : COLUMNS
/ 2; l
> 0; l
--)
plines(adr1
, adr2
, movedot
)
for (addr
= adr1
; addr
<= adr2
; addr
++) {
if (inopen
&& Outchar
!= termchar
) {
* Dudley doright to the rescue.
* Undo saves the day again.
* A tip of the hatlo hat to Warren Teitleman
* who made undo as useful as do.
* Command level undo works easily because
* the editor has a unique temporary file
* index for every line which ever existed.
* We don't have to save large blocks of text,
* only the indices which are small. We do this
* by moving them to after the last line in the
* line buffer array, and marking down info
* about whence they came.
* Undo is its own inverse.
line
*dolp1
, *newdol
, *newadot
;
if (inglobal
&& inopen
<= 0)
error("Can't undo in global@commands");
if (undkind
== UNDMOVE
) {
* Command to be undone is a move command.
* This is handled as a special case by noting that
* a move "a,b m c" can be inverted by another move.
if ((i
= (jp
= unddel
) - undap2
) > 0) {
* when c > b inverse is a+(c-b),c m a-1
addr1
= (jp
= undap1
) + i
;
* when b > c inverse is c+1,c+1+(b-a) m b
addr2
= jp
+ ((unddel
= undap2
) - undap1
);
* Command to be undone is a non-move.
* All such commands are treated as a combination of
* a delete command and a append command.
* We first move the lines appended by the last command
* from undap1 to undap2-1 so that they are just before the
if ((i
= (kp
= undap2
) - (jp
= undap1
)) > 0) {
* Account for possible backward motion of target
* for restoration of saved deleted lines.
* For the case where no lines are restored, dot
* is the line before the first line deleted.
* Now put the deleted lines, if any, back where they were.
* Basic operation is: dol+1,unddol m unddel
if ((i
= (kp
= unddol
) - dol
) > 0) {
* Account for possible forward motion of the target
* for restoration of the deleted lines.
* Dot is the first resurrected line.
* Clean up so we are invertible
if (dot
== zero
&& dot
!= dol
)
* Be (almost completely) sure there really
* was a change, before claiming to undo.
if (undap1
== undap2
&& dol
== unddol
)
if (unddol
- dol
!= lineDOL())
for (ip
= one
, jp
= dol
+ 1; ip
<= dol
; ip
++, jp
++)
if ((*ip
&~ 01) != (*jp
&~ 01))
error("Nothing to undo");
error("Nothing changed|Last undoable command didn't change anything");