Logo Search packages:      
Sourcecode: jed version File versions

paste.c

/* -*- mode: C; mode: fold; -*- */
/* Copyright (c) 1992, 1998, 2000, 2002 John E. Davis
 * This file is part of JED editor library source.
 *
 * You may distribute this file under the terms the GNU General Public
 * License.  See the file COPYING for more information.
 */
    
#include "config.h"
#include "jed-feat.h"
/*{{{ Include Files */

#include <stdio.h>
#include <string.h>

#include "buffer.h"
#include "ins.h"
#include "line.h"
#include "paste.h"
#include "screen.h"
#include "misc.h"
#include "cmds.h"

/*}}}*/

/* SLang user object be larger than 128 */
#define JED_MARK_TYPE 128

Buffer *Paste_Buffer;
static Buffer *Rectangle_Buffer;

/* This is used by the narrow command so that multiple windows are 
 * handled properly. The assumption is that we are dealing with a canonical
 * region */
      
static void touch_windows(void) /*{{{*/
{
   Window_Type *w;
   Line *l;
   unsigned int n;
   
   w = JWindow;
   JWindow = JWindow->next;
   while (JWindow != w)
     {
      if (CBuf == JWindow->buffer)
        {
           /* The mark is set with line at top of buffer */
           l = CBuf->marks->line;
           n = CBuf->marks->n;
           while ((l != NULL) && (l != JWindow->mark.line)) l = l->next, n++;
           if (l == NULL) 
             {
#if 0
              JWindow->mark.line = CLine;
              JWindow->mark.point = Point;
              JWindow->mark.n = n - 1;
#else
              jed_init_mark (&JWindow->mark, 0);
#endif
             }
           touch_window();
        }
      JWindow = JWindow->next;
     }
   pop_mark(&Number_Zero);
}

/*}}}*/

#if 0
static int line_in_buffer(Line *line) /*{{{*/
{
   Line *l;
   
   l = CBuf->beg;
   while (l != NULL) if (l == line) return(1); else l = l->next;
   return(0);
}

/*}}}*/
#endif

/*{{{ Spot/Mark Functions */

void jed_copy_mark (Mark *dest, Mark *src)
{
   *dest = *src;
   dest->next = NULL;
}

void jed_init_mark (Mark *m, unsigned int flags) /*{{{*/
{
   m->line = CLine;
   m->point = Point;
   m->n = LineNum + CBuf->nup;
   m->flags = flags;
   /* m->next = NULL; */
}

/*}}}*/

void jed_init_mark_for_buffer (Mark *m, Buffer *b, unsigned int flags) /*{{{*/
{
   m->line = b->line;
   m->point = b->point;
   m->n = b->linenum + b->nup;
   m->flags = flags;
   /* m->next = NULL; */
}

/*}}}*/
#if 0
int jed_init_mark_for_line (Mark *m, Line *l, unsigned int flags) /*{{{*/
{
   Line *ll;
   unsigned int n;
   
   n = 1;
   ll = CBuf->beg;
   while ((ll != NULL) && (ll != l))
     {
      ll = ll->next;
      n++;
     }
   if (ll == NULL)
     return -1;
   
   m->line = l;
   m->point = 0;
   m->n = n + CBuf->nup;
   m->flags = flags;
   /* m->next = NULL; */
   return 0;
}

/*}}}*/
#endif
#if JED_HAS_SAVE_NARROW
static Mark *create_mark (unsigned int flags) /*{{{*/
{
   Mark *m;
   
   if (NULL == (m = (Mark *) jed_malloc0 (sizeof(Mark))))
     exit_error("create-mark: malloc error", 0);
   
   jed_init_mark (m, flags);
   
   return m;
}

/*}}}*/
#endif   
/* with prefix argument, pop marks */
int set_mark_cmd (void) /*{{{*/
{
   Mark *m;
   if (Repeat_Factor != NULL)
     {
      while (CBuf->marks != NULL) pop_mark(&Number_Zero);
      Repeat_Factor = NULL;
      return(1);
     }
   
   if (CBuf->marks == NULL)
     {
      push_mark ();
     }

   m = CBuf->marks;
   
   jed_init_mark (m, m->flags);
   
   if ((m->flags & VISIBLE_MARK) == 0) 
     {
      m->flags |= VISIBLE_MARK;
      CBuf->vis_marks++;
     }
   
   /* if (m != CBuf->marks) m->next = CBuf->marks;
    CBuf->marks = m; */
   if (Last_Key_Function == (FVOID_STAR) set_mark_cmd) message("Mark Set.");
   return(1);
}

/*}}}*/

static Mark *allocate_mark (Jed_Mark_Array_Type **ap, Mark **mp, unsigned int flags) /*{{{*/
{
   Jed_Mark_Array_Type *a, *b;
   Mark *m;
   
   a = *ap;
   if ((a == NULL)
       || (a->num_marks == JED_MAX_MARK_ARRAY_SIZE))
     {
      if (NULL == (b = (Jed_Mark_Array_Type *) jed_malloc0 (sizeof(Jed_Mark_Array_Type))))
        {
           exit_error("allocate_mark: malloc error", 0);
        }
      b->next = a;
      a = b;
      *ap = a;
     }
   
   m = &a->marks[a->num_marks];
   jed_init_mark (m, flags);

   a->num_marks += 1;
   m->next = *mp;
   *mp = m;
   return m;
}

