home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / AP / JED / JED097-1.TAR / jed / src / paste.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-12  |  16.7 KB  |  905 lines

  1. /*
  2.  *  Copyright (c) 1992, 1994 John E. Davis  (davis@amy.tch.harvard.edu)
  3.  *  All Rights Reserved.
  4.  */
  5.     
  6. #include <stdio.h>
  7. #include <string.h>
  8.  
  9. #include "config.h"
  10. #include "buffer.h"
  11. #include "ins.h"
  12. #include "line.h"
  13. #include "paste.h"
  14. #include "screen.h"
  15. #include "misc.h"
  16. #include "cmds.h"
  17.  
  18. /* SLang user object be larger than 100 */
  19. #define JED_MARK_TYPE 100
  20.  
  21. Buffer *Paste_Buffer;
  22. Buffer *Rectangle_Buffer;
  23.  
  24.  
  25.  
  26. /* This is used by the narrow command so that multiple windows are 
  27.  * handled properly. The assumption is that we are dealing with a canonical
  28.  * region */
  29.       
  30. void touch_windows(void)
  31. {
  32.    Window_Type *w;
  33.    Line *l;
  34.    unsigned int n;
  35.    
  36.    w = JWindow;
  37.    JWindow = JWindow->next;
  38.    while (JWindow != w)
  39.      {
  40.     if (CBuf == JWindow->buffer)
  41.       {
  42.          /* The mark is set with line at top of buffer */
  43.          l = CBuf->marks->line;
  44.          n = CBuf->marks->n;
  45.          while ((l != NULL) && (l != JWindow->mark.line)) l = l->next, n++;
  46.          if (l == NULL) 
  47.            {
  48.           JWindow->mark.line = CLine;
  49.           JWindow->mark.point = Point;
  50.           JWindow->mark.n = n - 1;
  51.            }
  52.          touch_window();
  53.       }
  54.     JWindow = JWindow->next;
  55.      }
  56.    pop_mark(&Number_Zero);
  57. }
  58.  
  59.  
  60. int line_in_buffer(Line *line)
  61. {
  62.    Line *l;
  63.    
  64.    l = CBuf->beg;
  65.    while (l != NULL) if (l == line) return(1); else l = l->next;
  66.    return(0);
  67. }
  68.  
  69.  
  70. /* with prefix argument, pop marks */
  71. int set_mark_cmd()
  72. {
  73.    Mark *m;
  74.    if (Repeat_Factor != NULL)
  75.      {
  76.     while (CBuf->marks != NULL) pop_mark(&Number_Zero);
  77.     Repeat_Factor = NULL;
  78.     return(1);
  79.      }
  80.    
  81.    if (CBuf->marks == NULL)
  82.      {
  83.     push_mark();
  84.      }
  85.    m = CBuf->marks;
  86.    m->line = CLine;
  87.    m->point = Point;
  88.    m->n = LineNum + CBuf->nup;
  89.    if ((m->flags & VISIBLE_MARK) == 0) 
  90.      {
  91.     m->flags |= VISIBLE_MARK;
  92.     CBuf->vis_marks++;
  93.      }
  94.    
  95.    /* if (m != CBuf->marks) m->next = CBuf->marks;
  96.     CBuf->marks = m; */
  97.    if (Last_Key_Function == (VOID *) set_mark_cmd) message("Mark Set.");
  98.    return(1);
  99. }
  100.  
  101. int push_spot()
  102. {
  103.     Mark *m;
  104.  
  105.    if (CBuf->spot_ptr < SPOT_ARRAY_SIZE)
  106.      {
  107.     m = &CBuf->spot_array[CBuf->spot_ptr++];
  108.      }
  109.    else if (NULL == (m = (Mark *) SLMALLOC(sizeof(Mark))))
  110.       {
  111.       exit_error("push_spot: malloc error!", 0);
  112.       }
  113.  
  114.    m->line = CLine;
  115.    m->point = Point;
  116.    m->n = LineNum + CBuf->nup;
  117.    m->next = CBuf->spots;
  118.    CBuf->spots = m;
  119.    return(1);
  120. }
  121.  
  122. int push_mark()
  123. {
  124.     Mark *m;
  125.  
  126.    if (CBuf->mark_ptr < SPOT_ARRAY_SIZE)
  127.      {
  128.     m = &CBuf->mark_array[CBuf->mark_ptr++];
  129.      }
  130.    else if (NULL == (m = (Mark *) SLMALLOC(sizeof(Mark))))
  131.      {
  132.     exit_error("push_mark: malloc error!", 0);
  133.      }
  134.    /*
  135.     if (NULL == (m = (Mark *) SLMALLOC(sizeof(Mark))))
  136.       {
  137.      msg_error("push_mark: malloc error!");
  138.      return(0);
  139.       } */
  140.  
  141.    m->line = CLine;
  142.    m->point = Point;
  143.    m->n = LineNum + CBuf->nup;
  144.    m->next = CBuf->marks;
  145.    m->flags = 0;
  146.    CBuf->marks = m;
  147.    return(1);
  148. }
  149.  
  150. void goto_mark(Mark *m)
  151. {
  152.    Line *l;
  153.    
  154.    l = m->line;
  155.    LineNum = m->n;
  156.     
  157.    if (LineNum <= CBuf->nup) bob();
  158.    else if (LineNum > CBuf->nup + Max_LineNum) eob();
  159.    else
  160.      {
  161.     CLine = l;
  162.     Point = m->point;
  163.     LineNum -= CBuf->nup;
  164.      }
  165. }
  166.  
  167. int pop_mark(int *go)
  168. {
  169.    Mark *m;
  170.    
  171.    m = CBuf->marks;
  172.    if (m == NULL) return(0);
  173.  
  174.    if (*go) goto_mark(m);
  175.    if (m->flags & VISIBLE_MARK)
  176.      {
  177.     CBuf->vis_marks--;
  178.     /* touch screen since region may be highlighted */
  179.     if (CBuf->vis_marks == 0) touch_screen();
  180.      }
  181.    
  182.    CBuf->marks = m->next;
  183.    if (m == &CBuf->mark_array[CBuf->mark_ptr - 1])
  184.      {
  185.     CBuf->mark_ptr--;
  186.      }
  187.    else SLFREE(m);
  188.    return(1);
  189. }
  190.  
  191. int mark_spot()
  192. {
  193.     push_spot();
  194.     message("Spot Marked.");
  195.     return(1);
  196. }
  197.  
  198. int pop_spot()
  199. {
  200.    Mark *m;
  201.    
  202.    m = CBuf->spots;
  203.    if (m == NULL) return(0);
  204.    
  205.    goto_mark (m);
  206.    
  207.    CBuf->spots = m->next;
  208.    
  209.    if (m == &CBuf->spot_array[CBuf->spot_ptr - 1])
  210.      {
  211.     CBuf->spot_ptr--;
  212.      }
  213.    else SLFREE(m);
  214.    return(1);
  215. }
  216.  
  217. int exchange_point_mark(void)
  218. {
  219.    Line *save_line;
  220.    int save_point;
  221.    unsigned int save_n;
  222.    Mark *m;
  223.    
  224.    if ((m = CBuf->marks) == NULL) return(0);
  225.    
  226.    save_point = Point;
  227.    save_line = CLine;
  228.    save_n = LineNum + CBuf->nup;
  229.    
  230.    goto_mark (m);
  231.    
  232.    m->point = save_point; m->line = save_line; m->n = save_n;
  233.    return(1);
  234. }
  235.  
  236.    
  237.  /*returns 0 if the mark is not set and gives error.  Exchanges point and mark
  238.   * to produce valid region.  A valid region is one with mark
  239.   * earlier in the buffer than point.  Always call this if using a region
  240.   * which reqires point > mark.  Also, push spot first then pop at end. 
  241.   */
  242. int check_region(int *push)
  243. {
  244.    register Line *beg, *tthis = CLine;
  245.    int pbeg;
  246.  
  247.    if (CBuf->marks == NULL)
  248.      {
  249.     msg_error("Set mark first.");
  250.     return(0);
  251.      }
  252.  
  253.    if (*push) push_spot();
  254.    beg = CBuf->marks->line;
  255.    pbeg = CBuf->marks->point;
  256.  
  257.    if (beg == CLine)
  258.      {
  259.     if (pbeg <= Point) return(1);
  260.      }
  261.  
  262.    else
  263.      {
  264.     while((beg != NULL) && (beg != tthis)) beg = beg->next;
  265.     if (beg == tthis) return(1);
  266.      }
  267.  
  268.    exchange_point_mark();
  269.    return(1);
  270. }
  271.  
  272.  
  273. int widen_buffer(Buffer *b)
  274. {
  275.    Narrow_Type *n;
  276.    Buffer *save = CBuf;
  277.    
  278.    if (NULL == (n = b->narrow)) return(0);
  279.    
  280.    /* make sure buffer ends in final newline */
  281.    
  282.    switch_to_buffer(b);
  283.    push_spot();
  284.    eob();
  285.    if ((n->end != NULL)
  286.        && (!CLine->len || ('\n' != *(CLine->data + (CLine->len - 1)))))
  287.      ins('\n');
  288.    
  289.    pop_spot();
  290.    
  291.    if (n->end != NULL) n->end->prev = b->end;
  292.    if (n->beg != NULL) n->beg->next = b->beg;
  293.    b->end->next = n->end;
  294.    b->beg->prev = n->beg;
  295.    b->beg = n->beg1;
  296.    if (n->end != NULL) b->end = n->end1;
  297.    
  298.    Max_LineNum += n->ndown + n->nup;
  299.    LineNum += n->nup;
  300.    
  301.    /* adjust absolute offsets */
  302.    b->nup -= n->nup;
  303.    b->ndown -= n->ndown;
  304.    b->narrow = n->next;
  305.    
  306.    SLFREE(n);
  307.    switch_to_buffer(save);
  308.    return(1);
  309. }
  310.    
  311. int widen()
  312. {
  313.    return widen_buffer(CBuf);
  314. }
  315.    
  316.  
  317. /* not really a region of points but a region of lines. */
  318. int narrow_to_region()
  319. {
  320.    Line *beg;
  321.    Narrow_Type *nt;
  322.    
  323.    if (NULL == (nt = (Narrow_Type *) SLMALLOC(sizeof(Narrow_Type))))
  324.      {
  325.     msg_error("Malloc Error during narrow.");
  326.     return(0);
  327.      }
  328.    
  329.    if (!check_region(&Number_One)) return(0);       /* spot pushed */
  330.  
  331.    push_spot();
  332.    pop_mark(&Number_One);
  333.    push_mark();                   /* popped and used in touch_windows! */
  334.    beg = CLine;
  335.    nt->nup = LineNum - 1;
  336.    
  337.    pop_spot();  /* eor now */
  338.    
  339.    nt->ndown = Max_LineNum - LineNum;
  340.  
  341.    Max_LineNum = LineNum = LineNum - nt->nup;
  342.    CBuf->nup += nt->nup;
  343.    CBuf->ndown += nt->ndown;
  344.    
  345.    
  346.    nt->next = CBuf->narrow;
  347.    CBuf->narrow = nt;
  348.    nt->beg = beg->prev;
  349.    nt->end = CLine->next;
  350.    nt->beg1 = CBuf->beg;
  351.    nt->end1 = CBuf->end;
  352.    
  353.    CBuf->beg = beg;
  354.    CBuf->end = CLine;
  355.    beg->prev = NULL;
  356.    CLine->next = NULL;
  357.    
  358.    pop_spot();
  359.    touch_windows();
  360.    return(1);
  361. }
  362.  
  363. int yank()
  364. {
  365.     if (Paste_Buffer == NULL) return(0);
  366.     insert_buffer(Paste_Buffer);
  367.     return(1);
  368. }
  369.  
  370. int copy_region_to_buffer(Buffer *b)
  371. {
  372.    int first_point, last_point, n, tmpm;
  373.    Line *first, *last;
  374.    Buffer *save_buffer;
  375.  
  376.    if (b->flags & READ_ONLY) 
  377.      {
  378.     msg_error(Read_Only_Error);
  379.     return (0);
  380.      }
  381.    
  382.    if (!check_region(&Number_One)) return(0);  /* spot pushed */
  383.    last = CLine;
  384.    last_point = Point;
  385.  
  386.    tmpm = 1; pop_mark(&tmpm);
  387.    if (b == CBuf)
  388.      {
  389.     msg_error("A buffer cannot be inserted upon itself.");
  390.     pop_spot();
  391.     return(0);
  392.      }
  393.  
  394.    first = CLine;
  395.    first_point = Point;
  396.  
  397.    save_buffer = CBuf;
  398.    switch_to_buffer(b);
  399.  
  400.    /* go through standard routines for undo comapatability */
  401.    Suspend_Screen_Update = 1;
  402.    if (first == last)
  403.      {
  404.     n = last_point - first_point;
  405.     if (save_buffer == MiniBuffer)
  406.       {
  407.          ins_chars(first->data + first_point, n);
  408.       }
  409.     else quick_insert(first->data + first_point, n);
  410.      }
  411.    else 
  412.      {
  413.     n = first->len - first_point;
  414.     quick_insert(first->data + first_point, n);
  415.     while (first = first->next, first != last)
  416.       {
  417.          quick_insert(first->data, first->len);
  418.       }
  419.     quick_insert(first->data, last_point);
  420.      }
  421.    switch_to_buffer(save_buffer);
  422.    pop_spot();
  423.    return(1);
  424. }
  425.  
  426. int copy_to_pastebuffer()
  427. {
  428.    /* delete paste buffer */
  429.    if (Paste_Buffer != NULL) delete_buffer(Paste_Buffer);
  430.    Paste_Buffer = make_buffer();
  431.    strcpy(Paste_Buffer->name, " <paste>");
  432.  
  433.    copy_region_to_buffer(Paste_Buffer);
  434.    return(0);
  435. }
  436.  
  437. int delete_region (void)
  438. {
  439.    int beg_point, tmpm, end_point, n;
  440.    Line *beg, *end;
  441.    
  442.    CHECK_READ_ONLY
  443.     if (!check_region(&Number_Zero)) return(0);
  444.  
  445.    /* make this go through standard ins/del routines to ensure undo */
  446.    
  447.    end = CLine; end_point = Point;
  448.    push_spot();
  449.    tmpm = 1; pop_mark(&tmpm);
  450.    beg = CLine; beg_point = Point;
  451.    pop_spot();
  452.    
  453.    Point = 0;
  454.    
  455.    if (end != beg) 
  456.      {
  457.     deln(&end_point);
  458.     
  459.     /* go back because we do not want to mess with Line structures
  460.        changing on us --- shouldn't happen anyway */
  461.     
  462.     while (CLine = CLine->prev, LineNum--, CLine != beg)
  463.       {
  464.          eol(); 
  465.          n = Point + 1;
  466.          Point = 0;
  467.          generic_deln(&n);
  468.       }
  469.     eol();
  470.     n = Point - beg_point + 1;  /* the \n char */
  471.     Point = beg_point;
  472.      }
  473.    else 
  474.      {
  475.     Point = beg_point;
  476.     n = end_point - Point;
  477.      }
  478.    
  479.    generic_deln(&n);
  480.    return(1);
  481. }
  482.  
  483. int kill_region()
  484. {
  485.    int tmpm = 1;
  486.    
  487.    CHECK_READ_ONLY
  488.  
  489.    /* need two marks for this one */
  490.    push_spot();
  491.    if (!pop_mark(&tmpm))
  492.      {
  493.     check_region(&Number_Zero);
  494.     pop_spot();
  495.     return(0);
  496.      }
  497.    push_mark();
  498.    push_mark();
  499.    pop_spot();
  500.  
  501.    copy_to_pastebuffer();
  502.    delete_region();
  503.    return(1);
  504. }
  505.  
  506. static char *Rect_Error = "Rectangle has 0 width.";
  507. int insert_rectangle()
  508. {
  509.    int c1;
  510.    Line *rline;
  511.  
  512.    CHECK_READ_ONLY
  513.    if (Rectangle_Buffer == NULL) return(0);
  514.  
  515.    Suspend_Screen_Update = 1;
  516.    c1 = calculate_column();
  517.    rline = Rectangle_Buffer->beg;
  518.    if (rline != NULL) while (1)
  519.      {
  520.     goto_column(&c1);
  521.     quick_insert(rline->data, rline->len);
  522.     rline = rline->next;
  523.     if (rline == NULL) break;
  524.     if (CLine->next == NULL)
  525.       {
  526.          eol();
  527.          newline();
  528.       }
  529.     else 
  530.       {
  531.          CLine = CLine->next;
  532.          LineNum++;
  533.       }
  534.      }
  535.    return(1);
  536. }
  537.  
  538. int open_rectangle()
  539. {
  540.    int c1, n, c2, tmpm;
  541.    Line *save_line;
  542.    
  543.    CHECK_READ_ONLY
  544.    if (!check_region(&Number_One)) return(0); /* push_spot(); performed */
  545.  
  546.    c1 = calculate_column();
  547.    save_line = CLine;
  548.    tmpm = 1; pop_mark(&tmpm);
  549.    c2 = calculate_column();
  550.    n = c2 - c1;
  551.    if (n < 0)
  552.      {
  553.     n = -n;
  554.     c1 = c2;
  555.      }
  556.    
  557.    Suspend_Screen_Update = 1;
  558.    while(1)
  559.      {
  560.     goto_column(&c1);
  561.     ins_char_n_times(' ', n);
  562.     if (CLine == save_line) break;
  563.     CLine = CLine->next;
  564.     LineNum++;
  565.      }
  566.    pop_spot();
  567.  
  568.    return(1);
  569. }
  570.  
  571. /* rectangle commands */
  572. int copy_rectangle()
  573. {
  574.     Line *save_line, *line, *beg;
  575.     int c1, c2, dc, tmp, tmpm, dc_malloc;
  576.     unsigned char *p1, *p2, *data;
  577.    
  578.     if (!check_region(&Number_One)) return(0);       /* spot pushed */
  579.     /* delete Rectangle buffer */
  580.     if (Rectangle_Buffer != NULL) delete_buffer(Rectangle_Buffer);
  581.  
  582.     Rectangle_Buffer = make_buffer();
  583.     strcpy(Rectangle_Buffer->name, " <rect>");
  584.     c2 = calculate_column();
  585.     save_line = CLine;
  586.  
  587.     tmpm = 1; pop_mark(&tmpm);
  588.     c1 = calculate_column();
  589.     if (c1 == c2)
  590.       {
  591.      msg_error(Rect_Error);
  592.      pop_spot();
  593.      return(0);
  594.       }
  595.     if (c1 > c2)
  596.       {
  597.      tmp = c1;
  598.      c1 = c2;
  599.      c2 = tmp;
  600.      goto_column(&c1);
  601.       }
  602.  
  603.     /* go through the region copying rectanglar blocks to Rectanglebuffer */
  604.     dc = c2 - c1;
  605.    if (dc == 1) dc_malloc = 2; else dc_malloc = dc;
  606.     line = beg = make_line1(dc_malloc);
  607.    
  608.     beg->prev = NULL;
  609.     while (1)
  610.       {
  611.      data = line->data;
  612.      /* p1 = data;
  613.      p2 = data + dc;
  614.      while (p1 < p2) *p1++ = ' '; */
  615.      MEMSET ((char *) data, ' ', dc);
  616.      
  617.      line->len = dc;
  618.  
  619.      if (c1 == goto_column1(&c1))
  620.        {
  621.           p1 = CLine->data + Point;
  622.           (void) goto_column1(&c2);
  623.           p2 = CLine->data + Point;
  624.  
  625.           /* while(p1 < p2) *data++ = *p1++; */
  626.           MEMCPY((char *) data, (char *) p1, (int) (p2 - p1));
  627.        }
  628.      if (CLine == save_line) break;
  629.      CLine = CLine->next;
  630.      LineNum++;
  631.  
  632.      line->next = make_line1(dc_malloc);
  633.      line->next->prev = line;
  634.      line = line->next;
  635.       }
  636.  
  637.     line->next = NULL;
  638.  
  639.     Rectangle_Buffer->line = Rectangle_Buffer->beg = beg;
  640.     Rectangle_Buffer->end = line;
  641.     Rectangle_Buffer->point = 0;
  642.  
  643.     pop_spot();
  644.     return(0);
  645. }
  646.  
  647. int kill_rectangle()
  648. {
  649.     Line *save_line, *line, *beg;
  650.    int c1, c2, dc, tmp, n, tmpm, dc_malloc;
  651.    unsigned char *p1, *p2, *data;
  652.  
  653.    CHECK_READ_ONLY
  654.    if (!check_region(&Number_One)) return(0);
  655.  
  656.    /* delete Rectangle buffer */
  657.    if (Rectangle_Buffer != NULL) delete_buffer(Rectangle_Buffer);
  658.  
  659.    Rectangle_Buffer = make_buffer();
  660.    strcpy(Rectangle_Buffer->name, " <rect>");
  661.    c2 = calculate_column();
  662.    save_line = CLine;
  663.  
  664.    tmpm = 1; pop_mark(&tmpm);
  665.     c1 = calculate_column();
  666.     if (c1 == c2)
  667.       {
  668.      msg_error(Rect_Error);
  669.      pop_spot();
  670.      return(0);
  671.       }
  672.     if (c1 > c2)
  673.       {
  674.      tmp = c1;
  675.      c1 = c2;
  676.      c2 = tmp;
  677.      goto_column(&c1);
  678.       }
  679.  
  680.    Suspend_Screen_Update = 1;
  681.     /* go through the region copying rectanglar blocks to Rectanglebuffer */
  682.     dc = c2 - c1;
  683.    if (dc == 1) dc_malloc = 2; else dc_malloc = dc;
  684.                   /* length of 1 not usable here.
  685.             * See makeline1 to see why 
  686.             */
  687.     line = beg = make_line1(dc_malloc);
  688.     beg->prev = NULL;
  689.     while (1)
  690.       {
  691.      data = line->data;
  692.      
  693.      /* p2 = data + dc; p1 = data;
  694.      while (p1 < p2) *p1++ = ' '; */
  695.      MEMSET((char *) data, ' ', dc);
  696.      line->len = dc;
  697.  
  698.      if (c1 == goto_column1(&c1))
  699.        {
  700.           p1 = CLine->data + Point;
  701.           (void) goto_column1(&c2);
  702.           p2 = CLine->data + Point;
  703.           Point = (int) (p1 - CLine->data);
  704.           n = (int) (p2 - p1);
  705.           MEMCPY((char *) data, (char *) p1, n);
  706.           deln (&n);
  707.           /* while(n-- > 0)
  708.             {
  709.            *data++ = *p1;
  710.            del();
  711.         } */
  712.        }
  713.      if (CLine == save_line) break;
  714.      CLine = CLine->next;  LineNum++;
  715.  
  716.      line->next = make_line1(dc_malloc);
  717.      line->next->prev = line;
  718.      line = line->next;
  719.       }
  720.  
  721.     line->next = NULL;
  722.  
  723.     Rectangle_Buffer->line = Rectangle_Buffer->beg = beg;
  724.     Rectangle_Buffer->end = line;
  725.     Rectangle_Buffer->point = 0;
  726.  
  727.     pop_spot();
  728.     return(0);
  729. }
  730.  
  731. int blank_rectangle()
  732. {
  733.    int c1, n, c2, pnt, tmpm;
  734.    Line *save_line;
  735.    int nn;
  736.    
  737.  
  738.    CHECK_READ_ONLY
  739.    if (!check_region(&Number_One)) return(0); /* push_spot(); performed */
  740.  
  741.    c1 = calculate_column();
  742.    save_line = CLine;
  743.    tmpm = 1; pop_mark(&tmpm);
  744.    c2 = calculate_column();
  745.    n = c2 - c1;
  746.    if (n < 0)
  747.      {
  748.     n = -n;
  749.     c1 = c2;
  750.      }
  751.    
  752.    Suspend_Screen_Update = 1;
  753.    while(1)
  754.      {
  755.     goto_column(&c1);
  756.     pnt = Point;
  757.     eol();
  758.     nn = Point - pnt;
  759.     if (nn > n) nn = n;
  760.     Point = pnt;
  761.     
  762.     deln(&nn);
  763.     ins_char_n_times( ' ', nn);
  764.     
  765.     if (CLine == save_line) break;
  766.     CLine = CLine->next;
  767.     LineNum++;
  768.      }
  769.    pop_spot();
  770.    /* mark_buffer_modified(&Number_One); */
  771.    return(1);
  772. }
  773.  
  774. /*  User Marks */
  775.  
  776. typedef struct 
  777. {
  778.    Mark m;                   /* MUST be the first */
  779.    Buffer *b;
  780. }
  781. User_Mark_Type;
  782.  
  783. static void free_user_mark (User_Mark_Type *um)
  784. {
  785.    Mark *m, *m1;
  786.    Buffer *b;
  787.  
  788.    m1 = &um->m;
  789.  
  790.    /* The mark is only valid if the buffer that it was created for still
  791.     * exists.
  792.     */
  793.    if ((m1->flags & MARK_INVALID) == 0)
  794.      {
  795.     /* Unlink the mark from the chain. */
  796.     b = um->b;
  797.     m = b->user_marks;
  798.    
  799.     if (m == m1)    b->user_marks = m1->next;
  800.     else 
  801.       {
  802.          while (m->next != m1) m = m->next;
  803.          m->next = m1->next;
  804.       }
  805.      }
  806.    
  807.    SLFREE (um);
  808. }
  809.  
  810. void free_user_marks (Buffer *b)
  811. {
  812.    Mark *m = b->user_marks;
  813.    
  814.    while (m != NULL)
  815.      {
  816.     m->flags |= MARK_INVALID;
  817.     m = m->next;
  818.      }
  819. }
  820.  
  821. static int mark_valid (Mark *m)
  822. {
  823.    if (m->flags & MARK_INVALID)
  824.      {
  825.     msg_error ("Mark is invalid.");
  826.     return 0;
  827.      }
  828.    return 1;
  829. }
  830.  
  831.  
  832. void goto_user_mark (void)
  833. {
  834.    SLuser_Object_Type *uo;
  835.    User_Mark_Type *um;
  836.    
  837.    if ((uo = SLang_pop_user_object (JED_MARK_TYPE)) == NULL) return;
  838.    um = (User_Mark_Type *) uo->obj;
  839.    
  840.    if (mark_valid (&um->m))
  841.      {
  842.     if (CBuf != um->b) msg_error ("Mark not in buffer.");
  843.     else
  844.       goto_mark (&um->m);
  845.      }
  846.    SLang_free_user_object (uo);
  847. }
  848.  
  849. void create_user_mark (void)
  850. {
  851.    User_Mark_Type *um;
  852.    SLuser_Object_Type *uo;
  853.    Mark *m;
  854.    
  855.    uo = SLang_create_user_object (JED_MARK_TYPE);
  856.    if (uo == NULL) return;
  857.    
  858.  
  859.    if (NULL == (um = (User_Mark_Type *) SLMALLOC (sizeof(User_Mark_Type))))
  860.      {
  861.     SLang_Error = SL_MALLOC_ERROR;
  862.     SLFREE (uo);
  863.     return;
  864.      }
  865.    m = &um->m;
  866.    
  867.    m->line = CLine;
  868.    m->point = Point;
  869.    m->n = LineNum + CBuf->nup;
  870.    m->next = CBuf->user_marks;
  871.    m->flags = 0;
  872.    
  873.    CBuf->user_marks = m;
  874.    
  875.    um->b = CBuf;   
  876.    uo->obj = (long *) um;
  877.    SLang_push_user_object (uo);
  878. }
  879.  
  880.    
  881.    
  882. char *user_mark_buffer (void)
  883. {
  884.    SLuser_Object_Type *uo;
  885.    User_Mark_Type *um;
  886.    char *s = "";
  887.    
  888.    if (NULL == (uo = SLang_pop_user_object (JED_MARK_TYPE))) return s;
  889.    um = (User_Mark_Type *) uo->obj;
  890.    
  891.    if (mark_valid (&um->m))
  892.      {
  893.     s = um->b->name;
  894.      }
  895.    
  896.    SLang_free_user_object (uo);
  897.    return s;
  898. }
  899.  
  900.    
  901. int register_jed_classes (void)
  902. {
  903.    return SLang_register_class (JED_MARK_TYPE, (VOID *) free_user_mark, NULL);
  904. }
  905.