Logo Search packages:      
Sourcecode: jed version File versions

ins.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 "screen.h"
#include "window.h"
#include "misc.h"
#include "paste.h"
#include "ledit.h"
#include "undo.h"
#include "file.h"

/*}}}*/

int Suspend_Screen_Update = 0;
int No_Screen_Update;

static void cinsert_update_marks (Mark *m, unsigned int linenum, int n)
{
   (void) linenum;

   while (m != NULL)
     {
      if ((m->line == CLine) && (m->point > Point))
        m->point += n;
      m = m->next;
     }
}

static void cdelete_update_marks (Mark *m, unsigned int linenum, int n)
{
   (void) linenum;
   while(m != NULL)
     {
      if ((m->line == CLine) && (m->point > Point))
        {
           int tmp;

           /* BCC generates wrong code here with optimization.  So use a
            * silly tmp variable as a way around the bug.
            */
           tmp = m->point;
           tmp -= n;
           if (tmp < Point) tmp = Point;
           m->point = tmp;
           
           /*
            BAD CODE:
           m->point -= n;
           if (m->point < Point) m->point = Point; */
        }
      m = m->next;
     }
}

static void ldelete_update_marks (Mark *m, unsigned int linenum, int n)
{
   (void) n;
   while (m != NULL)
     {
      if (CLine == m->line)
        {
           if (CLine->prev != NULL)
             {
              m->line = CLine->prev;
             }
           else m->line = CBuf->beg;
           m->point = 0;
        }
      if (linenum <= m->n) m->n -= 1;
      m = m->next;
     }
}

static void nldelete_update_marks (Mark *m, unsigned int linenum, int n)
{
   /* deletion performed at end of a line (CLine->prev)  */
   
   (void) n;
   while (m != NULL)
      {
       if (m->line == CLine)
         {
            m->line = CLine->prev;
            m->point += Point;
         }
       if (linenum <= m->n) m->n -= 1;
       m = m->next;
      }
}


static void nlinsert_update_marks (Mark *m, unsigned int linenum, int n)
{
   /* newline added-- affects only marks onward from insertion point */
   (void) n;
   while (m != NULL)
      {
       /* This is a bit controversial if the mark corresponds to JWindow->beg.
          In this case, JWindow beg gets shifted if Point = 0.  */

       if ((linenum < m->n) 
           || ((linenum == m->n) && (m->point > Point))) m->n += 1;
          
       if ((m->line == CLine) && (m->point > Point))
            {
             m->line = CLine->next;
             m->point -= Point;
             if (m->point > m->line->len) m->point = m->line->len;
            }
       m = m->next;
      }
}


void jed_update_marks (int type, int n) /*{{{*/
{
   register Window_Type *w;
   register Buffer *b = CBuf;
   Mark *m;
#if JED_HAS_SAVE_NARROW
   Jed_Save_Narrow_Type *save_narrow;
#endif
   void (*update_marks_fun) (Mark *, unsigned int, int);
   unsigned int line_num;

   if (!n) return;
   
   switch (type)
     {
      case CINSERT:
      update_marks_fun = cinsert_update_marks;
      break;
      
      case CDELETE:
      update_marks_fun = cdelete_update_marks;
      break;
      
      case LDELETE:
      update_marks_fun = ldelete_update_marks;
      break;
      
      case NLINSERT:
      update_marks_fun = nlinsert_update_marks;
      break;
      
      case NLDELETE:
      update_marks_fun = nldelete_update_marks;
      break;
      
      default:
      update_marks_fun = NULL;       /* crash.  I want to know about this */
     }

   Cursor_Motion = 0;

   if (b->flags & UNDO_ENABLED)
     {
      if (b->undo == NULL) create_undo_ring();
      Undo_Buf_Unch_Flag = !(b->flags & BUFFER_MODIFIED);
     }
   
   mark_buffer_modified (b, 1, 0);

   line_num = LineNum + b->nup;
#if JED_HAS_LINE_ATTRIBUTES
   if ((b->min_unparsed_line_num == 0)
       || (b->min_unparsed_line_num > line_num))
     b->min_unparsed_line_num = line_num;

   if ((b->max_unparsed_line_num == 0)
       || (b->max_unparsed_line_num < line_num))
     b->max_unparsed_line_num = line_num;
#endif
   if ((m = b->spots) != NULL) (*update_marks_fun)(m, line_num, n);
   if ((m = b->marks) != NULL) (*update_marks_fun)(m, line_num, n);
   if ((m = b->user_marks) != NULL) (*update_marks_fun)(m, line_num, n);

#if JED_HAS_SAVE_NARROW
   save_narrow = b->save_narrow;
   while (save_narrow != NULL)
     {
      (*update_marks_fun) (save_narrow->beg, line_num, n);
      (*update_marks_fun) (save_narrow->end, line_num, n);
      save_narrow = save_narrow->next;
     }
#endif
   
   w = JWindow;
   do
     {
      if (w->buffer == b)
        {
           (*update_marks_fun) (&w->mark, line_num, n);
           (*update_marks_fun) (&w->beg, line_num, n);
        }

      w = w->next;
     }
   while (w != JWindow);

   if (!Suspend_Screen_Update) register_change(type);
}