/*}}}*/

static void deallocate_mark (Jed_Mark_Array_Type **ap, Mark **mp) /*{{{*/
{
   Jed_Mark_Array_Type *a;
   Mark *m;
   
   m = *mp;
   *mp = m->next;
   
   a = *ap;
   a->num_marks -= 1;
   
   if (a->num_marks == 0)
     {
      *ap = a->next;
      SLfree ((char *)a);
     }
}

/*}}}*/

int push_spot() /*{{{*/
{
   (void) allocate_mark (&CBuf->spot_array, &CBuf->spots, 0);
   return 1;
}

/*}}}*/

int push_mark() /*{{{*/
{
   (void) allocate_mark (&CBuf->mark_array, &CBuf->marks, 0);
   return 1;
}

/*}}}*/

int jed_goto_mark(Mark *m) /*{{{*/
{
   Line *l;
   int ret = -1;
   
   l = m->line;
   LineNum = m->n;
      
   if (LineNum <= CBuf->nup) bob();
   else if (LineNum > CBuf->nup + Max_LineNum) eob();
   else
     {
      CLine = l;
      Point = m->point;
      LineNum -= CBuf->nup;
      ret = 0;
     }
   return ret;
}

/*}}}*/

int pop_mark (int *go) /*{{{*/
{
   Mark *m;
   
   m = CBuf->marks;
   if (m == NULL) return(0);

   if (*go) jed_goto_mark(m);
   if (m->flags & VISIBLE_MARK_MASK)
     {
      CBuf->vis_marks--;
      /* touch screen since region may be highlighted */
      if (CBuf->vis_marks == 0) touch_screen();
     }

   deallocate_mark (&CBuf->mark_array, &CBuf->marks);
   
   return 1;
}

/*}}}*/

int mark_spot() /*{{{*/
{
    push_spot();
    message("Spot Marked.");
    return(1);
}

/*}}}*/

static int pop_spot_go (int go) /*{{{*/
{
   Mark *m;
   
   m = CBuf->spots;
   if (m == NULL) return(0);
   
   if (go) jed_goto_mark (m);

   deallocate_mark (&CBuf->spot_array, &CBuf->spots);
   return 1;
}

/*}}}*/

int pop_spot () /*{{{*/
{
   return pop_spot_go (1);
}

/*}}}*/

int exchange_point_mark(void) /*{{{*/
{
   Line *save_line;
   int save_point;
   unsigned int save_n;
   Mark *m;
   
   if ((m = CBuf->marks) == NULL) return(0);
   
   save_point = Point;
   save_line = CLine;
   save_n = LineNum + CBuf->nup;
   
   jed_goto_mark (m);
   
   m->point = save_point; m->line = save_line; m->n = save_n;
   return(1);
}

/*}}}*/

/*}}}*/

/*{{{ Narrow/Widen/Region Functions */

 /*returns 0 if the mark is not set and gives error.  Exchanges point and mark
  * to produce valid region.  A valid region is one with mark
  * earlier in the buffer than point.  Always call this if using a region
  * which reqires point > mark.  Also, push spot first then pop at end. 
  */
int check_region(int *push) /*{{{*/
{
   register Line *beg, *tthis = CLine;
   int pbeg;

   if (CBuf->marks == NULL)
     {
      msg_error("No region defined");
      return(0);
     }

   if (*push) push_spot();
   beg = CBuf->marks->line;
   pbeg = CBuf->marks->point;

   if (beg == CLine)
     {
      if (pbeg <= Point) return(1);
     }

   else
     {
      while((beg != NULL) && (beg != tthis)) beg = beg->next;
      if (beg == tthis) return(1);
     }

   exchange_point_mark();
   return(1);
}

/*}}}*/

static int widen_buffer_lines (Buffer *b) /*{{{*/
{
   Narrow_Type *n;
   Buffer *save = CBuf;
   
   if (NULL == (n = b->narrow)) return(0);
   
   /* make sure buffer ends in final newline */
   
   switch_to_buffer(b);
   push_spot();
   eob();
   if ((n->end != NULL)
       && (!CLine->len || ('\n' != *(CLine->data + (CLine->len - 1)))))
     {
      /* This is a hack to avoid messing with the lock file. Yuk. */
      unsigned int flags = CBuf->flags;
      CBuf->flags &= ~(READ_ONLY);
      CBuf->flags |= BUFFER_NON_LOCKING;
      (void) jed_ins('\n');
      CBuf->flags = flags;  /* jed_set_buffer_flags (CBuf, flags); */
     }

   pop_spot();
   
   if (n->end != NULL) n->end->prev = b->end;
   if (n->beg != NULL) n->beg->next = b->beg;
   b->end->next = n->end;
   b->beg->prev = n->beg;
   b->beg = n->beg1;
   if (n->end != NULL) b->end = n->end1;
   
   Max_LineNum += n->ndown + n->nup;
   LineNum += n->nup;
   
   /* adjust absolute offsets */
   b->nup -= n->nup;
   b->ndown -= n->ndown;
   b->narrow = n->next;

   /* mark_undo_boundary (b); */

   SLfree ((char *)n);
   switch_to_buffer(save);
   return(1);
}

