/* -*- 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 "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) jed_init_mark (&JWindow->mark, 0); touch_window(); } JWindow = JWindow->next; } jed_pop_mark(0); } /*}}}*/ #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) jed_pop_mark(0); Repeat_Factor = NULL; return(1); } if (CBuf->marks == NULL) { jed_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 jed_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 jed_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) && (0 == LINE_HAS_NEWLINE (CLine))) { /* 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_byte ('\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_wchar (); #if JED_HAS_LINE_ATTRIBUTES CLine->flags = line_flags; #endif pop_spot (); (void) jed_up (1); #if JED_HAS_LINE_ATTRIBUTES line_flags = CLine->flags; CLine->flags &= ~JED_LINE_IS_READONLY; #endif (void) jed_del_wchar (); #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; jed_pop_mark (1); /* 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 jed_push_mark (); (void) jed_insert_newline (); #if JED_HAS_LINE_ATTRIBUTES CLine->flags = line_flags; #endif (void) jed_up (1); #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 jed_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 jed_up (1); #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) /*{{{*/ { if (CBuf->narrow == NULL) return 0; if (CBuf->narrow->is_region == 0) return widen_buffer_lines (CBuf); return widen_buffer (CBuf); } /*}}}*/ int widen_region (void) /*{{{*/ { return widen (); } /*}}}*/ /* 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(); jed_pop_mark(1); jed_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; 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; jed_pop_mark(1); 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_insert_nbytes (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 (" ", NULL, NULL); copy_region_to_buffer(Paste_Buffer); return(0); } /*}}}*/ static int jed_check_readonly_region (void) { int beg_point, end_point; Line *beg, *end; if (CBuf->flags & READ_ONLY) { msg_error(Read_Only_Error); return -1; } if (!check_region(&Number_Zero)) return -1; end = CLine; end_point = Point; (void) exchange_point_mark (); beg = CLine; beg_point = Point; (void) exchange_point_mark (); while (1) { if (beg->flags & JED_LINE_IS_READONLY) { if ((beg == end) && (end_point == 0) && (beg_point == 0)) return 0; msg_error (Line_Read_Only_Error); return -1; } if (beg == end) break; beg = beg->next; } return 0; } int delete_region (void) /*{{{*/ { int beg_point, end_point; Line *beg, *end; if (0 != jed_check_readonly_region ()) return -1; /* make this go through standard ins/del routines to ensure undo */ end = CLine; end_point = Point; push_spot(); jed_pop_mark(1); beg = CLine; beg_point = Point; pop_spot(); if (end != beg) { bol (); if (-1 == jed_del_nbytes (end_point)) return -1; /* go back because we do not want to mess with Line structures changing on us --- shouldn't happen anyway */ while (jed_up (1) && (CLine != beg)) { bol (); if (-1 == jed_del_through_eol ()) return -1; } end_point = CLine->len; /* include \n */ } jed_set_point (beg_point); (void) jed_generic_del_nbytes (end_point - Point); return 1; } /*}}}*/ int kill_region() /*{{{*/ { if (-1 == jed_check_readonly_region ()) return -1; /* need two marks for this one */ push_spot(); if (!jed_pop_mark(1)) { check_region(&Number_Zero); pop_spot(); return(0); } jed_push_mark(); jed_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 (0 == buffer_exists (Rectangle_Buffer)) { 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 (0 == jed_down (1)) { eol(); jed_insert_newline(); } } 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; jed_pop_mark(1); 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_insert_wchar_n_times(' ', n)) break; if (CLine == save_line) break; (void) jed_down (1); } pop_spot(); return(1); } /*}}}*/ /* MB Safe */ static int copy_or_kill_rectangle (int kill) /*{{{*/ { Line *save_line, *line, *beg; int c1, c2, dc, tmp; if (!check_region(&Number_One)) return(0); /* spot pushed */ /* delete Rectangle buffer */ if (Rectangle_Buffer != NULL) delete_buffer(Rectangle_Buffer); Rectangle_Buffer = make_buffer (" ", NULL, NULL); c2 = calculate_column(); save_line = CLine; jed_pop_mark(1); 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); } dc = c2 - c1; /* go through the region copying rectanglar blocks to Rectanglebuffer */ line = beg = NULL; while (1) { int col2, col1; unsigned int len, len1; unsigned int nspaces; unsigned int nbytes; unsigned char *p1, *p2; col1 = goto_column1 (&c1); p1 = CLine->data + Point; if (col1 == c1) { col2 = goto_column1(&c2); p2 = CLine->data + Point; } else { col2 = col1; p2 = p1; } nspaces = (unsigned int) (dc - (col2 - col1)); nbytes = (unsigned int) (p2 - p1); len1 = len = nbytes + nspaces; /* Need to allocate at least 2 bytes, since a single byte is a * signature of a line with a single character whose value is a * newline character. See make_line1 for details. */ if (len <= 1) len1++; if (beg == NULL) { beg = line = make_line1 (len1); beg->prev = NULL; } else { line->next = make_line1 (len1); line->next->prev = line; line = line->next; } line->len = len; memcpy ((char *) line->data, (char *) p1, nbytes); memset ((char *) line->data + nbytes, ' ', nspaces); if (kill && (nbytes != 0)) { jed_position_point (p1); if (-1 == jed_del_nbytes (nbytes)) break; } if (CLine == save_line) break; (void) jed_down(1); } line->next = NULL; Rectangle_Buffer->line = Rectangle_Buffer->beg = beg; Rectangle_Buffer->end = line; Rectangle_Buffer->point = 0; pop_spot(); return(0); } /*}}}*/ int copy_rectangle (void) { return copy_or_kill_rectangle (0); } int kill_rectangle (void) { return copy_or_kill_rectangle (1); } int blank_rectangle (void) /*{{{*/ { int c1, c2; Line *save_line; int ncols; CHECK_READ_ONLY if (!check_region(&Number_One)) return(0); /* push_spot(); performed */ c1 = calculate_column(); save_line = CLine; jed_pop_mark(1); c2 = calculate_column(); if (c1 > c2) { int tmp = c1; c1 = c2; c2 = tmp; } ncols = c2 - c1; Suspend_Screen_Update = 1; while(1) { int pnt; goto_column (&c2); pnt = Point; goto_column (&c1); if (-1 == jed_del_nbytes (pnt - Point)) break; if (-1 == jed_insert_wchar_n_times( ' ', ncols)) break; if (CLine == save_line) break; (void) jed_down (1); } pop_spot(); return(1); } /*}}}*/ /*}}}*/ /*{{{ User Mark Functions */ typedef struct /*{{{*/ { Mark m; /* MUST be the first */ Buffer *b; } /*}}}*/ User_Mark_Type; static void free_user_mark (SLtype 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, SLtype a, SLtype b, SLtype *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, SLtype a_type, VOID_STAR ap, unsigned int na, SLtype 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 (SLtype 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); jed_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); }