/*}}}*/

int jed_prepare_for_modification (void)
{
   if (CBuf->flags & READ_ONLY)
     {
      jed_verror ("Buffer %s is read-only", CBuf->name);
      return -1;
     }
#if JED_HAS_LINE_ATTRIBUTES
   if (CLine->flags & JED_LINE_IS_READONLY)
     {
      jed_verror ("This line is read-only");
      return -1;
     }
#endif

   if (CBuf->flags & BUFFER_MODIFIED)
     return 0;
   
   if (0 == CBuf->file[0])
     return 0;                       /* not attached to a file */
   
   if ((SLang_Error == 0)
       && (0 == (CBuf->flags & BUFFER_NON_LOCKING)))
     {
      check_buffer (CBuf);
      if (CBuf->flags & FILE_MODIFIED)
        {
           if (1 != jed_get_y_n ("File changed on disk.  Do you really want to edit this buffer"))
             return -1;
        }
      if (1 == jed_buffer_file_is_readonly (CBuf))
        {
           if (1 != jed_get_y_n ("Disk file is read-only.  Do you really want to edit this buffer"))
             {
              CBuf->flags |= READ_ONLY;
              return -1;
             }
        }

      (void) jed_lock_buffer_file (CBuf);
     }

   if (SLang_Error)
     return -1;

   return 0;
}


int jed_ins (char c) /*{{{*/
{
   register unsigned char *p, *p1, *p2;

   if (-1 == jed_prepare_for_modification ())
     return -1;

#ifdef KEEP_SPACE_INFO
   if (CLine->space <= CLine->len + 1)
     remake_line(CLine->space + 15);
#else
   remake_line (CLine->len + 1);
#endif

   p = CLine->data + Point;
   if (Point < CLine->len)
     {
      p1 = CLine->data + (CLine->len - 1);
      p2 = p1 + 1;
      while(p1 >= p)
        {
           *p2 = *p1;
           p2 = p1;
           p1--;
           /* *(p1 + 1) = *p1; p1--; */
        }
     }
   *p = c;
   CLine->len += 1;
   jed_update_marks(CINSERT,1);
   if ((c != '\n') || (CBuf == MiniBuffer)) record_insertion(1);
   Point++;
   
   return 0;
}

/*}}}*/

int jed_del_newline(void) /*{{{*/
{
   if (-1 == jed_prepare_for_modification ())
     return -1;

#if JED_HAS_LINE_ATTRIBUTES
   if ((CLine->next != NULL) && (CLine->next->flags & JED_LINE_IS_READONLY))
     {
      msg_error (Line_Read_Only_Error);
      return -1;
     }
#endif

   if (!eol() || eobp()) return -1;
   
   CLine->len -= 1;
   jed_update_marks(CDELETE,1);
   record_deletion((unsigned char *) "\n", 1);
   splice_line();
   return 0;
}

/*}}}*/

/* del *np chars up until newline.  Return actual number deleted. */
int jed_deln (int n) /*{{{*/
{
   register int nn;
   register unsigned char *p, *pmax;

   if ((n == 0) || !CLine->len) return 0;

   nn = CLine->len - 1;
   p = CLine->data + nn;
   if ((*p == '\n') && (CBuf != MiniBuffer)) nn = nn - Point; else nn = nn - Point + 1;
   
   p = CLine->data + Point;

   nn = nn > n ? n : nn;
   if (!nn) return (0);

   if (-1 == jed_prepare_for_modification ())
     return -1;

   jed_update_marks(CDELETE, nn);
   record_deletion(p, nn);
   CLine->len -= nn;
   pmax = CLine->data + CLine->len;
   while (p < pmax)
     {
      *p = *(p + nn);
      p++;
     }
   return nn;
}