/*}}}*/

int widen_buffer (Buffer *b) /*{{{*/
{
   unsigned int flags;
#if JED_HAS_LINE_ATTRIBUTES
   unsigned int line_flags;
#endif
   Buffer *save;
   
   if (b->narrow == NULL) return 0;

   if (b->narrow->is_region == 0)
     return widen_buffer_lines (b);
   
   flags = b->flags;
   b->flags &= ~(READ_ONLY);

   /* A hack to avoid locking file */
   b->flags |= BUFFER_NON_LOCKING;

   save = CBuf;
   if (b != CBuf) switch_to_buffer (b);
   push_spot ();
   bob ();
   push_spot ();
   eob ();
   widen_buffer_lines (CBuf);
   
#if JED_HAS_LINE_ATTRIBUTES
   line_flags = CLine->flags;
   CLine->flags &= ~JED_LINE_IS_READONLY;
#endif
   (void) jed_del ();
#if JED_HAS_LINE_ATTRIBUTES
   CLine->flags = line_flags;
#endif
   
   pop_spot ();
   prevline (&Number_One);
#if JED_HAS_LINE_ATTRIBUTES
   line_flags = CLine->flags;
   CLine->flags &= ~JED_LINE_IS_READONLY;
#endif
   (void) jed_del ();
#if JED_HAS_LINE_ATTRIBUTES
   CLine->flags = line_flags;
#endif
   /* mark_undo_boundary (b); */

   pop_spot ();
   if (save != CBuf) switch_to_buffer (save);
   
   b->flags = flags;
   return 1;
}

/*}}}*/

int narrow_to_region (void) /*{{{*/
{
   int pnt;
   Line *line;
   unsigned int flags;
#if JED_HAS_LINE_ATTRIBUTES
   unsigned int line_flags;
#endif
     
   if (0 == check_region (&Number_One))/* spot pushed */
     return 0;

   /* unmark_undo_boundary (CBuf); */

   flags = CBuf->flags;
   CBuf->flags &= ~(READ_ONLY);
   /* A hack to avoid locking file */
   CBuf->flags |= BUFFER_NON_LOCKING;
   
   push_spot ();
   
   line = CLine;
   pnt = Point;
   
   pop_mark (&Number_One);
   /* Special case if region is empty */
   if ((CLine == line) && (pnt == Point))
     {
      pop_spot ();
      pop_spot ();

#if JED_HAS_LINE_ATTRIBUTES
      line_flags = CLine->flags;
      CLine->flags &= ~JED_LINE_IS_READONLY;
#endif
      
      (void) jed_insert_newline ();
      
#if JED_HAS_LINE_ATTRIBUTES
      if (CLine->prev != NULL) CLine->prev->flags = line_flags;
#endif
      
      push_mark ();

      (void) jed_insert_newline ();
      
#if JED_HAS_LINE_ATTRIBUTES
      CLine->flags = line_flags;
#endif
      prevline (&Number_One);

#if JED_HAS_LINE_ATTRIBUTES
      CLine->flags = line_flags;
#endif

      if (narrow_to_lines ())
        CBuf->narrow->is_region = 1;
     }
   else
     {
#if JED_HAS_LINE_ATTRIBUTES
      line_flags = CLine->flags;
      CLine->flags &= ~JED_LINE_IS_READONLY;
#endif
      jed_insert_newline ();
#if JED_HAS_LINE_ATTRIBUTES
      CLine->flags = line_flags;
      if (CLine->prev != NULL) CLine->prev->flags = line_flags;
#endif

      push_mark ();
      pop_spot ();
      
#if JED_HAS_LINE_ATTRIBUTES
      line_flags = CLine->flags;
      CLine->flags &= ~JED_LINE_IS_READONLY;
#endif
      jed_insert_newline ();
#if JED_HAS_LINE_ATTRIBUTES
      CLine->flags = line_flags;
#endif
      prevline (&Number_One);

#if JED_HAS_LINE_ATTRIBUTES
      CLine->flags = line_flags;
#endif
      if (narrow_to_lines ())
        CBuf->narrow->is_region = 1;
      
      pop_spot ();
     }
   
   /* mark_undo_boundary (CBuf); */
   CBuf->flags = flags;
   return 1;
}

/*}}}*/

int widen (void) /*{{{*/
{
   /* unmark_undo_boundary (CBuf); */
   return widen_buffer_lines (CBuf);
}

/*}}}*/

int widen_region (void) /*{{{*/
{
   /* unmark_undo_boundary (CBuf); */
   return widen_buffer (CBuf);
}

/*}}}*/

