/* -*- mode: C; mode: fold; -*- */ /* Copyright (c) 1992, 1998, 2000, 2002, 2003, 2004, 2005, 2006 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 #include #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 (int check_line_readonly) { if (CBuf->flags & READ_ONLY) { jed_verror ("Buffer %s is read-only", CBuf->name); return -1; } #if JED_HAS_LINE_ATTRIBUTES if (check_line_readonly && (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_get_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_get_error ()) return -1; return 0; } /* This function does not handle newlines, that is, it does not split the * line if one is inserted. */ int _jed_ins_byte (unsigned char c) /*{{{*/ { register unsigned char *p, *p1, *p2; if (-1 == jed_prepare_for_modification (0)) 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 (1)) return -1; #if JED_HAS_LINE_ATTRIBUTES if ((CLine->next != NULL) && (CLine->len > 1) && (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_del_nbytes (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 (1)) 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_del_nbytes (int n) /*{{{*/ { while ((n > 0) && (SLang_get_error () == 0)) { int dn; if (eobp()) { msg_error("End of Buffer."); return -1; } dn = jed_del_nbytes (n); if (dn == -1) return -1; n -= dn; if (n && (-1 == jed_del_newline())) return -1; n--; } return 0; } /*}}}*/ int jed_del_through_eol (void) { return jed_generic_del_nbytes (CLine->len - Point); } int jed_insert_newline (void) { #if JED_HAS_LINE_ATTRIBUTES unsigned int flags = CLine->flags; #endif if (-1 == jed_prepare_for_modification (Point != 0)) return -1; split_line(); #if JED_HAS_LINE_ATTRIBUTES if (Point == 0) CLine->flags = 0; #endif if (-1 == _jed_ins_byte ('\n')) return -1; (void) jed_down (1); #if JED_HAS_LINE_ATTRIBUTES CLine->flags = flags; #endif return 0; } /* MULTIBYTE OK */ int jed_del_wchar (void) { unsigned char *p, *pmax; if (eolp ()) return jed_del_through_eol (); p = CLine->data + Point; pmax = jed_multibyte_chars_forward (p, CLine->data + CLine->len, 1, NULL, 1); return jed_generic_del_nbytes (pmax - p); } 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 (0)) return -1; #if JED_HAS_LINE_ATTRIBUTES if ((CLine->flags & JED_LINE_IS_READONLY) && ((Point != 0) || (s[n-1] != '\n'))) { jed_verror (Line_Read_Only_Error); return -1; } #endif if ((*(s + (n - 1)) == '\n') && (CBuf != MiniBuffer)) { n--; nl = 1; if (-1 == jed_insert_newline ()) return -1; (void) jed_up(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) jed_down (1); return 0; } /*}}}*/ int jed_insert_nbytes (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; } } /*}}}*/ /* Multibyte-safe */ int jed_insert_wchar_n_times (SLwchar_Type c, unsigned int n) /*{{{*/ { unsigned char wchar_buf [JED_MAX_MULTIBYTE_SIZE]; unsigned char buf[20*JED_MAX_MULTIBYTE_SIZE]; unsigned char *pmax; unsigned int len; if (n == 0) return 0; if (NULL == (pmax = jed_wchar_to_multibyte (c, wchar_buf))) return -1; len = pmax - wchar_buf; pmax = buf + (sizeof (buf) - len); while (n) { unsigned char *p = buf; while ((p < pmax) && n) { memcpy (p, wchar_buf, len); n--; p += len; } if (-1 == jed_insert_nbytes (buf, p - buf)) return -1; } return 0; } /*}}}*/ void insert_buffer(Buffer *b) /*{{{*/ { Buffer *cb; if ((cb = CBuf) == b) return; switch_to_buffer(b); push_spot(); bob(); jed_push_mark(); eob(); copy_region_to_buffer(cb); pop_spot(); switch_to_buffer(cb); touch_window(); } /*}}}*/ /* Multibyte safe */ int _jed_replace_wchar (SLwchar_Type ch) /*{{{*/ { unsigned char buf[JED_MAX_MULTIBYTE_SIZE]; unsigned char *b, *bmax; unsigned char *p, *pmax; if (ch == '\n') return -1; b = buf; bmax = jed_wchar_to_multibyte (ch, buf); if (bmax == NULL) return -1; p = CLine->data + Point; pmax = CLine->data + CLine->len; while ((p < pmax) && (b < bmax) && (*b == *p)) { b++; p++; } if (b == bmax) return 0; if (-1 == jed_insert_nbytes (buf, bmax - buf)) return -1; if (-1 == jed_del_wchar ()) return -1; (void) jed_left(1); return 0; } /*}}}*/ int jed_insert_string (char *s) { return jed_insert_nbytes ((unsigned char *) s, strlen (s)); } int jed_insert_byte (unsigned char ch) { return jed_insert_nbytes (&ch, 1); } int jed_insert_wchar (SLwchar_Type ch) { unsigned char buf[JED_MAX_MULTIBYTE_SIZE]; unsigned char *b; if (NULL == (b = jed_wchar_to_multibyte (ch, buf))) return -1; return jed_insert_nbytes (buf, b-buf); }