Google
 

Trailing-Edge - PDP-10 Archives - mit_emacs_170_teco_1220 - emacs/buffer.emacs
There are no other files named buffer.emacs in the archive.
!* -*-TECO-*-!

!* Q.B contains the buffer table.  It is a vector which is divided
 into several multi-word entries, one for each buffer.
 The entries are in no particular order.
 Each entry starts with its length in words, as the zeroth word.
 Word 1|*bufnam| is the name of the buffer.
 Word 2|*bufvis| is the visited filename.
  These are the filenames as spec'd, not the real
  names (ie, they contain ">", not the version).
  This word can be 0, if the buffer doesn't correspond to a file.
 Word 3|*bufmod| is the name of the major mode selected in this
  buffer (eg, "LISP" or "Fundamental").  This may not be accurate
  for the selected buffer.
 Word 4|*bufbuf| points to the actual buffer itself.
 Word 5|*buftdf| is the TECO default filenames associated with the buffer.
  They are swapped in and out of FS D FILE,
  and are not accurate for the selected buffer.
  They are 0 in a buffer that has never been selected.
 Word 6|*bufwin| is the FS WINDOW associated with the buffer.
  This is not accurate for the selected buffer.
 Word 7|*bufnum| is the buffer's number, assigned when it was created.
  A buffer can be selected by number as well as by name.
 Word 8|*bufdat| is the creation date of last file visited or saved.
 Word 9|*bufver| is the actual version number as of last read or save.
  On ITS, if the files does not have a numeric FN2, this slot
  contains the FN2 as a string.  Consider as a number, the string is negative.
  Referred to only in SUPPRT and FILES and BUFFER.
 Word 10|*bufsav| is nonzero if autosaving is on for this buffer;
  1 for saving as the visited filename, or else the filename for auto saves.
  Referred to only in this file and FILES and SUPPRT.
 Word 11|*bufsiz| is the size of the file when last read or saved.
  Referred to only in FILES.
 Word 12|*bufnwr| is nonzero for read-only visiting.
  Positive means the buffer can be changed but not the file.
  Negative means the file cannot be changed either.
 Word 13|*bufcng| is the list of recent changes to the buffer; see TECORD.INFO.
  Referred to only in this file and EINIT.
 Word 14|*buflcl| is the start of the local variables,
  of which there may be zero or more.
  Referred to only in this file and EINIT.

 Following words in an entry are in pairs, one pair per local variable.
  The first word of a pair is the variable name (a string);  the second
  is the value.  When a buffer is selected, the global value lives here.
  When it is not selected, the local value lives here.  Thus, ..Q always
  has the actual (local or global) value of the variable.

 |*buf...| is a comment, removed during compression, which makes
 it easy to find code that depends on the order of elements in
 the buffer table entry.  You really write it with exclamation marks,
 not vertical bars, but it's impossible to put exclamation marks
 inside this big comment.

A buffer's "Index" is the offset of its entry from the start of .B, in words.
A buffer's index can change, if earlier entries grow, but only the
current buffer's entry can grow, so the current buffer's index can't change.
!