/* not really a region of points but a region of lines. */
int narrow_to_lines () /*{{{*/
{
   Line *beg;
   Narrow_Type *nt;
   
   if (NULL == (nt = (Narrow_Type *) jed_malloc0 (sizeof(Narrow_Type))))
     return 0;
   
   if (!check_region(&Number_One)) return(0);       /* spot pushed */

   /* unmark_undo_boundary (CBuf); */

   push_spot();
   pop_mark(&Number_One);
   push_mark();                      /* popped and used in touch_windows! */
   beg = CLine;
   nt->nup = LineNum - 1;
   
   pop_spot();  /* eor now */
   
   nt->ndown = Max_LineNum - LineNum;

   Max_LineNum = LineNum = LineNum - nt->nup;
   CBuf->nup += nt->nup;
   CBuf->ndown += nt->ndown;
   
   
   nt->next = CBuf->narrow;
   CBuf->narrow = nt;
   nt->beg = beg->prev;
   nt->end = CLine->next;
   nt->beg1 = CBuf->beg;
   nt->end1 = CBuf->end;
   
   nt->is_region = 0;
   CBuf->beg = beg;
   CBuf->end = CLine;
   beg->prev = NULL;
   CLine->next = NULL;
   
   if (CLine->len && (CLine->data[CLine->len - 1] == '\n'))
     {
      /* I do not think that this will affect undo. */
      CLine->len--;
     }
   
   pop_spot();
   touch_windows();
   return(1);
}

/*}}}*/

/*}}}*/

/*{{{ Pastebuffer, Delete Region functions */

int yank() /*{{{*/
{
   CHECK_READ_ONLY
    if (Paste_Buffer == NULL) return(0);
    insert_buffer(Paste_Buffer);
    return(1);
}

/*}}}*/

int copy_region_to_buffer(Buffer *b) /*{{{*/
{
   int first_point, last_point, n, tmpm;
   Line *first, *last;
   Buffer *save_buf;

   if (b->flags & READ_ONLY) 
     {
      msg_error(Read_Only_Error);
      return (0);
     }
   
   if (!check_region(&Number_One)) return(0);  /* spot pushed */
   last = CLine;
   last_point = Point;

   tmpm = 1; pop_mark(&tmpm);
   if (b == CBuf)
     {
      msg_error("A buffer cannot be inserted upon itself.");
      pop_spot();
      return(0);
     }

   first = CLine;
   first_point = Point;

   save_buf = CBuf;
   switch_to_buffer(b);

   /* go through standard routines for undo comapatability */
   Suspend_Screen_Update = 1;
   if (first == last)
     {
      n = last_point - first_point;
      if (save_buf == MiniBuffer)
        {
           (void) jed_ins_chars(first->data + first_point, n);
        }
      else (void) jed_quick_insert(first->data + first_point, n);
     }
   else 
     {
      n = first->len - first_point;
      if (-1 == jed_quick_insert(first->data + first_point, n))
        goto the_return;

      while (first = first->next, first != last)
        {
           if (-1 == jed_quick_insert(first->data, first->len))
             goto the_return;
        }
      (void) jed_quick_insert(first->data, last_point);
     }

   the_return:
   switch_to_buffer(save_buf);
   pop_spot();
   return(1);
}

/*}}}*/

int copy_to_pastebuffer() /*{{{*/
{
   /* delete paste buffer */
   if (Paste_Buffer != NULL) delete_buffer(Paste_Buffer);
   Paste_Buffer = make_buffer (" <paste>", NULL, NULL);

   copy_region_to_buffer(Paste_Buffer);
   return(0);
}

/*}}}*/

int delete_region (void) /*{{{*/
{
   int beg_point, tmpm, end_point, n;
   Line *beg, *end;
   
   CHECK_READ_ONLY
    if (!check_region(&Number_Zero)) return(0);

   /* make this go through standard ins/del routines to ensure undo */
   
   end = CLine; end_point = Point;
   push_spot();
   tmpm = 1; pop_mark(&tmpm);
   beg = CLine; beg_point = Point;
   pop_spot();
   
   Point = 0;
   
   if (end != beg) 
     {
      if (-1 == jed_deln (end_point))
        return -1;

      /* go back because we do not want to mess with Line structures
         changing on us --- shouldn't happen anyway */
      
      while (CLine = CLine->prev, LineNum--, CLine != beg)
        {
           eol(); 
           n = Point + 1;
           Point = 0;
           if (-1 == jed_generic_deln (n))
             return -1;
        }
      eol();
      n = Point - beg_point + 1;  /* the \n char */
      Point = beg_point;
     }
   else 
     {
      Point = beg_point;
      n = end_point - Point;
     }
   
   (void) jed_generic_deln (n);
   return(1);
}

/*}}}*/

int kill_region() /*{{{*/
{
   int tmpm = 1;
   
   CHECK_READ_ONLY

   /* need two marks for this one */
   push_spot();
   if (!pop_mark(&tmpm))
     {
      check_region(&Number_Zero);
      pop_spot();
      return(0);
     }
   push_mark();
   push_mark();
   pop_spot();

   copy_to_pastebuffer();
   delete_region();
   return(1);
}

/*}}}*/

/*}}}*/

/*{{{ Rectangle Functions */