/*}}}*/

/* delete n characters, crossing nl if necessary */
int jed_generic_deln (int n) /*{{{*/
{
   while ((n > 0) && (SLang_Error == 0))
     {
      int dn;

      if (eobp())
        {
           msg_error("End of Buffer.");
           return -1;
        }
      
      dn = jed_deln (n);
      if (dn == -1)
        return -1;
      
      n -= dn;

      if (n && (-1 == jed_del_newline()))
        return -1;

      n--;
     }
   return 0;
}

/*}}}*/

int jed_del (void) /*{{{*/
{
   return jed_generic_deln (1);
}

/*}}}*/

int jed_quick_insert(register unsigned char *s, int n) /*{{{*/
{
   register unsigned char *p, *p1;
   int nl = 0;
   
   if (n == 0) return 0;

   if (-1 == jed_prepare_for_modification ())
     return -1;
   
   if ((*(s + (n - 1)) == '\n') && (CBuf != MiniBuffer))
     {
      n--;
      nl = 1;
     }
   
#ifdef KEEP_SPACE_INFO
   if (CLine->space <= CLine->len + n + 1) remake_line(CLine->space + n + 8);
#else
   if (n) remake_line (CLine->len + n);
#endif
    
   
   /* shove n chars over to make space */
   p = CLine->data + Point;
   if (Point < CLine->len)   /* could be equal for last line of buffer */
     {
      p1 = CLine->data + CLine->len - 1;
      while(p1 >= p)
        {
           *(p1 + n) = *p1;
           p1--;
        }
     }
   CLine->len += n;
   SLMEMCPY((char *) p, (char *) s, n);
   
   jed_update_marks(CINSERT, n);
   record_insertion(n);
   Point += n;

   if (nl)
     {
      split_line();
      if (-1 == jed_ins('\n'))
        return -1;
      CLine = CLine->next;
      LineNum++;
      Point = 0;
     }
   
   return 0;
}

/*}}}*/

int jed_ins_chars(unsigned char *ss, int n) /*{{{*/
{
   register unsigned char nl, *pmax;
   register unsigned char *p, *p1, *s = ss;
   int n1;

   if (CBuf == MiniBuffer) nl = 0; else nl = '\n';
   
   p1 = s;
   while (1)
     {
      p = p1;
      /* count the number until a new line is reached */
      pmax = p1 + n;
      while((p1 < pmax) && (*p1 != nl)) p1++;
      
      n1 = (int) (p1 - p);
      if (p1 != pmax) n1++;
      if (-1 == jed_quick_insert(p, n1))
        return -1;
      if (p1++ == pmax) return 0;
      n -= n1;
     }
}

/*}}}*/

/* This needs fixed to handle large n */
int jed_ins_char_n_times(char c, int n) /*{{{*/
{
    char b[256], *p;
    int n1;

    if (n == 0) return 0;
    if (n > 255) n = 255;
    p = b;
    n1 = n;
    while(n1--) *p++ = c;
   return jed_ins_chars((unsigned char *) b, n);
}

/*}}}*/

void insert_buffer(Buffer *b) /*{{{*/
{
   Buffer *cb;

   if ((cb = CBuf) == b) return;

   switch_to_buffer(b);
   push_spot();
   bob(); push_mark();
   eob();
   copy_region_to_buffer(cb);
   pop_spot();
   switch_to_buffer(cb);

   touch_window();
}

/*}}}*/

int jed_replace_char(unsigned char ch) /*{{{*/
{
   if (*(CLine->data + Point) == ch) return 0;
   if (ch == '\n') return -1;
   if (-1 == jed_ins(ch))
     return -1;
   if (-1 == jed_del())
     return -1;
   
   Point--;
   return 0;
}

/*}}}*/

int jed_insert_string (char *s)
{
   return jed_ins_chars ((unsigned char *) s, strlen (s));
}

int jed_insert_newline (void)
{
   return jed_ins_chars ((unsigned char *) "\n", 1);
}

Generated by  Doxygen 1.6.0   Back to index