!Select Buffer:! !C Select or create buffer with specified name.
Can accept the buffer name as a string arg, or the buffer number
as a numeric arg, or a string pointer as arg (when used as a subroutine).
If there is a buffer with that name, it is selected.
Otherwise, a buffer with that name is created and selected.
When a new buffer is selected the first time, if Buffer Creation Hook
is nonzero, it is run after the buffer is selected.
A precomma arg is the prompt string to use.!

    MMM_&_Check_Top_Levelbuffers
    [4 0[3
    FF&1"N U3'  !* Numeric arg => use it as buffer or buffer # to select.!
    "# "E :F"G :i3''	    !* Precomma arg, or no postcomma arg, => read string arg.!
      Q3"E M.M List_BuffersF[HELPMAC	    !* Else must read from tty.!
         "N u4'		    !* Precomma arg is prompt string to use.!
           "# :i4 Select_Buffer'
	 QPrevious_Bufferu3	    !* Get name of default new buffer to put in prompt.!
	 1,Q3M(M.M &_Find_Buffer)"L Q:.B(1)U3'
	 3,m(m.m &_Read_Line)4_(3):_u3	    !* Read name of buffer to select.!
	 Q..H"N F' 0U..H	    !* Don't wait for space: redisplay text immediately.!
	 FQ3"L 0'		    !* Give up if get a rubout instead.!
	 F]HELPMAC''
    Q3[5			    !* Save name (or buffer #) in Q5.!
    FQ3"E QPrevious_BufferU3'	    !* Null string means previous buffer.!
    1,Q3 M(M.M&_Find_Buffer)[1	    !* Get index in buffer table of this name or number.!
    Q1U4			    !* Q4 remains negative, for a new buffer.!
    Q1"L			    !* No such buffer => make one now.!
      FQ3"L :I*No_such_buffer FS ERR'	    !* Refuse to create buffer if bfr number spec'd.!
      FQ5"E 0U1 0U4'		            !* If ^XB<cr> and prev bfr non ex, use 1st buffer instead.!
      "# Q3 M(M.M &_Create_Buffer)U1''   !* Else create the specified buffer.!
    Q1 :M(M.M &_Select_Buffer)
!& Select Buffer:! !S Selects buffer with index given in post-comma arg.!

    [4 [5
    [1
    QBuffer_Index[3
    Q1-Q3"E 0'
    1F[Noquit			    !* Prevent quitting half-switched.!
    0FO..Q Buffer_Deselection_HookU5
    Q5"N M5'
    Q.B[..O ZJ 0K ]..O	    !* Get gap in buffer table out of the way.!
    Q3,14!*buflcl!F.B		    !* Swap old buffer's locals back into its entry.!
    QBuffer_FilenamesU:.B(Q3+2!*bufvis!)  !* Stick its filenames back into entry.!
    QMode U:.B(Q3+3!*bufmod!)	    !* Stick selected mode into entry.!
    FS New Cng			    !* Make sure change history up to date!

!* Simultaneously swap out old buffer's TECO default filenames
 and window address, and swap in the new buffer's.!
    Q:.B(Q1+6!*bufwin!) FS WINDOW U:.B(Q3+6!*bufwin!)
    Q:.B(Q1+5!*buftdf!)F"E W' FS D FILE U:.B(Q3+5!*buftdf!)

!* We now are "between buffers".!
    Q:.B(Q1+13!*bufcng!) FS CNGBUF !* New file's change record!
    Q:.B(Q1+2!*bufvis!)UBuffer_Filenames  !* Get filenames of new buffer.!
    Q:.B(Q1+1!*bufnam!)UBuffer_Name	    !* For our records, save its name!
    Q:.B(Q1+3!*bufmod!)UMode
    0F[VARMAC			    !* Set QAuto Save Mode to match the truth.!
    Q:.B(Q1+10!*bufsav!)UAuto_Save_Mode    !* But don't try calling the function!
    F]VARMAC			    !* Auto Save Mode -- nothing is really changing.!

    Q1 UBuffer_Index		    !* and its index, for when we deselect it.!
    Q:.B(Q3+1!*bufnam!)UPrevious_Buffer   !* remember previously selected buffer's name.!
    Q:.B(Q1+3!*bufmod!) U3
    Q1,14!*buflcl!F.B		    !* Get new buffer's local variable values.!
    1FSMODE CHANGE		    !* Recompute mode line eventually.!
    Q:.B(Q1+4!*bufbuf!) U..O	    !* Now really switch to this buffer.!
    Q..O FS TopBuf		    !* Only this buffer has change history.!
    Z FS Old Z			    !* No changes should be outstanding.!

    0FO..Q Buffer_Selection_HookF"N [..N'
    Q:.B(Q1+5!*buftdf!)"N '	    !* If buffer has been selected before, that's all.!
    Q:.B(Q1+1!*bufnam!)U4
    FS OS TECO "E F64'"#Q4' FS DFN1    !* If buffer selected for 1st time, set default fn1 from name.!
    QDefault_Major_ModeU4	    !* Select the desired major mode.!
    FQ4"G M(M.M4_Mode)'
    0UAuto_Save_Count
    0FO..QBuffer_Creation_HookU4   !* If buffer selected for 1st time, maybe run user's hook.!
    Q4"N M4'
    
!& Create Buffer:! !S Make a new buffer at end of buffer table.
The buffer's name should be specified as a string pointer.
The new buffer's index is returned.!

    1F[NOQUIT			    !* Don't allow quitting with buffer half-created.!
    FQ.B/5[2 [1			    !* Q2 gets length of buffer table in words.!
    Q.B[..O			    !* Select the buffer table, and add new entry at end.!
    ZJ 14!*buflcl!*5,0I		    !* Q2 gets idx of the end;  make the space.!
    ]..O			    !* 14|*buflcl| words of fixed storage.!
    14!*buflcl!U:.B(Q2)		    !* Local vars get added later.!
    Q2[4
    U:.B(%4)			    !* Store the name.!
    0U:.B(%4)			    !* Set filenames to 0.!
    QModeU:.B(%4)		    !* New buffers copy mode from previous one.!
    FS B CONS U:.B(%4)		    !* Make a buffer to put in this entry.!
    0U:.B(%4)			    !* Put 0 in as TECO filenames to mark bfr as unvisited.!
    0U:.B(%4)			    !* Its FS WINDOW is 0 since it is empty.!
    %Next_Bfr_NumberU:.B(%4)	    !* Assign the new buffer a number.!
    0U:.B(%4)			    !* No date of last save or read, yet.!
    0U:.B(%4)			    !* No actual file version # yet.!
    0U:.B(%4)			    !* Auto save off.!
    0U:.B(%4)			    !* 0 is size of file when last read or saved.!
    0U:.B(%4)			    !* Not read-only.!
    128@FO..qChange_Buffer_Size*5 FS B Cons U:.B(%4)	!* New change buffer.!
			      !* Note that value remembered for Z is 0, i.e. Z!

!* Now copy the locals from the selected buffer.!
    QBuffer_IndexU1
    Q:.B(Q1)-Q:.B(Q2)/2U4	    !* Q4 gets number of locals to copy.!
    FQDefault_Major_Mode"G	    !* Maybe all, maybe just perm. ones.!
      :I*Fundamental U:.B(Q2+3!*bufmod!)
      QInitial_Local_CountU4'
    Q.B[..O  Q2+Q:.B(Q2)*5J	    !* Go to end of entry of new buffer.!
    Q1+Q:.B(Q2)*5,(Q4*2+Q1+Q:.B(Q2)*5)G.B	    !* Copy additional locals from that buffer.!
    Q4*2+Q:.B(Q2)U:.B(Q2)	    !* Increase entry size word.!
    Q2,(!*buflcl!14+2)@F.B	    !* Store current (local) var values (but not Autosave Count) into new bfr locals!
    Q2			    !* return the index of this new buffer.!
!List Buffers:! !C List numbers, names, files and modes of all buffers.!
    FT
       __#__Buffer___(Mode)________Filenames
       __(*_means_buffer_needs_saving)

       
    F[D FILE
    FQ.B/5[1 0[2 [3 [..O
    < Q2-Q1;			    !* Go thru buffer table;  stop at end.!
      Q:.B(Q2+4!*bufbuf!)U..O
      FS MODIF"N FT*_' "# FT__'  !* Type a star if buffer is modified.!
      Q:.B(Q2+7!*bufnum!):=	    !* Type the buffer's number.!
      5-(FS TYO HPOS)<FT_>
      Q:.B(Q2+1!*bufnam!)U3	    !* Type buffer's name,!
      FT 3
      Q:.B(Q2+3!*bufmod!)U3	    !* and its major mode,!
      QBuffer_Index-Q2"E QModeU3'	    !* (current major mode if current buffer)!
      FT__ FQ3-7"L 11-(FS TYO HPOS)<FT_>'
      FT (3)
      FT__ 28-(FSTYO HPOS)<FT_>
      Q:.B(Q2+2!*bufvis!)U3 Q3"N
        FT 3			    !* and its filenames if it has them.!
	ET3
	Q:.B(Q2+9!*bufver!)U3	    !* and actual version number.!
	FS D VERS:"G FS D VERS+1"N
	  FT_(
	  FQ3"L Q3:=' "# FT3'
	  FT)'''
      "# FSZ:= FT _Characters'    !* No filename => type the size.!
      Q:.B(Q2+12!*bufnwr!)"N
        FT __Read-Only'
      FT

      Q:.B(Q2)+Q2U2>		    !* Advance past this buffer.!
      
!List Locals:! !C List a specific buffer's local variables' names.
Takes name of buffer as a string argument.
Default is current buffer.!
    :I* [0 FQ0"E QBuffer_NameU0'
    Q0 M(M.M &_Find_Buffer)[9	    !* Find index of specified buffer.!
    14!*buflcl!-Q:.B(Q9)/2-1[1	    !* Q1 gets -1 minus # of locals this buffer has.!
    Q9+14!*buflcl!-1[2		    !* %2 will point at name of first local.!
    [3 [4
    FT Local_variables_of_buffer_0:

    <   %1;
	Q:.B(%2)U3 %2		    !* Q3 gets name of next local.!
	FQ3"L Q3@FS QP HOME U3'    !* If it's the address of QA, turn into "QA".!
	Q1+1"E FT3.
'      "# FT3,
' >
    
!& Find Buffer:! !S Find buffer index from buffer name or number.
Takes name as string, or number, as a prefix argument.  Given a
commaed argument ("1,"), if the buffer name is not found
-1 is returned;  otherwise it is an error.!

    FQ.B/5[1 0[2 [3 [4	    !* Q1 gets length in words of buffer table.!
    FP"L :\U3
      :I4 Q:.B(Q2+7!*bufnum!)-'  !* Q4 has comparison test of bfr num or bfr name.!
    "# :I4 F~:.B(Q2+1!*bufnam!)3 '
    < Q2-Q1;			    !* Q2 points at first (or next) buffer to test.!
      M4@;		    !* If name matches our arg, stop looking.!
      Q:.B(Q2)+Q2U2>		    !* Else advance to and look at next buffer.!
    Q2-Q1"L Q2'		    !* If we found the buffer, return its index.!
    "N -1'			    !* Otherwise, return -1 or signal error.!
    :I*NSB	No_such_buffer:_3 FS ERR
!& Find File:! !S Find buffer name from visited file name.
Takes filename, as string, as a prefix argument.
Returns the buffer name as a string object.
If there is no buffer visiting the specified file, returns 0.!

    FQ.B/5[1 0[2 [3 [4	    !* Q1 gets length in words of buffer table.!
    < Q2-Q1;			    !* Q2 points at first (or next) buffer test.!
      Q:.B(Q2+2!*bufvis!)U4
      Q4"N F~43"E
        Q:.B(Q2+1!*bufnam!)''	    !* If name matches our arg, stop looking.!
      Q:.B(Q2)+Q2U2>		    !* Else advance to and look at next buffer.!
    0				    !* Not found => return -1.!
!Kill Buffer:! !C Kill the buffer with specified name.
Takes name as a string (suffix) argument, or reads it from terminal.
Alternatively, the name (as string pointer) or the buffer
number may be given as a prefix argument.
If the buffer has changes in it, we offer to write it out.!

    FF&1"N [1 '		    !* Numeric arg => use it as buffer # to select.!
    "# 1,F Kill_Buffer:_[1'	    !* Read name of buffer to kill.!
  Q1:M(M.m &_Kill_Buffer)
!& Kill Buffer:! !S Takes buffer name or index as numeric arg & kills.!

    [1
    FQ1"E MMM_&_Check_Top_Levelbuffers
	  QBuffer_NameU1'	    !* Null string means current buffer.!
    [2 [3
    Q1 M(M.M&_Find_Buffer)U1	    !* Get index in buffer table of this name.!
    Q:.B(Q1+2!*bufvis!)"N	    !* If the buffer is visiting a file,!
      Q:.B(Q1+4!*bufbuf!) [..O	    !* Select it!
      FS MODIF"N		    !* to see if it needs to be written back!
       Q:.B(Q1+12!*bufnwr!)"E	    !* (and is not read-only).!
        Q:.B(Q1+1!*bufnam!)U2
        FS TYPEOUT"L @' FT
	Buffer_2_contains_changes.__Write_them_out
	FS TYPEOUT"L 1' M(M.M &_Yes_or_No)"N
	  Q:.B(Q1+2!*bufvis!)F[D FILE
	  FS OSTECO"N 0FS D VERS'
	  0[..F M(M.M Write_File) ]..F
	  F]D FILE'''
      ]..O'
    Q:.B(Q1)U2			    !* Get length in words of entry.!
    Q1-QBuffer_Index"E	    !* If trying to kill the current buffer,!
      0U:.B(Q1+10!*bufsav!)	    !* Turn off auto save - might save as visited file.!
      :I* Killing_current_buffer;__Select_which_other_buffer  !* 
!      ,M(M.M Select_Buffer)'	    !* select a different one first.!
    1F[NOQUIT
    Q:.B(Q1+4!*bufbuf!) FS BKILL   !* Kill the actual buffer (why wait for GC?).!
    10.F?			    !* Also errs out if try to kill selected buffer.!
    Q.B[..OQ1*5J Q2*5D		    !* Delete the entry from the table.!
    QBuffer_Index-Q1F"G +Q1-Q2 UBuffer_Index'
    0U..H 			    !* If killed buffer preceded current one, current one's!
				    !* index has been changed.!
!Make Local Variable:! !C Make a variable local to the current buffer.
Example:  M.LFoo Variable (since this function lives in .L).
The variable name must be given in full, not abbreviated.
Its local value starts off the same as its global value.
However, a numeric argument to this function sets the local value.
"1," as arg means assume that the local doesn't exist yet.
"2," means make a permanent local that won't go away when major mode changes.!

    :I*[0			    !* Q0 gets name of desired local.!
    QBuffer_Index[9
    Q9+14!*buflcl!-1[2		    !* %2 will point at name of first existing local.!
    Q:.B(Q9)-14!*buflcl!/2[1	    !* Q1 gets # of locals this buffer has.!
    :FO..Q 0[3
    Q3"G F~:..Q(Q3)0"N -Q3U3''   !* Make sure we find exact match.!
    Q3"L 0M.V 0		    !* Make sure a global var with that name exists.!
         :FO..Q 0U3'		    !* In either case, Q3 gets idx in Q..Q of that var.!
    Q:..Q(Q3)U0			    !* Q0 gets global var's name string, so we share it.!
    &1"N O Fast'
!*** Now insert this local in the local list, if it's not there yet.!
    Q1< Q:.B(%2)U3		    !* Q3 gets name of next old local.!
	FQ3"G F~3 0"E	    !* If desired local exists, return.!
	  FF&1"N		    !* But first set its value, if desired.!
	    U0'
	  ''
	%2>			    !* Compare each existing local's name against desired.!
 !Fast!
    Q.B[..O			    !* Local doesn't exist, so make it.!
    (Q:.B(Q9)+Q9)*5J		    !* Make 2 words space at end of locals of this entry.!
    &2"N Q9+14!*buflcl!*5J'	    !* But for perm. local, make space at front of locals.!
    1F[NOQUIT
    10,0I
    Q0,.-10 FS WORD		    !* Store name in first word.!
    Q0 ,.-5FS WORD		    !* Store old (global) value in second word.!
    Q:.B(Q9)+2 U:.B(Q9)		    !* Make entry know it is 2 words longer.!
    &2"N 2,M.L Initial_Local_Count
           %Initial_Local_Count'
    F]NOQUIT
    FF&1"N U0'	    !* Numeric arg is new local value.!
    
!Make Local Q-register:! !C Make a q-register local to the current buffer.
String argument should be name of q-register, as in "A" or ".^RA".
It can also be "FS" followed by the name of a TECO FS flag.
"1," as arg means assume that the local doesn't exist yet.!

    :I*[0			    !* get the q-reg name.!
    F~0 FS-3"E 1:F0 [ M0'	    !* if it starts with "FS", push the FS flag - !
				    !* change the "S" to a "[" and execute it.!
    "# [0'			    !* Otherwise push the qreg.!
    FS QP PTR-1[4		    !* Get pointer to pdl slot.!
    Q4:FS QP HOME[3		    !* Get the :fsqphome$ of that qreg.!
    QBuffer_Index[9
    Q9+14!*buflcl!-1[2		    !* %2 will point at name of first existing local.!
    "E
       Q:.B(Q9)-14!*buflcl!/2[1	    !* Q1 gets # of locals this buffer has.!
       Q1< Q:.B(%2)-Q3"E	    !* Search table of locals for desired one.!
	     FF&1"N ,Q4FS QP SLOT'   !* If found, set it if necessary, and exit.!
	     '
           %2>'
    Q.B[..O			    !* Local doesn't exist, so make it.!
    1F[NOQUIT
    (Q:.B(Q9)+Q9)*5J 10,0I	    !* Make 2 words space at end of locals of this entry.!
    Q3,.-10 FS WORD		    !* Store name in first word.!
    Q4FS QP SLOT ,.-5FS WORD	    !* Store old (global) value in second word.!
    Q:.B(Q9)+2 U:.B(Q9)		    !* Make entry know it is 2 words longer.!
    F]NOQUIT
    FF&1"N ,Q4FS QP SLOT'  !* Set it if necessary, and exit.!
!Kill Local Variable:! !C Kill one of the current buffer's local variables.
The global value is restored.!

    :I*[0			    !* Q0 gets name of desired local.!
    QBuffer_Index[9
    Q9+14!*buflcl!-1[2		    !* %2 will point at name of first existing local.!
    Q:.B(Q9)-14!*buflcl!/2[1	    !* Q1 gets # of locals this buffer has.!
    [3
    Q1< Q:.B(%2)U3		    !* Q3 gets name of next old local.!
	FQ3"G F~3 0@;'	    !* If desired local exists, return.!
	%2>			    !* Compare each existing local's name against desired.!
    F~3 0"N '		    !* No-op if the local does not exist.!
    Q.B[..O			    !* Local exists, so flush it.!
    Q2*5J
    .+5FS WORD U0	    !* Restore saved global value of variable.!
    1F[NOQUIT
    10D Q:.B(Q9)-2 U:.B(Q9)	    !* Make entry 2 words shorter.!
    
!Kill Local Q-register:! !C Kill one of the current buffer's local q-registers.
The global value is restored.  See Make Local Q-register for more info.!

    :I*[0			    !* Q0 gets name of desired local.!
    F~0 FS-3"E 1:F0 [ M0'	    !* if it starts with "FS", push the FS flag - !
				    !* change the "S" to a "[" and execute it.!
    "# [0'			    !* Otherwise push the qreg.!
    FS QP PTR-1[4		    !* Get pointer to pdl slot.!
    Q4:FS QP HOME[3		    !* Get the :fsqphome$ of that qreg.!

    QBuffer_Index[9
    Q9+14!*buflcl!-1[2		    !* %2 will point at name of first existing local.!
    -Q:.B(Q9)+14!*buflcl!/2[1	    !* Q1 gets # of locals this buffer has.!
    < %1"G '			    !* Local not found => no-op.!
      Q:.B(%2)-Q3@;		    !* Have we found the specified local?!
      %2>			    !* Compare each existing local's name against desired.!
    Q:.B(q2+1!*bufnam!),Q4FS QP SLOT	    !* Reload the global value.!
    Q.B[..O			    !* Flush local.!
    1F[NOQUIT
    Q2*5J 10D			    !* ...!
    Q:.B(Q9)-2 U:.B(Q9)		    !* Make buffer entry 2 words shorter.!
    
!& Init Buffer Locals:! !S When about to switch modes, flush locals of old mode.
We delete from the buffer's list of local variables
all locals except those put on initially when the buffer was made.
Also, unless we have a nonzero argument, we leave .Q bound locally
when we exit to MM Make Local Q-register.!

    "E M.M Make_Local_Q-reg[.Q'
!*** If Initial Local Count is -1, we are inside & Process File Modes !
!*** and the locals were already flushed, and some new ones have been made,!
!*** so avoid flushing them again.  Just return with :^\ to avoid popping .Q or .0.!
    QInitial_Local_CountF"L :'[2
    FS QP PTR[3
    QBuffer_Index[1
    Q.B[..O
    Q1,Q2+Q2+14!*buflcl!F.B	    !* Swap out locals so we don't lose now.!
				    !* Notice we only swap those we'll kill!
    1F[NOQUIT
    (Q1+14!*buflcl!+Q2+Q2)*5J
    (Q:.B(Q1)-14!*buflcl!-Q2-Q2)*5D !* Delete space in buffer table of per-mode locals.!
    Q2+Q2+14!*buflcl!U:.B(Q1)'	    !* Adjust size of this buffer entry.!
    Q3FS QP UNWIND
!Save All Files:! !C Offer to write back each buffer which may need it.
For each buffer which is visiting a file and which
has been written, you are asked whether to save it.
A numeric arg means don't ask;  save everything.!

    0[1 [2 [3 -1[4
    [..O F[D FILE
    < Q1*5-FQ.B;		    !* Stop after hacking all the buffers.!
      Q:.B(Q1+1!*bufnam!)U2	    !* Get next buffer's name.!
      Q:.B(Q1+4!*bufbuf!)U..O	    !* Select it, TECO style, so we can check its FS MODIF!
      FS MODIF"E  O LP'	    !* Don't save an unchanged buffer,!
      Q:.B(Q1+12!*bufnwr!)"N O LP' !* or a read-only buffer,!
      Q:.B(Q1+2!*bufvis!)F"E O LP'U3 ET3 !* or one not visiting a file.!
      ET3
      FS OS TECO"N		    !* On Twenex, always save as new version,!
        0FS D VERSW FS D FILEU3'  !* and the question we ask should indicate this.!
      FF&1"E
        < FT Save_buffer_2_in_3
          1,M(M.M &_Yes_or_No)U4
	  -Q4;>'		    !* if answer wasn't Y or N, ask again.!
      Q4"L			    !* It was a Y => save the file!
	Q3U:.B(Q1+2!*bufvis!)
	Q1-QBuffer_Index"E	    !* If current buffer, on Twenex maybe filename changed.!
	 FS OSTECO"N
	  1FS MODE CH
	  Q3UBuffer_Filenames''
	Q1[Buffer_Index	    !* Update the data for buffer being saved.!
	Q.F[..F
        1,M(M.M Write_File)
	]..F
	]Buffer_Index'
  !LP!
      Q1+Q:.B(Q1)U1>		    !* Advance to next buffer.!
    0U..H 			    !* Cause redisplay.!
!Kill Some Buffers:! !C Offer to kill each buffer, one by one.
If the buffer contains a modified file and you say to kill it,
you are asked whether to write the file out first.!

    :m(m.a AUXKill_Some_Buffers)
!Rename Buffer:! !C Change the name of the current buffer.
New name is suffix string arg;  null arg means use FN1 of visited file.!

    1,FRename_Buffer:_[1	    !* Q1 gets specified new name.!
    QBuffer_FilenamesF"N F[D FILE'
    fq1:"g fs d fn1@f6 u1'	    !* Default to first file name of visited file.!
    f~Buffer_Name1"e '	    !* No-op if buffer already has desired name.!
    1,Q1M(M.M &_Find_Buffer):"l    !* Is there already a buffer with that name?!
       :i*Name_1_already_in_use FS ERR'
    Q1UBuffer_Name
    Q1U:.B(QBuffer_Index+1!*bufnam!)
    :M(M.M &_Set_Mode_Line)	    !* Put new name into mode line.!
!Insert Buffer:! !C Insert contents of another buffer into existing text.
Specify buffer name as string argument.!

    1,FBuffer:_[1
    Q1:M(M.m &_Insert_Buffer)
!& Insert Buffer:! !S Inserts buffer passed in numeric.  Can be string ptr.!

     [1
    fq1"e qPrevious_Bufferu1'
    Q1M(M.M &_Find_Buffer)[2	    !* Else get index of specified buffer.!
    G:.B(Q2+4!*bufbuf!)		    !* Select the specified buffer, and!
    .: FK(FKC)		    !* Put mark at end, point before.!