static char *Rect_Error = "Rectangle has 0 width.";
int insert_rectangle() /*{{{*/
{
   int c1;
   Line *rline;

   CHECK_READ_ONLY
   if (Rectangle_Buffer == NULL) return(0);

   Suspend_Screen_Update = 1;
   c1 = calculate_column();
   rline = Rectangle_Buffer->beg;
   if (rline != NULL) while (1)
     {
      goto_column(&c1);
      if (-1 == jed_quick_insert (rline->data, rline->len))
        return -1;

      rline = rline->next;
      if (rline == NULL) break;
      if (CLine->next == NULL)
        {
           eol();
           jed_insert_newline();
        }
      else 
        {
           CLine = CLine->next;
           LineNum++;
        }
     }
   return(1);
}

/*}}}*/

int open_rectangle() /*{{{*/
{
   int c1, n, c2, tmpm;
   Line *save_line;
   
   CHECK_READ_ONLY
   if (!check_region(&Number_One)) return(0); /* push_spot(); performed */

   c1 = calculate_column();
   save_line = CLine;
   tmpm = 1; pop_mark(&tmpm);
   c2 = calculate_column();
   n = c2 - c1;
   if (n < 0)
     {
      n = -n;
      c1 = c2;
     }
   
   Suspend_Screen_Update = 1;
   while(1)
     {
      goto_column(&c1);
      if (-1 == jed_ins_char_n_times(' ', n))
        break;
      if (CLine == save_line) break;
      CLine = CLine->next;
      LineNum++;
     }
   pop_spot();

   return(1);
}

/*}}}*/

/* rectangle commands */
int copy_rectangle() /*{{{*/
{
    Line *save_line, *line, *beg;
    int c1, c2, dc, tmp, tmpm, dc_malloc;
    unsigned char *p1, *p2, *data;
   
    if (!check_region(&Number_One)) return(0);       /* spot pushed */
    /* delete Rectangle buffer */
    if (Rectangle_Buffer != NULL) delete_buffer(Rectangle_Buffer);

    Rectangle_Buffer = make_buffer (" <rect>", NULL, NULL);
    c2 = calculate_column();
    save_line = CLine;

    tmpm = 1; pop_mark(&tmpm);
    c1 = calculate_column();
    if (c1 == c2)
      {
       msg_error(Rect_Error);
       pop_spot();
       return(0);
      }
    if (c1 > c2)
      {
       tmp = c1;
       c1 = c2;
       c2 = tmp;
       goto_column(&c1);
      }

    /* go through the region copying rectanglar blocks to Rectanglebuffer */
    dc = c2 - c1;
   if (dc == 1) dc_malloc = 2; else dc_malloc = dc;
    line = beg = make_line1(dc_malloc);
   
    beg->prev = NULL;
    while (1)
      {
       data = line->data;
       /* p1 = data;
       p2 = data + dc;
       while (p1 < p2) *p1++ = ' '; */
       SLMEMSET ((char *) data, ' ', dc);
       
       line->len = dc;

       if (c1 == goto_column1(&c1))
         {
            p1 = CLine->data + Point;
            (void) goto_column1(&c2);
            p2 = CLine->data + Point;

            /* while(p1 < p2) *data++ = *p1++; */
            SLMEMCPY((char *) data, (char *) p1, (int) (p2 - p1));
         }
       if (CLine == save_line) break;
       CLine = CLine->next;
       LineNum++;

       line->next = make_line1(dc_malloc);
       line->next->prev = line;
       line = line->next;
      }

    line->next = NULL;

    Rectangle_Buffer->line = Rectangle_Buffer->beg = beg;
    Rectangle_Buffer->end = line;
    Rectangle_Buffer->point = 0;

    pop_spot();
    return(0);
}

/*}}}*/

int kill_rectangle() /*{{{*/
{
    Line *save_line, *line, *beg;
   int c1, c2, dc, tmp, n, tmpm, dc_malloc;
   unsigned char *p1, *p2, *data;

   CHECK_READ_ONLY
   if (!check_region(&Number_One)) return(0);

   /* delete Rectangle buffer */
   if (Rectangle_Buffer != NULL) delete_buffer(Rectangle_Buffer);

   Rectangle_Buffer = make_buffer (" <rect>", NULL, NULL);
   c2 = calculate_column();
   save_line = CLine;

   tmpm = 1; pop_mark(&tmpm);
    c1 = calculate_column();
    if (c1 == c2)
      {
       msg_error(Rect_Error);
       pop_spot();
       return(0);
      }
    if (c1 > c2)
      {
       tmp = c1;
       c1 = c2;
       c2 = tmp;
       goto_column(&c1);
      }

   Suspend_Screen_Update = 1;
    /* go through the region copying rectanglar blocks to Rectanglebuffer */
    dc = c2 - c1;
   if (dc == 1) dc_malloc = 2; else dc_malloc = dc;
                   /* length of 1 not usable here.
                  * See makeline1 to see why 
                  */
    line = beg = make_line1(dc_malloc);
    beg->prev = NULL;
    while (1)
      {
       data = line->data;
       
       /* p2 = data + dc; p1 = data;
       while (p1 < p2) *p1++ = ' '; */
       SLMEMSET((char *) data, ' ', dc);
       line->len = dc;

       if (c1 == goto_column1(&c1))
         {
            p1 = CLine->data + Point;
            (void) goto_column1(&c2);
            p2 = CLine->data + Point;
            Point = (int) (p1 - CLine->data);
            n = (int) (p2 - p1);
            SLMEMCPY((char *) data, (char *) p1, n);

            if (-1 == jed_deln (n))
            break;
         }
       if (CLine == save_line) break;
       CLine = CLine->next;  LineNum++;

       line->next = make_line1(dc_malloc);
       line->next->prev = line;
       line = line->next;
      }

    line->next = NULL;

    Rectangle_Buffer->line = Rectangle_Buffer->beg = beg;
    Rectangle_Buffer->end = line;
    Rectangle_Buffer->point = 0;

    pop_spot();
    return(0);
}

