home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / bbs / util / jade-3.0.lha / Jade / src / buffers.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-19  |  29.0 KB  |  1,165 lines

  1. /* buffers.c -- Buffer handling
  2.    Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
  3.  
  4. This file is part of Jade.
  5.  
  6. Jade is free software; you can redistribute it and/or modify it
  7. under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. Jade is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with Jade; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include "jade.h"
  21. #include "jade_protos.h"
  22.  
  23. #include <string.h>
  24.  
  25. _PR void buffer_sweep(void);
  26. _PR void buffer_prin(VALUE, VALUE);
  27. _PR TX *firstbuffer(void);
  28. _PR void swapvwfiles(VW *, TX *);
  29. _PR TX *swapvwfilesnd(VW *, TX *);
  30. _PR int execfilecode(TX *, long *);
  31. _PR POS *gettxcurspos(TX *);
  32. _PR int autosavebuffers(void);
  33. _PR void makemarksres(TX *);
  34. _PR void makemarksnonres(TX *);
  35. _PR void mark_sweep(void);
  36. _PR int mark_cmp(VALUE, VALUE);
  37. _PR void mark_prin(VALUE, VALUE);
  38. _PR void buffers_init(void);
  39. _PR void buffers_kill(void);
  40.  
  41. /*
  42.  * Chain of all allocated TXs.
  43.  */
  44. _PR TX *BufferChain;
  45. TX *BufferChain;
  46.  
  47. VALUE sym_auto_save_function, sym_no_file_code_p, sym_leading, sym_all;
  48.  
  49. _PR VALUE cmd_make_buffer_name(VALUE);
  50. DEFUN("make-buffer-name", cmd_make_buffer_name, subr_make_buffer_name, (VALUE rawName), V_Subr1, DOC_make_buffer_name) /*
  51. ::doc:make_buffer_name::
  52. (make-buffer-name NAME)
  53. Construct a unique buffer-name from NAME.
  54. ::end:: */
  55. {
  56.     int suffix = 1;
  57.     DECLARE1(rawName, STRINGP);
  58.     while(TRUE)
  59.     {
  60.     u_char buf[256];
  61.     u_char *thistry;
  62.     TX *tx = BufferChain;
  63.     if(suffix != 1)
  64.     {
  65.         sprintf(buf, "%s<%d>", VSTR(rawName), suffix);
  66.         thistry = buf;
  67.     }
  68.     else
  69.         thistry = VSTR(rawName);
  70.     while(tx)
  71.     {
  72.         if(tx->tx_BufferName && !strcmp(thistry, VSTR(tx->tx_BufferName)))
  73.         break;
  74.         tx = tx->tx_Next;
  75.     }
  76.     if(!tx)
  77.     {
  78.         if(suffix == 1)
  79.         return(rawName);
  80.         return(valstrdup(buf));
  81.     }
  82.     suffix++;
  83.     }
  84. }
  85.  
  86. _PR VALUE cmd_make_buffer(VALUE, VALUE, VALUE);
  87. DEFUN("make-buffer", cmd_make_buffer, subr_make_buffer, (VALUE name, VALUE oldTx, VALUE litName), V_Subr3, DOC_make_buffer) /*
  88. ::doc:make_buffer::
  89. (make-buffer NAME)
  90. Return a new buffer, it's name is the result of (make-buffer-name NAME).
  91. ::end:: */
  92. {
  93.     TX *tx;
  94.     DECLARE1(name, STRINGP);
  95.     if(!BUFFERP(oldTx))
  96.     {
  97.     if(CurrVW)
  98.         oldTx = CurrVW->vw_Tx;
  99.     else
  100.         oldTx = NULL;
  101.     }
  102.     if((tx = mycalloc(sizeof(TX))) && clearlinelist(tx))
  103.     {
  104.     tx->tx_Type = V_Buffer;
  105.     tx->tx_Next = BufferChain;
  106.     BufferChain = tx;
  107.     DataAfterGC += sizeof(TX);
  108.     tx->tx_BufferName = NILP(litName) ? cmd_make_buffer_name(name) : name;
  109.     if(tx->tx_BufferName)
  110.     {
  111.         tx->tx_FileName = NullString;
  112.         tx->tx_SavedBlockStatus = -1;
  113.         copyfileprefs(tx, oldTx);
  114.         tx->tx_LocalVariables = sym_nil;
  115.         tx->tx_LastSaveTime = getsystime();
  116.         return(tx);
  117.     }
  118.     }
  119.     return(NULL);
  120. }
  121.  
  122. _PR VALUE cmd_destroy_buffer(VALUE);
  123. DEFUN("destroy-buffer", cmd_destroy_buffer, subr_destroy_buffer, (VALUE tx), V_Subr1, DOC_destroy_buffer) /*
  124. ::doc:destroy_buffer::
  125. (destory-buffer BUFFER)
  126. Throw away everything associated with buffer. All resident marks are made
  127. non-resident.
  128. ::end:: */
  129. {
  130.     DECLARE1(tx, BUFFERP);
  131.     makemarksnonres(VTX(tx));
  132.     clearlinelist(VTX(tx));
  133.     VTX(tx)->tx_FileName = NullString;
  134.     VTX(tx)->tx_BufferName = NullString;
  135.     VTX(tx)->tx_ModeName = NULL;
  136.     VTX(tx)->tx_Changes = 0;
  137.     VTX(tx)->tx_LocalVariables = sym_nil;
  138.     VTX(tx)->tx_Flags |= TXFF_RDONLY | TXFF_REFRESH_ALL;
  139.     sm_flush(&MainStrMem);
  140.     return(sym_t);
  141. }
  142.  
  143. void
  144. buffer_sweep(void)
  145. {
  146.     TX *tx = BufferChain;
  147.     BufferChain = NULL;
  148.     while(tx)
  149.     {
  150.     TX *nxt = tx->tx_Next;
  151.     if(!GC_MARKEDP(tx))
  152.     {
  153.         makemarksnonres(tx);
  154.         killlinelist(tx);
  155.         myfree(tx);
  156.     }
  157.     else
  158.     {
  159.         GC_CLR(tx);
  160.         tx->tx_Next = BufferChain;
  161.         BufferChain = tx;
  162.     }
  163.     tx = nxt;
  164.     }
  165. }
  166. void
  167. buffer_prin(VALUE strm, VALUE obj)
  168. {
  169.     streamputs(strm, "#<buffer ", FALSE);
  170.     streamputs(strm, VSTR(VTX(obj)->tx_BufferName), TRUE);
  171.     streamputc(strm, '>');
  172. }
  173.  
  174. TX *
  175. firstbuffer(void)
  176. {
  177.     TX *tx;
  178.     if(!CurrVW)
  179.     {
  180.     if(!(CurrVW = cmd_make_window(sym_nil, sym_nil, sym_nil, sym_nil)))
  181.         return(NULL);
  182.     }
  183.     tx = cmd_make_buffer(MKSTR("*jade*"), sym_nil, sym_t);
  184.     if(tx)
  185.     {
  186. #ifndef NOSCRLBAR
  187.     updatescroller(CurrVW);
  188. #endif
  189.     swapvwfiles(CurrVW, tx);
  190.     return(tx);
  191.     }
  192.     return(NULL);
  193. }
  194.  
  195. /*
  196.  * Makes `new' the file being shown in window `vw'
  197.  */
  198. void
  199. swapvwfiles(VW *vw, TX *new)
  200. {
  201.     TX *old = vw->vw_Tx;
  202.     if(old != new)
  203.     {
  204.     if(old)
  205.     {
  206.         old->tx_SavedCPos = vw->vw_CursorPos;
  207.         old->tx_SavedWPos = vw->vw_DisplayOrigin;
  208.         old->tx_SavedBlockPos[0] = vw->vw_BlockS;
  209.         old->tx_SavedBlockPos[1] = vw->vw_BlockE;
  210.         old->tx_SavedBlockStatus = vw->vw_BlockStatus;
  211.     }
  212.     vw->vw_Tx = new;
  213.     vw->vw_CursorPos = new->tx_SavedCPos;
  214.     vw->vw_DisplayOrigin = new->tx_SavedWPos;
  215.     vw->vw_BlockS = new->tx_SavedBlockPos[0];
  216.     vw->vw_BlockE = new->tx_SavedBlockPos[1];
  217.     vw->vw_BlockStatus = new->tx_SavedBlockStatus;
  218.     vw->vw_LastRefTx = NULL;
  219.     }
  220. }
  221. /*
  222.  * "nd" means non-destructive. refcount's of buffers are not changed and
  223.  * previous buffer shown is returned.
  224.  * This is intended to allow *temporary* switching of buffers before
  225.  * reinstalling the original.
  226.  * ** this is kind of obsolete but never mind **
  227.  */
  228. TX *
  229. swapvwfilesnd(VW *vw, TX *new)
  230. {
  231.     TX *old = vw->vw_Tx;
  232.     if(old != new)
  233.     {
  234.     if(old)
  235.     {
  236.         old->tx_SavedCPos = vw->vw_CursorPos;
  237.         old->tx_SavedWPos = vw->vw_DisplayOrigin;
  238.         old->tx_SavedBlockPos[0] = vw->vw_BlockS;
  239.         old->tx_SavedBlockPos[1] = vw->vw_BlockE;
  240.         old->tx_SavedBlockStatus = vw->vw_BlockStatus;
  241.     }
  242.     vw->vw_Tx = new;
  243.     vw->vw_CursorPos = new->tx_SavedCPos;
  244.     vw->vw_DisplayOrigin = new->tx_SavedWPos;
  245.     vw->vw_BlockS = new->tx_SavedBlockPos[0];
  246.     vw->vw_BlockE = new->tx_SavedBlockPos[1];
  247.     vw->vw_BlockStatus = new->tx_SavedBlockStatus;
  248.     }
  249.     return(old);
  250. }
  251.  
  252. _PR VALUE cmd_get_file_buffer(VALUE);
  253. DEFUN("get-file-buffer", cmd_get_file_buffer, subr_get_file_buffer, (VALUE name), V_Subr1, DOC_get_file_buffer) /*
  254. ::doc:get_file_buffer::
  255. (get-file-buffer NAME)
  256. Scan all buffers for one containing the file NAME.
  257. ::end:: */
  258. {
  259.     TX *tx = BufferChain;
  260.     DECLARE1(name, STRINGP);
  261.     while(tx)
  262.     {
  263.     if(samefiles(VSTR(name), VSTR(tx->tx_FileName)))
  264.         return(tx);
  265.     tx = tx->tx_Next;
  266.     }
  267.     return(sym_nil);
  268. }
  269. _PR VALUE cmd_get_buffer(VALUE);
  270. DEFUN("get-buffer", cmd_get_buffer, subr_get_buffer, (VALUE name), V_Subr1, DOC_get_buffer) /*
  271. ::doc:get_buffer::
  272. (get-buffer NAME)
  273. Scan all buffers for one whose name is NAME.
  274. ::end:: */
  275. {
  276.     TX *tx = BufferChain;
  277.     if(BUFFERP(name))
  278.     return(name);
  279.     DECLARE1(name, STRINGP);
  280.     while(tx)
  281.     {
  282.     if(!strcmp(VSTR(name), VSTR(tx->tx_BufferName)))
  283.         return(tx);
  284.     tx = tx->tx_Next;
  285.     }
  286.     return(sym_nil);
  287. }
  288.  
  289. int
  290. execfilecode(TX *tx, long *codePos)
  291. {
  292.     bool rc = FALSE;
  293.     String *buf;
  294.     long buflen;
  295.     VALUE nfc;
  296.     if((nfc = cmd_symbol_value(sym_no_file_code_p)) && !NILP(nfc))
  297.     return(rc);
  298.     buflen = (codePos[2] - codePos[1]) * 100;
  299.     buf = mystralloc(buflen + 1);
  300.     if(buf)
  301.     {
  302.     if(colcopysect(tx, codePos, VSTR(buf), buflen))
  303.     {
  304.         TX *old;
  305.         buf->str_Type = V_String;
  306.         old = swapvwfilesnd(CurrVW, tx);
  307.         if(old)
  308.         {
  309.         VALUE res;
  310.         if((res = evalstring(VSTR(buf), TRUE)) && !NILP(res))
  311.             rc = TRUE;
  312.         swapvwfilesnd(CurrVW, old);
  313.         }
  314.     }
  315.     mystrfree(buf);
  316.     }
  317.     return(rc);
  318. }
  319.  
  320. POS *
  321. gettxcurspos(TX *tx)
  322. {
  323.     VW *vw = ViewChain;
  324.     /* Check active window first */
  325.     if(CurrVW->vw_Tx == tx)
  326.     return(&CurrVW->vw_CursorPos);
  327.     while(vw)
  328.     {
  329.     if(vw->vw_Window && (vw->vw_Tx == tx))
  330.         return(&vw->vw_CursorPos);
  331.     vw = vw->vw_Next;
  332.     }
  333.     return(&tx->tx_SavedCPos);
  334. }
  335.  
  336. /*
  337.  * returns the number of buffers saved.
  338.  * (maybe should only save one buffer at a time, then wait to be called
  339.  *  again to save next in line? This could be less intrusive: yes.)
  340.  */
  341. int
  342. autosavebuffers(void)
  343. {
  344.     /*
  345.      * Stops me entering here more than once at the same time. This
  346.      * can happen when tracing the `auto-save-function'
  347.      */
  348.     static bool Exclusion;
  349.     if(!Exclusion)
  350.     {
  351.     VALUE tx = BufferChain;
  352.     u_long time = getsystime();
  353.     Exclusion = TRUE;
  354.     while(tx)
  355.     {
  356.         if(VTX(tx)->tx_Changes
  357.            && VTX(tx)->tx_AutoSaveInterval
  358.            && (VTX(tx)->tx_LastSaveChanges != VTX(tx)->tx_Changes)
  359.            && (time > (VTX(tx)->tx_LastSaveTime + VTX(tx)->tx_AutoSaveInterval)))
  360.         {
  361.         GCVAL gcv_tx;
  362.         PUSHGC(gcv_tx, tx);
  363.         calllisp1(sym_auto_save_function, tx);
  364.         POPGC;
  365.         VTX(tx)->tx_LastSaveTime = time;
  366.         VTX(tx)->tx_LastSaveChanges = VTX(tx)->tx_Changes;
  367.         Exclusion = FALSE;
  368.         return(1);
  369.         }
  370.         tx = VTX(tx)->tx_Next;
  371.     }
  372.     Exclusion = FALSE;
  373.     }
  374.     return(0);
  375. }
  376.  
  377. _PR VALUE cmd_current_buffer(VALUE);
  378. DEFUN("current-buffer", cmd_current_buffer, subr_current_buffer, (VALUE vw), V_Subr1, DOC_current_buffer) /*
  379. ::doc:current_buffer::
  380. (current-buffer [WINDOW])
  381. Return the buffer that WINDOW (or the current window) is displaying.
  382. ::end:: */
  383. {
  384.     if(!WINDOWP(vw))
  385.     vw = CurrVW;
  386.     return(VWIN(vw)->vw_Tx);
  387. }
  388.  
  389. _PR VALUE cmd_set_current_buffer(VALUE, VALUE);
  390. DEFUN("set-current-buffer", cmd_set_current_buffer, subr_set_current_buffer, (VALUE tx, VALUE vw), V_Subr2, DOC_set_current_buffer) /*
  391. ::doc:set_current_buffer::
  392. (set-current-buffer BUFFER [WINDOW])
  393. Set the buffer that WINDOW (or the current window) is displaying. Returns
  394. the buffer which was being displayed before.
  395. ::end:: */
  396. {
  397.     VALUE old;
  398.     DECLARE1(tx, BUFFERP);
  399.     if(!WINDOWP(vw))
  400.     vw = CurrVW;
  401.     old = VWIN(vw)->vw_Tx;
  402.     swapvwfiles(VWIN(vw), VTX(tx));
  403.     return(old);
  404. }
  405.  
  406. _PR VALUE cmd_file_name(VALUE);
  407. DEFUN("file-name", cmd_file_name, subr_file_name, (VALUE tx), V_Subr1, DOC_file_name) /*
  408. ::doc:file_name::
  409. (file-name [BUFFER])
  410. Return the name of the file being edited in BUFFER.
  411. ::end:: */
  412. {
  413.     if(!BUFFERP(tx))
  414.     tx = CurrVW->vw_Tx;
  415.     return(VTX(tx)->tx_FileName);
  416. }
  417.  
  418. _PR VALUE cmd_set_file_name(VALUE, VALUE);
  419. DEFUN("set-file-name", cmd_set_file_name, subr_set_file_name, (VALUE tx, VALUE name), V_Subr2, DOC_set_file_name) /*
  420. ::doc:set_file_name::
  421. (set-file-name BUFFER NAME)
  422. Set the name of the file being edited in BUFFER to NAME.
  423. ::end:: */
  424. {
  425.     DECLARE1(name, STRINGP);
  426.     if(!BUFFERP(tx))
  427.     tx = CurrVW->vw_Tx;
  428.     makemarksnonres(VTX(tx));
  429.     VTX(tx)->tx_FileName = name;
  430.     makemarksres(VTX(tx));
  431.     return(name);
  432. }
  433.  
  434. _PR VALUE cmd_buffer_name(VALUE);
  435. DEFUN("buffer-name", cmd_buffer_name, subr_buffer_name, (VALUE tx), V_Subr1, DOC_buffer_name) /*
  436. ::doc:buffer_name::
  437. (buffer-name [BUFFER])
  438. Return the name of BUFFER.
  439. ::end:: */
  440. {
  441.     if(!BUFFERP(tx))
  442.     tx = CurrVW->vw_Tx;
  443.     return(VTX(tx)->tx_BufferName);
  444. }
  445.  
  446. _PR VALUE cmd_set_buffer_name(VALUE, VALUE);
  447. DEFUN("set-buffer-name", cmd_set_buffer_name, subr_set_buffer_name, (VALUE tx, VALUE name), V_Subr2, DOC_set_buffer_name) /*
  448. ::doc:set_buffer_name::
  449. (set-buffer-name BUFFER NAME)
  450. Set the name of BUFFER to NAME.
  451. ::end:: */
  452. {
  453.     DECLARE1(name, STRINGP);
  454.     if(!BUFFERP(tx))
  455.     tx = CurrVW->vw_Tx;
  456.     VTX(tx)->tx_BufferName = name;
  457.     resetslptxtitles(VTX(tx));
  458.     return(name);
  459. }
  460.  
  461. _PR VALUE cmd_buffer_changes(VALUE);
  462. DEFUN("buffer-changes", cmd_buffer_changes, subr_buffer_changes, (VALUE tx), V_Subr1, DOC_buffer_changes) /*
  463. ::doc:buffer_changes::
  464. (buffer-changes [BUFFER])
  465. Return the number of modifications to BUFFER.
  466. ::end:: */
  467. {
  468.     if(!BUFFERP(tx))
  469.     tx = CurrVW->vw_Tx;
  470.     return(newnumber(VTX(tx)->tx_Changes));
  471. }
  472.  
  473. _PR VALUE cmd_buffer_modified_p(VALUE);
  474. DEFUN("buffer-modified-p", cmd_buffer_modified_p, subr_buffer_modified_p, (VALUE tx), V_Subr1, DOC_buffer_modified_p) /*
  475. ::doc:buffer_modified_p::
  476. (buffer-modified-p [BUFFER])
  477. Returns t if the buffer has changed since it was last saved.
  478. ::end:: */
  479. {
  480.     if(!BUFFERP(tx))
  481.     tx = CurrVW->vw_Tx;
  482.     /* TXFF_SPECIAL means this buffer's modifications aren't important. */
  483.     if(VTX(tx)->tx_Flags & TXFF_SPECIAL)
  484.     return(sym_nil);
  485.     if(VTX(tx)->tx_Changes != VTX(tx)->tx_ProperSaveChanges)
  486.     return(sym_t);
  487.     return(sym_nil);
  488. }
  489.  
  490. _PR VALUE cmd_set_buffer_modified(VALUE, VALUE);
  491. DEFUN("set-buffer-modified", cmd_set_buffer_modified, subr_set_buffer_modified, (VALUE tx, VALUE stat), V_Subr2, DOC_set_buffer_modified) /*
  492. ::doc:set_buffer_modified::
  493. (set-buffer-modified BUFFER STATUS)
  494. If STATUS is nil make it look as though buffer hasn't changed, else make
  495. it look as though it has.
  496. ::end:: */
  497. {
  498.     if(!BUFFERP(tx))
  499.     tx = CurrVW->vw_Tx;
  500.     if(NILP(stat))
  501.     {
  502.     VTX(tx)->tx_ProperSaveChanges = VTX(tx)->tx_Changes;
  503.     VTX(tx)->tx_LastSaveChanges = VTX(tx)->tx_Changes;
  504.     }
  505.     else
  506.     {
  507.     VTX(tx)->tx_ProperSaveChanges = VTX(tx)->tx_Changes - 1;
  508.     VTX(tx)->tx_LastSaveChanges = VTX(tx)->tx_Changes - 1;
  509.     }
  510.     return(tx);
  511. }
  512.  
  513. _PR VALUE cmd_set_buffer_special(VALUE tx, VALUE specialp);
  514. DEFUN("set-buffer-special", cmd_set_buffer_special, subr_set_buffer_special, (VALUE tx, VALUE specialp), V_Subr2, DOC_set_buffer_special) /*
  515. ::doc:set_buffer_special::
  516. (set-buffer-special BUFFER SPECIALP)
  517. When a buffer is `special' it means that it is controlled by some Lisp code,
  518. not by the user typing into it (although this can still happen as well). This
  519. is used for things like the `*jade*' or `*Info*' buffers (in fact most of
  520. the buffers whose names are surrounded by asterisks are special).
  521.  
  522. What the `special' attribute actually does is make sure that the buffer is
  523. never truely killed (`kill-buffer' removes it from each window's `buffer-list'
  524. but doesn't detroy the actual contents) and modifications don't cause the
  525. `+' marker to appear in the status line.
  526. ::end:: */
  527. {
  528.     if(!BUFFERP(tx))
  529.     tx = CurrVW->vw_Tx;
  530.     if(NILP(specialp))
  531.     VTX(tx)->tx_Flags &= ~TXFF_SPECIAL;
  532.     else
  533.     VTX(tx)->tx_Flags |= TXFF_SPECIAL;
  534.     return(tx);
  535. }
  536.  
  537. _PR VALUE cmd_buffer_special_p(VALUE tx);
  538. DEFUN("buffer-special-p", cmd_buffer_special_p, subr_buffer_special_p, (VALUE tx), V_Subr1, DOC_buffer_special_p) /*
  539. ::doc:buffer_special_p::
  540. (buffer-special-p [BUFFER])
  541. Returns t if BUFFER is ``special''. See `set-buffer-special' for the meaning of
  542. the ``special'' attribute.
  543. ::end:: */
  544. {
  545.     if(!BUFFERP(tx))
  546.     tx = CurrVW->vw_Tx;
  547.     if(VTX(tx)->tx_Flags & TXFF_SPECIAL)
  548.     return(sym_t);
  549.     return(sym_nil);
  550. }
  551.  
  552. _PR VALUE cmd_set_buffer_read_only(VALUE tx, VALUE stat);
  553. DEFUN("set-buffer-read-only", cmd_set_buffer_read_only, subr_set_buffer_read_only, (VALUE tx, VALUE stat), V_Subr2, DOC_set_buffer_read_only) /*
  554. ::doc:set_buffer_read_only::
  555. (set-buffer-read-only BUFFER READ-ONLY-P)
  556. If a buffer is read-only no modification of its contents is allowed.
  557. ::end:: */
  558. {
  559.     if(!BUFFERP(tx))
  560.     tx = CurrVW->vw_Tx;
  561.     if(NILP(stat))
  562.     VTX(tx)->tx_Flags &= ~TXFF_RDONLY;
  563.     else
  564.     VTX(tx)->tx_Flags |= TXFF_RDONLY;
  565.     return(tx);
  566. }
  567.  
  568. _PR VALUE cmd_buffer_read_only_p(VALUE tx);
  569. DEFUN("buffer-read-only-p", cmd_buffer_read_only_p, subr_buffer_read_only_p, (VALUE tx), V_Subr1, DOC_buffer_read_only_p) /*
  570. ::doc:buffer_read_only_p::
  571. (buffer-read-only-p [BUFFER])
  572. Returns t if BUFFER is read-only. See `set-buffer-read-only'.
  573. ::end:: */
  574. {
  575.     if(!BUFFERP(tx))
  576.     tx = CurrVW->vw_Tx;
  577.     if(VTX(tx)->tx_Flags & TXFF_RDONLY)
  578.     return(sym_t);
  579.     return(sym_nil);
  580. }
  581.  
  582. _PR VALUE cmd_file_length(VALUE);
  583. DEFUN("file-length", cmd_file_length, subr_file_length, (VALUE tx), V_Subr1, DOC_file_length) /*
  584. ::doc:file_length::
  585. (file-length [BUFFER])
  586. Returns the number of lines in BUFFER.
  587. ::end:: */
  588. {
  589.     if(!BUFFERP(tx))
  590.     tx = CurrVW->vw_Tx;
  591.     return(newnumber(VTX(tx)->tx_NumLines));
  592. }
  593.  
  594. _PR VALUE cmd_line_length(VALUE, VALUE);
  595. DEFUN("line-length", cmd_line_length, subr_line_length, (VALUE pos, VALUE tx), V_Subr2, DOC_line_length) /*
  596. ::doc:line_length::
  597. (line-length [LINE-POS] [BUFFER])
  598. Returns the length (not including newline) of the specified line, or
  599. using current cursor position if specifiers are not provided.
  600. ::end:: */
  601. {
  602.     POS p;
  603.     if(POSP(pos))
  604.     {
  605.     if(!BUFFERP(tx))
  606.         tx = CurrVW->vw_Tx;
  607.     p = VPOS(pos);
  608.     }
  609.     else
  610.     {
  611.     p = CurrVW->vw_CursorPos;
  612.     tx = CurrVW->vw_Tx;
  613.     }
  614.     return(newnumber(VTX(tx)->tx_Lines[p.pos_Line].ln_Strlen - 1));
  615. }
  616.  
  617. _PR VALUE cmd_with_buffer(VALUE);
  618. DEFUN("with-buffer", cmd_with_buffer, subr_with_buffer, (VALUE args), V_SF, DOC_with_buffer) /*
  619. ::doc:with_buffer::
  620. (with-buffer BUFFER FORMS...) <SPECIAL-FORM>
  621. Temporarily switches to buffer, then executes the FORMS in it before 
  622. returning to the original buffer.
  623. ::end:: */
  624. {
  625.     if(CONSP(args))
  626.     {
  627.     GCVAL gcv_args;
  628.     VALUE res;
  629.     PUSHGC(gcv_args, args);
  630.     if((res = cmd_eval(VCAR(args))) && BUFFERP(res))
  631.     {
  632.         VALUE oldtx = swapvwfilesnd(CurrVW, VTX(res));
  633.         if(oldtx)
  634.         {
  635.         GCVAL gcv_oldtx;
  636.         PUSHGC(gcv_oldtx, oldtx);
  637.         res = cmd_progn(VCDR(args));
  638.         POPGC;
  639.         swapvwfilesnd(CurrVW, VTX(oldtx));
  640.         }
  641.     }
  642.     POPGC;
  643.     return(res);
  644.     }
  645.     return(NULL);
  646. }
  647.  
  648. _PR VALUE cmd_bufferp(VALUE);
  649. DEFUN("bufferp", cmd_bufferp, subr_bufferp, (VALUE arg), V_Subr1, DOC_bufferp) /*
  650. ::doc:bufferp::
  651. (bufferp ARG)
  652. Returns t if ARG is a buffer.
  653. ::end:: */
  654. {
  655.     if(BUFFERP(arg))
  656.     return(sym_t);
  657.     return(sym_nil);
  658. }
  659.  
  660. _PR VALUE var_auto_save_interval(VALUE);
  661. DEFUN("auto-save-interval", var_auto_save_interval, subr_auto_save_interval, (VALUE val), V_Var, DOC_auto_save_interval) /*
  662. ::doc:auto_save_interval::
  663. The number of modifications which must be made to a buffer before it
  664. is considered for auto-saving. A value of zero means that this buffer
  665. is not to be auto-saved.
  666. ::end:: */
  667. {
  668.     return(handlevarint(val, &CurrVW->vw_Tx->tx_AutoSaveInterval));
  669. }
  670.  
  671. _PR VALUE var_last_save_changes(VALUE);
  672. DEFUN("last-save-changes", var_last_save_changes, subr_last_save_changes, (VALUE val), V_Var, DOC_last_save_changes) /*
  673. ::doc:last_save_changes::
  674. Number of changes the last time this buffer was saved (could be auto-save).
  675. ::end:: */
  676. {
  677.     return(handlevarint(val, &CurrVW->vw_Tx->tx_LastSaveChanges));
  678. }
  679.  
  680. _PR VALUE var_last_user_save_changes(VALUE);
  681. DEFUN("last-user-save-changes", var_last_user_save_changes, subr_last_user_save_changes, (VALUE val), V_Var, DOC_last_user_save_changes) /*
  682. ::doc:last_user_save_changes::
  683. Number of changes the last time this buffer was saved (not from auto-save).
  684. ::end:: */
  685. {
  686.     return(handlevarint(val, &CurrVW->vw_Tx->tx_ProperSaveChanges));
  687. }
  688.  
  689. _PR VALUE var_last_save_time(VALUE);
  690. DEFUN("last-save-time", var_last_save_time, subr_last_save_time, (VALUE val), V_Var, DOC_last_save_time) /*
  691. ::doc:last_save_time::
  692. System time at last save of this buffer (could be from an auto-save).
  693. ::end:: */
  694. {
  695.     return(handlevarint(val, &CurrVW->vw_Tx->tx_LastSaveTime));
  696. }
  697.  
  698. _PR VALUE var_screen_tab(VALUE);
  699. DEFUN("screen-tab", var_screen_tab, subr_screen_tab, (VALUE val), V_Var, DOC_screen_tab) /*
  700. ::doc:screen_tab::
  701. Sets the size of tab-stops for the `left-tab' and `right-tab' commands.
  702. ::end:: */
  703. {
  704.     return(handlevarint(val, &CurrVW->vw_Tx->tx_TabSize));
  705. }
  706.  
  707. _PR VALUE var_disk_tab(VALUE);
  708. DEFUN("disk-tab", var_disk_tab, subr_disk_tab, (VALUE val), V_Var, DOC_disk_tab) /*
  709. ::doc:disk_tab::
  710. Sets the size of the tab-stops used when loading and saving files in this
  711. buffer.
  712. ::end:: */
  713. {
  714.     return(handlevarint(val, &CurrVW->vw_Tx->tx_DiskTab));
  715. }
  716.  
  717. _PR VALUE var_save_tabs(VALUE);
  718. DEFUN("save-tabs", var_save_tabs, subr_save_tabs, (VALUE val), V_Var, DOC_save_tabs) /*
  719. ::doc:save_tabs::
  720. Defines whether or not tab characters (ASCII 9) are used when saving files,
  721. STATUS can be one of,
  722.      nil     NO tabs are used, all spaces are left intact.
  723.      leading All *leading* spaces in each line will be optimised into
  724.          tabs.
  725.      all     All groups of spaces (except after any quotes) are changed
  726.          to tabs wherever possible.
  727. ::end:: */
  728. {
  729.     if(val)
  730.     {
  731.     int st;
  732.     if(SYMBOLP(val))
  733.     {
  734.         switch(VSTR(VSYM(val)->sym_Name)[0])
  735.         {
  736.         case 'n': /* nil */
  737.         st = 0;
  738.         break;
  739.         case 'l': /* leading */
  740.         st = 1;
  741.         break;
  742.         case 'a': /* all */
  743.         st = 2;
  744.         break;
  745.         default:
  746.         return(NULL);
  747.         }
  748.     }
  749.     else if(NUMBERP(val))
  750.         st = VNUM(val);
  751.     else
  752.         return(NULL);
  753.     CurrVW->vw_Tx->tx_SaveTabs = st;
  754.     return(val);
  755.     }
  756.     switch(CurrVW->vw_Tx->tx_SaveTabs)
  757.     {
  758.     case 0:
  759.     return(sym_nil);
  760.     case 1:
  761.     return(sym_leading);
  762.     case 2:
  763.     return(sym_all);
  764.     }
  765.     return(NULL);
  766. }
  767.  
  768. _PR VALUE var_mode_name(VALUE);
  769. DEFUN("mode-name", var_mode_name, subr_mode_name, (VALUE val), V_Var, DOC_mode_name) /*
  770. ::doc:mode_name::
  771. This is used to display the name of the edit-mode being used in the status
  772. line.
  773. ::end:: */
  774. {
  775.     TX *tx = CurrVW->vw_Tx;
  776.     if(val)
  777.     {
  778.     if(STRINGP(val))
  779.         tx->tx_ModeName = val;
  780.     else
  781.         tx->tx_ModeName = NULL;
  782.     return(val);
  783.     }
  784.     else if(tx->tx_ModeName)
  785.     return(tx->tx_ModeName);
  786.     return(sym_nil);
  787. }
  788.  
  789. /* chain of all non-resident marks, linked via `mk_Next' */
  790. Mark *NRMarkChain;
  791. /* chain of all marks, linked via `mk_NextAlloc' */
  792. Mark *MarkChain;
  793.  
  794. /*
  795.  * For all non-resident marks, see if any point to NEWTX, if so link them
  796.  * onto NEWTX's `tx_Marks' chain.
  797.  */
  798. void
  799. makemarksres(TX *newtx)
  800. {
  801.     Mark *nxt, *mk = NRMarkChain;
  802.     NRMarkChain = NULL;
  803.     while(mk)
  804.     {
  805.     nxt = mk->mk_Next;
  806.     if(samefiles(VSTR(newtx->tx_FileName), VSTR(mk->mk_File.name)))
  807.     {
  808.         mk->mk_File.tx = newtx;
  809.         mk->mk_Resident = TRUE;
  810.         mk->mk_Next = newtx->tx_MarkChain;
  811.         newtx->tx_MarkChain = mk;
  812.     }
  813.     else
  814.     {
  815.         mk->mk_Next = NRMarkChain;
  816.         NRMarkChain = mk;
  817.     }
  818.     mk = nxt;
  819.     }
  820. }
  821.  
  822. void
  823. makemarksnonres(TX *oldtx)
  824. {
  825.     Mark *nxt, *mk = oldtx->tx_MarkChain;
  826.     oldtx->tx_MarkChain = NULL;
  827.     while(mk)
  828.     {
  829.     nxt = mk->mk_Next;
  830.     mk->mk_File.name = oldtx->tx_FileName;
  831.     mk->mk_Resident = FALSE;
  832.     mk->mk_Next = NRMarkChain;
  833.     NRMarkChain = mk;
  834.     mk = nxt;
  835.     }
  836. }
  837.  
  838. /*
  839.  * Takes MK off the buffer mark chain that it's on (or the NRMarkChain).
  840.  */
  841. static void
  842. unchainmark(Mark *mk)
  843. {
  844.     Mark **headp, *this;
  845.     if(!mk->mk_Resident)
  846.     headp = &NRMarkChain;
  847.     else
  848.     headp = &(mk->mk_File.tx->tx_MarkChain);
  849.     this = *headp;
  850.     *headp = NULL;
  851.     while(this)
  852.     {
  853.     Mark *tmp = this->mk_Next;
  854.     if(this != mk)
  855.     {
  856.         this->mk_Next = *headp;
  857.         *headp = this;
  858.     }
  859.     this = tmp;
  860.     }
  861. }
  862.  
  863. void
  864. mark_sweep(void)
  865. {
  866.     Mark *mk = MarkChain;
  867.     MarkChain = NULL;
  868.     while(mk)
  869.     {
  870.     Mark *nxt = mk->mk_NextAlloc;
  871.     if(!GC_MARKEDP(mk))
  872.     {
  873.         unchainmark(mk);
  874.         mystrfree(mk);
  875.     }
  876.     else
  877.     {
  878.         GC_CLR(mk);
  879.         mk->mk_NextAlloc = MarkChain;
  880.         MarkChain = mk;
  881.     }
  882.     mk = nxt;
  883.     }
  884. }
  885. int
  886. mark_cmp(VALUE v1, VALUE v2)
  887. {
  888.     int rc = 1;
  889.     if(VTYPE(v1) == VTYPE(v2))
  890.     {
  891.     u_char *name1, *name2;
  892.     if(VMARK(v1)->mk_Resident)
  893.         name1 = VSTR(VMARK(v1)->mk_File.tx->tx_FileName);
  894.     else
  895.         name1 = VSTR(VMARK(v1)->mk_File.name);
  896.     if(VMARK(v2)->mk_Resident)
  897.         name2 = VSTR(VMARK(v2)->mk_File.tx->tx_FileName);
  898.     else
  899.         name2 = VSTR(VMARK(v2)->mk_File.name);
  900.     if(samefiles(name1, name2))
  901.     {
  902.         if(!(rc = VPOS(VMARK(v1)->mk_Pos).pos_Line - VPOS(VMARK(v2)->mk_Pos).pos_Line))
  903.         rc = VPOS(VMARK(v1)->mk_Pos).pos_Col - VPOS(VMARK(v2)->mk_Pos).pos_Col;
  904.     }
  905.     }
  906.     return(rc);
  907. }
  908. void
  909. mark_prin(VALUE strm, VALUE obj)
  910. {
  911.     u_char tbuf[40];
  912.     streamputs(strm, "#<mark ", FALSE);
  913.     if(VMARK(obj)->mk_Resident)
  914.     {
  915.     if(VMARK(obj)->mk_File.tx->tx_FileName)
  916.     {
  917.         streamputc(strm, '"');
  918.         streamputs(strm, VSTR(VMARK(obj)->mk_File.tx->tx_FileName), TRUE);
  919.         streamputc(strm, '"');
  920.     }
  921.     else
  922.         streamputs(strm, VSTR(VMARK(obj)->mk_File.tx->tx_BufferName), TRUE);
  923.     }
  924.     else
  925.     {
  926.     streamputc(strm, '"');
  927.     streamputs(strm, VSTR(VMARK(obj)->mk_File.name), TRUE);
  928.     streamputc(strm, '"');
  929.     }
  930.     sprintf(tbuf, " #<pos %ld %ld>>",
  931.         VPOS(VMARK(obj)->mk_Pos).pos_Col + 1,
  932.         VPOS(VMARK(obj)->mk_Pos).pos_Line + 1);
  933.     streamputs(strm, tbuf, FALSE);
  934. }
  935.  
  936. _PR VALUE cmd_make_mark(VALUE, VALUE);
  937. DEFUN("make-mark", cmd_make_mark, subr_make_mark, (VALUE pos, VALUE buffer), V_Subr2, DOC_make_mark) /*
  938. ::doc:make_mark::
  939. (make-mark [POS] [BUFFER | FILE-NAME])
  940. Creates a new mark pointing to position POS either in the current file
  941. or in FILE-NAME, or BUFFER.
  942.  
  943. Note that FILE-NAME doesn't have to be a file that has been loaded, it's
  944. stored as a string, the file it points to is only opened when needed.
  945.  
  946. Unlike position objects, the position in a file that a mark points to is
  947. updated as the file changes -- it will always point to the same character
  948. (for as long as that character exists, anyway).
  949. ::end:: */
  950. {
  951.     Mark *mk = NULL;
  952.     if((mk = mystralloc(sizeof(Mark))) && (mk->mk_Pos = newlpos(NULL)))
  953.     {
  954.     mk->mk_Type = V_Mark;
  955.     mk->mk_NextAlloc = MarkChain;
  956.     MarkChain = mk;
  957.     DataAfterGC += sizeof(Mark);
  958.     if(POSP(pos))
  959.         VPOS(mk->mk_Pos) = VPOS(pos);
  960.     else
  961.         VPOS(mk->mk_Pos) = CurrVW->vw_CursorPos;
  962.     if(STRINGP(buffer))
  963.     {
  964.         VALUE tx;
  965.         if((tx = cmd_get_file_buffer(buffer)) && BUFFERP(tx))
  966.         {
  967.         mk->mk_Resident = TRUE;
  968.         mk->mk_File.tx = VTX(tx);
  969.         mk->mk_Next = VTX(tx)->tx_MarkChain;
  970.         VTX(tx)->tx_MarkChain = mk;
  971.         }
  972.         else
  973.         {
  974.         mk->mk_Resident = FALSE;
  975.         mk->mk_File.name = buffer;
  976.         mk->mk_Next = NRMarkChain;
  977.         NRMarkChain = mk;
  978.         }
  979.     }
  980.     else
  981.     {
  982.         if(!BUFFERP(buffer))
  983.         buffer = CurrVW->vw_Tx;
  984.         mk->mk_Resident = TRUE;
  985.         mk->mk_File.tx = VTX(buffer);
  986.         mk->mk_Next = VTX(buffer)->tx_MarkChain;
  987.         VTX(buffer)->tx_MarkChain = mk;
  988.     }
  989.     return(mk);
  990.     }
  991.     if(mk)
  992.     mystrfree(mk);
  993.     return(NULL);
  994. }
  995.  
  996. _PR VALUE cmd_set_mark(VALUE, VALUE, VALUE);
  997. DEFUN("set-mark", cmd_set_mark, subr_set_mark, (VALUE mark, VALUE pos, VALUE buffer), V_Subr3, DOC_set_mark) /*
  998. ::doc:set_mark::
  999. (set-mark MARK [POS] [FILE-NAME | BUFFER])
  1000. Sets the position which MARK points to POS in FILE-NAME or BUFFER.
  1001. ::end:: */
  1002. {
  1003.     DECLARE1(mark, MARKP);
  1004.     if(POSP(pos))
  1005.     VPOS(VMARK(mark)->mk_Pos) = VPOS(pos);
  1006.     if(BUFFERP(buffer) || STRINGP(buffer))
  1007.     {
  1008.     Mark *mk, *nxt, **chain;
  1009.     if(VMARK(mark)->mk_Resident)
  1010.         chain = &(VMARK(mark)->mk_File.tx->tx_MarkChain);
  1011.     else
  1012.         chain = &NRMarkChain;
  1013.     mk = *chain;
  1014.     *chain = NULL;
  1015.     while(mk)
  1016.     {
  1017.         nxt = mk->mk_Next;
  1018.         if(mk != mark)
  1019.         {
  1020.         mk->mk_Next = *chain;
  1021.         *chain = mk;
  1022.         }
  1023.         else
  1024.         mk->mk_Next = NULL;
  1025.         mk = nxt;
  1026.     }
  1027.     switch(VTYPE(buffer))
  1028.     {
  1029.     case V_StaticString:
  1030.     case V_String:
  1031.         if(!(VMARK(mark)->mk_File.tx = cmd_get_file_buffer(buffer)))
  1032.         {
  1033.         VMARK(mark)->mk_File.name = buffer;
  1034.         VMARK(mark)->mk_Resident = FALSE;
  1035.         VMARK(mark)->mk_Next = NRMarkChain;
  1036.         NRMarkChain = mark;
  1037.         break;
  1038.         }
  1039.         goto dotx;
  1040.     case V_TX:
  1041.         VMARK(mark)->mk_File.tx = buffer;
  1042. dotx:
  1043.         VMARK(mark)->mk_Resident = TRUE;
  1044.         VMARK(mark)->mk_Next = VMARK(mark)->mk_File.tx->tx_MarkChain;
  1045.         VMARK(mark)->mk_File.tx->tx_MarkChain = mark;
  1046.         break;
  1047.     }
  1048.     }
  1049.     return(mark);
  1050. }
  1051.  
  1052. _PR VALUE cmd_mark_pos(VALUE);
  1053. DEFUN("mark-pos", cmd_mark_pos, subr_mark_pos, (VALUE mark), V_Subr1, DOC_mark_pos) /*
  1054. ::doc:mark_pos::
  1055. (mark-pos MARK)
  1056. Returns the position that MARK points to. (note that this is the *same*
  1057. object that the mark stores internally -- so don't modify it unless you're
  1058. really sure you know what you're doing)
  1059. ::end:: */
  1060. {
  1061.     DECLARE1(mark, MARKP);
  1062.     return(VMARK(mark)->mk_Pos);
  1063. }
  1064.  
  1065. _PR VALUE cmd_mark_file(VALUE);
  1066. DEFUN("mark-file", cmd_mark_file, subr_mark_file, (VALUE mark), V_Subr1, DOC_mark_file) /*
  1067. ::doc:mark_file::
  1068. (mark-file MARK)
  1069. Returns the file-name or buffer that MARK points to.
  1070. ::end:: */
  1071. {
  1072.     DECLARE1(mark, MARKP);
  1073.     return(VMARK(mark)->mk_File.name);
  1074. }
  1075.  
  1076. _PR VALUE cmd_mark_resident_p(VALUE);
  1077. DEFUN("mark-resident-p", cmd_mark_resident_p, subr_mark_resident_p, (VALUE mark), V_Subr1, DOC_mark_resident_p) /*
  1078. ::doc:mark_resident_p::
  1079. (mark-resident-p MARK)
  1080. Returns t if the file that MARK points to is in a buffer.
  1081. ::end:: */
  1082. {
  1083.     DECLARE1(mark, MARKP);
  1084.     if(VMARK(mark)->mk_Resident)
  1085.     return(sym_t);
  1086.     return(sym_nil);
  1087. }
  1088.  
  1089. _PR VALUE cmd_markp(VALUE);
  1090. DEFUN("markp", cmd_markp, subr_markp, (VALUE mark), V_Subr1, DOC_markp) /*
  1091. ::doc:markp::
  1092. (markp ARG)
  1093. Return t if ARG is a mark.
  1094. ::end:: */
  1095. {
  1096.     if(MARKP(mark))
  1097.     return(sym_t);
  1098.     return(sym_nil);
  1099. }
  1100.  
  1101. void
  1102. buffers_init(void)
  1103. {
  1104.     markstatic((VALUE *)&NRMarkChain);
  1105.     INTERN(sym_auto_save_function, "auto-save-function");
  1106.     INTERN(sym_no_file_code_p, "no-file-code-p");
  1107.     INTERN(sym_leading, "leading");
  1108.     INTERN(sym_all, "all");
  1109.     ADD_SUBR(subr_make_buffer_name);
  1110.     ADD_SUBR(subr_make_buffer);
  1111.     ADD_SUBR(subr_destroy_buffer);
  1112.     ADD_SUBR(subr_get_file_buffer);
  1113.     ADD_SUBR(subr_get_buffer);
  1114.     ADD_SUBR(subr_current_buffer);
  1115.     ADD_SUBR(subr_set_current_buffer);
  1116.     ADD_SUBR(subr_file_name);
  1117.     ADD_SUBR(subr_set_file_name);
  1118.     ADD_SUBR(subr_buffer_name);
  1119.     ADD_SUBR(subr_set_buffer_name);
  1120.     ADD_SUBR(subr_buffer_changes);
  1121.     ADD_SUBR(subr_buffer_modified_p);
  1122.     ADD_SUBR(subr_set_buffer_modified);
  1123.     ADD_SUBR(subr_set_buffer_special);
  1124.     ADD_SUBR(subr_buffer_special_p);
  1125.     ADD_SUBR(subr_set_buffer_read_only);
  1126.     ADD_SUBR(subr_buffer_read_only_p);
  1127.     ADD_SUBR(subr_file_length);
  1128.     ADD_SUBR(subr_line_length);
  1129.     ADD_SUBR(subr_with_buffer);
  1130.     ADD_SUBR(subr_bufferp);
  1131.     ADD_SUBR(subr_auto_save_interval);
  1132.     ADD_SUBR(subr_last_save_changes);
  1133.     ADD_SUBR(subr_last_user_save_changes);
  1134.     ADD_SUBR(subr_last_save_time);
  1135.     ADD_SUBR(subr_screen_tab);
  1136.     ADD_SUBR(subr_disk_tab);
  1137.     ADD_SUBR(subr_save_tabs);
  1138.     ADD_SUBR(subr_mode_name);
  1139.     ADD_SUBR(subr_make_mark);
  1140.     ADD_SUBR(subr_set_mark);
  1141.     ADD_SUBR(subr_mark_pos);
  1142.     ADD_SUBR(subr_mark_file);
  1143.     ADD_SUBR(subr_mark_resident_p);
  1144.     ADD_SUBR(subr_markp);
  1145. }
  1146. void
  1147. buffers_kill(void)
  1148. {
  1149.     TX *tx = BufferChain;
  1150.     Mark *mk = MarkChain;
  1151.     while(tx)
  1152.     {
  1153.     TX *nxttx = tx->tx_Next;
  1154.     killlinelist(tx);
  1155.     myfree(tx);
  1156.     tx = nxttx;
  1157.     }
  1158.     while(mk)
  1159.     {
  1160.     Mark *nxtmk = mk->mk_NextAlloc;
  1161.     mystrfree(mk);
  1162.     mk = nxtmk;
  1163.     }
  1164. }
  1165.