/*}}}*/

int blank_rectangle() /*{{{*/
{
   int c1, n, c2, pnt, tmpm;
   Line *save_line;
   int nn;
   

   CHECK_READ_ONLY
   if (!check_region(&Number_One)) return(0); /* push_spot(); performed */

   c1 = calculate_column();
   save_line = CLine;
   tmpm = 1; pop_mark(&tmpm);
   c2 = calculate_column();
   n = c2 - c1;
   if (n < 0)
     {
      n = -n;
      c1 = c2;
     }
   
   Suspend_Screen_Update = 1;
   while(1)
     {
      goto_column(&c1);
      pnt = Point;
      eol();
      nn = Point - pnt;
      if (nn > n) nn = n;
      Point = pnt;
      
      if (-1 == jed_deln (nn))
        break;

      if (-1 == jed_ins_char_n_times( ' ', nn))
        break;
      
      if (CLine == save_line) break;
      CLine = CLine->next;
      LineNum++;
     }
   pop_spot();
   /* mark_buffer_modified(&Number_One); */
   return(1);
}

/*}}}*/

/*}}}*/

/*{{{ User Mark Functions */

typedef struct /*{{{*/
{
   Mark m;                     /* MUST be the first */
   Buffer *b;
}

/*}}}*/
User_Mark_Type;

static void free_user_mark (unsigned char type, VOID_STAR um_alias) /*{{{*/
{
   Mark *m, *m1;
   Buffer *b;
   User_Mark_Type *um;
   
   (void) type;
   um = (User_Mark_Type *) um_alias;
   m1 = &um->m;

   /* The mark is only valid if the buffer that it was created for still
    * exists.
    */
   if ((m1->flags & MARK_INVALID) == 0)
     {
      /* Unlink the mark from the chain. */
      b = um->b;
      m = b->user_marks;
#if JED_HAS_LINE_MARKS
      if (m1->flags & JED_LINE_MARK) 
        touch_screen ();
#endif
      if (m == m1)      b->user_marks = m1->next;
      else 
        {
           while (m->next != m1) m = m->next;
           m->next = m1->next;
        }
     }
   
   SLfree ((char *)um);
}

/*}}}*/

void free_user_marks (Buffer *b) /*{{{*/
{
   Mark *m = b->user_marks;
   
   while (m != NULL)
     {
      m->flags |= MARK_INVALID;
      m = m->next;
     }
}

/*}}}*/

static int mark_valid (Mark *m) /*{{{*/
{
   if (m->flags & MARK_INVALID)
     {
      msg_error ("Mark is invalid.");
      return 0;
     }
   return 1;
}

/*}}}*/

static SLang_MMT_Type *pop_valid_user_mark (User_Mark_Type **ump)
{   
   SLang_MMT_Type *mmt;
   User_Mark_Type *um;

   *ump = NULL;

   if (NULL == (mmt = SLang_pop_mmt (JED_MARK_TYPE)))
     return NULL;

   um = (User_Mark_Type *) SLang_object_from_mmt (mmt);
   
   if (0 == mark_valid (&um->m))
     {
      SLang_free_mmt (mmt);
      return NULL;
     }
   
   *ump = um;
   return mmt;
}

   
   
int jed_move_user_object_mark (SLang_MMT_Type *mmt) /*{{{*/
{
   User_Mark_Type *um;
   Mark *m;
   
   um = (User_Mark_Type *) SLang_object_from_mmt (mmt);
   m = &um->m;
   
   if (!mark_valid (m)) return 0;
   
   if (CBuf != um->b)
     {      
      msg_error ("Mark not in buffer.");
      return 0;
     }
   
   
   m->line = CLine;
   m->point = Point;
   m->n = LineNum + CBuf->nup;
   return 1;
}

/*}}}*/

void move_user_mark (void) /*{{{*/
{
   SLang_MMT_Type *mmt;
   
   if (NULL == (mmt = SLang_pop_mmt (JED_MARK_TYPE)))
     return;

   (void) jed_move_user_object_mark (mmt);
   SLang_free_mmt (mmt);
}

/*}}}*/

static int x_user_mark_fun (int (*xfun)(Mark *)) /*{{{*/
{
   SLang_MMT_Type *mmt;
   User_Mark_Type *um;
   int ret = -1;

   if (NULL == (mmt = pop_valid_user_mark (&um)))
     return -1;

   if (CBuf != um->b) msg_error ("Mark not in buffer.");
   else
     ret = (*xfun) (&um->m);

   SLang_free_mmt (mmt);
   return ret;
}

/*}}}*/

/* It is up to calling routine to ensure that mark is in buffer. */
static int is_mark_in_narrow (Mark *m)
{
   return ((m->n > CBuf->nup)
         && (m->n <= CBuf->nup + Max_LineNum));
}

int jed_is_user_mark_in_narrow (void)
{
   return x_user_mark_fun (is_mark_in_narrow);
}

void goto_user_mark (void)
{
   (void) x_user_mark_fun (jed_goto_mark);
}

SLang_MMT_Type *jed_make_user_object_mark (void) /*{{{*/
{
   User_Mark_Type *um;
   SLang_MMT_Type *mmt;
   Mark *m;
   
   if (NULL == (um = (User_Mark_Type *) jed_malloc0 (sizeof(User_Mark_Type))))
     return NULL;
     
   if (NULL == (mmt = SLang_create_mmt (JED_MARK_TYPE, (VOID_STAR) um)))
     {
      SLfree ((char *) um);
      return NULL;
     }

   m = &um->m;
   
   jed_init_mark (m, 0);
   
   m->next = CBuf->user_marks;
   
   CBuf->user_marks = m;
   
   um->b = CBuf;

   return mmt;
}

/*}}}*/


void create_user_mark (void) /*{{{*/
{
   SLang_MMT_Type *mmt;
   
   if (NULL != (mmt = jed_make_user_object_mark ()))
     {
      if (-1 == SLang_push_mmt (mmt))
        SLang_free_mmt (mmt);
     }
}

/*}}}*/

char *user_mark_buffer (void) /*{{{*/
{
   SLang_MMT_Type *mmt;
   User_Mark_Type *um;
   char *s;

   if (NULL == (mmt = pop_valid_user_mark (&um)))
     return "";

   s = um->b->name;

   SLang_free_mmt (mmt);
   return s;
}

/*}}}*/

static int
user_mark_bin_op_result (int op, unsigned char a, unsigned char b,
                   unsigned char *c)
{
   (void) a; (void) b;
   switch (op)
     {
      default: 
      return 0;
      
      case SLANG_GT:
      case SLANG_GE:
      case SLANG_LT:
      case SLANG_LE:
      case SLANG_EQ:
      case SLANG_NE:
      *c = SLANG_INT_TYPE;
      break;
     }
   return 1;
}


static int
user_mark_bin_op (int op,
              unsigned char a_type, VOID_STAR ap, unsigned int na,
              unsigned char b_type, VOID_STAR bp, unsigned int nb,
              VOID_STAR cp)
{
   int *ic;
   unsigned int n, n_max;
   unsigned int da, db;
   SLang_MMT_Type **a, **b;

   (void) a_type;
   (void) b_type;

   if (na == 1) da = 0; else da = 1;
   if (nb == 1) db = 0; else db = 1;

   if (na > nb) n_max = na; else n_max = nb;

   a = (SLang_MMT_Type **) ap;
   b = (SLang_MMT_Type **) bp;

   ic = (int *) cp;

   for (n = 0; n < n_max; n++)
     {
      User_Mark_Type *ua, *ub;
      Buffer *ba, *bb;
      int pa, pb;
      unsigned int la, lb;

      ub = NULL;
      ba = bb = NULL;
      pa = pb = 0;
      la = lb = 0;
      
      if ((*a != NULL)
          && (NULL != (ua = (User_Mark_Type *) SLang_object_from_mmt (*a))))
        {
           la = ua->m.n;
           pa = ua->m.point;
           ba = ua->b;
        }

      if ((*b != NULL)
          && (NULL != (ub = (User_Mark_Type *) SLang_object_from_mmt (*b))))
        {
           lb = ub->m.n;
           pb = ub->m.point;
           bb = ub->b;
        }

      if ((ba == NULL) || (bb == NULL))
        {
           ic[n] = 0;
           a += da;
           b += db;
           continue;
        }
      
      switch (op)
        {
         case SLANG_GT:
           ic[n] = ((la > lb)
                  || ((la == lb) && (pa > pb)));
           break;
           
         case SLANG_GE:
           ic[n] = ((la > lb)
                  || ((la == lb) && (pa >= pb)));
           break;
           
         case SLANG_LT:
           ic[n] = ((la < lb)
                  || ((la == lb) && (pa < pb)));
           break;

         case SLANG_LE:
           ic[n] = ((la < lb)
                  || ((la == lb) && (pa <= pb)));
           break;
           
         case SLANG_EQ:
           ic[n] = ((ba == bb) && (la == lb) && (pa == pb));
           break;

         case SLANG_NE:
           ic[n] = ((ba != bb) || (la != lb) || (pa != pb));
           break;
           
         default:
           return 0;
        }

      a += da;
      b += db;
     }

   return 1;
}




/*}}}*/

#if JED_HAS_LINE_MARKS
void jed_create_line_mark (int *color) /*{{{*/
{
   SLang_MMT_Type *mmt;
   User_Mark_Type *um;
   
   if (NULL == (mmt = jed_make_user_object_mark ()))
     return;

   um = (User_Mark_Type *) SLang_object_from_mmt (mmt);
   um->m.flags |= JED_LINE_MARK | (*color & MARK_COLOR_MASK);
   if (-1 == SLang_push_mmt (mmt))
     SLang_free_mmt (mmt);
}

/*}}}*/
#endif
   
static int user_mark_sget (unsigned char type, char *name)
{
   SLang_MMT_Type *mmt;
   User_Mark_Type *um;
   int status;
   Buffer *buf;

   (void) type;
   
   if (NULL == (mmt = pop_valid_user_mark (&um)))
     return -1;
   
   buf = um->b;

   status = -1;
   if (0 == strcmp (name, "buffer_name"))
     status = SLang_push_string (buf->name);
   else
     SLang_verror (SL_NOT_IMPLEMENTED,
               "Mark_Type.%s is invalid", name);
   
   SLang_free_mmt (mmt);
   return status;
}


int register_jed_classes (void) /*{{{*/
{
   SLang_Class_Type *cl;
   
   cl = SLclass_allocate_class ("Mark_Type");
   if (cl == NULL) return -1;
   (void) SLclass_set_destroy_function (cl, free_user_mark);
   
   (void) SLclass_set_sget_function (cl, user_mark_sget);

   if (-1 == SLclass_register_class (cl, JED_MARK_TYPE, sizeof (User_Mark_Type), SLANG_CLASS_TYPE_MMT))
     return -1;
   
   if (-1 == SLclass_add_binary_op (JED_MARK_TYPE, JED_MARK_TYPE, user_mark_bin_op, user_mark_bin_op_result))
     return -1;
   
   return 0;
}

/*}}}*/

void jed_widen_whole_buffer (Buffer *b) /*{{{*/
{
   while (b->narrow != NULL) widen_buffer (b);
}

/*}}}*/

#if JED_HAS_SAVE_NARROW
static void restore_saved_narrow (void) /*{{{*/
{
   Mark *beg, *end;
   
   Jed_Save_Narrow_Type *save_narrow;
   
   if (NULL == (save_narrow = CBuf->save_narrow))
     return;
   
   push_spot ();
   /* remove current restriction */
   jed_widen_whole_buffer (CBuf);
   
   beg = save_narrow->beg;
   end = save_narrow->end;
   
   while (beg != NULL)
     {
      jed_goto_mark (beg);
      push_mark ();
      jed_goto_mark (end);
      if (end->flags & NARROW_REGION_MARK)
        narrow_to_region ();
      else narrow_to_lines ();
      
      beg = beg->next;
      end = end->next;
     }
   pop_spot ();
}

/*}}}*/
static void free_mark_chain (Mark *m) /*{{{*/
{
   Mark *next;
      
   while (m != NULL)
     {
      next = m->next;
      SLfree ((char *)m);
      m = next;
     }
}

/*}}}*/
void jed_free_saved_narrow (Buffer *b) /*{{{*/
{
   Jed_Save_Narrow_Type *save_narrow;
   
   save_narrow = b->save_narrow;
   if (save_narrow == NULL) return;
   
   b->save_narrow = save_narrow->next;
   
   free_mark_chain (save_narrow->beg);
   free_mark_chain (save_narrow->end);
   SLfree ((char *)save_narrow);
}

/*}}}*/
void jed_push_narrow (void) /*{{{*/
{
   Jed_Save_Narrow_Type *save_narrow;
   
   if (NULL == (save_narrow = (Jed_Save_Narrow_Type *) jed_malloc0 (sizeof (Jed_Save_Narrow_Type))))
     {
      exit_error ("push_narrow: malloc error.", 0);
     }
   save_narrow->beg = save_narrow->end = NULL;
   save_narrow->next = CBuf->save_narrow;
   CBuf->save_narrow = save_narrow;
   
   push_spot ();
   while (CBuf->narrow != NULL)
     {
      Mark *m;
      
      bob ();
      m = create_mark (0);
      m->next = save_narrow->beg;
      save_narrow->beg = m;
      
      eob ();
      m = create_mark (CBuf->narrow->is_region ? NARROW_REGION_MARK : 0);
      m->next = save_narrow->end;
      save_narrow->end = m;
      
      widen_buffer (CBuf);
     }
   
   restore_saved_narrow ();
   
   pop_spot ();
}

/*}}}*/
void jed_pop_narrow (void) /*{{{*/
{
   restore_saved_narrow ();
   jed_free_saved_narrow (CBuf);
}

/*}}}*/
#endif

int jed_count_narrows (void) /*{{{*/
{
   int n = 0;
   Narrow_Type *nt = CBuf->narrow;
   
   while (nt != NULL)
     {
      n++;
      nt = nt->next;
     }
   return n;
}

/*}}}*/

unsigned int jed_count_lines_in_region (void)
{
   Mark *m;
   unsigned int n0, n1;

   m = CBuf->marks;
   if (m == NULL)
     return 0;
   
   n0 = m->n - CBuf->nup;
   n1 = LineNum;
   
   if (n0 > n1)
     return 1 + (n0 - n1);
   
   return 1 + (n1 - n0);
}

      
   

Generated by  Doxygen 1.6.0   Back to index