1 /* -*- mode: C; mode: fold; -*- */
2 /* Copyright (c) 1992, 1998 John E. Davis
3  * This file is part of JED editor library source.
4  *
5  * You may distribute this file under the terms the GNU General Public
6  * License.  See the file COPYING for more information.
7  */
8 #include "config.h"
9 #include "jed-feat.h"
10 /*{{{ Include Files */
11 
12 #include <stdio.h>
13 #include <string.h>
14 
15 #include "buffer.h"
16 #include "ins.h"
17 #include "line.h"
18 #include "screen.h"
19 #include "window.h"
20 #include "misc.h"
21 #include "paste.h"
22 #include "ledit.h"
23 #include "undo.h"
24 #include "kanji.h"
25 
26 /*}}}*/
27 
28 int Suspend_Screen_Update = 0;
29 int No_Screen_Update;
30 
cinsert_update_marks(Mark * m,unsigned int linenum,int n)31 static void cinsert_update_marks (Mark *m, unsigned int linenum, int n)
32 {
33    (void) linenum;
34 
35    while (m != NULL)
36      {
37 	if ((m->line == CLine) && (m->point > Point))
38 	  m->point += n;
39 	m = m->next;
40      }
41 }
42 
cdelete_update_marks(Mark * m,unsigned int linenum,int n)43 static void cdelete_update_marks (Mark *m, unsigned int linenum, int n)
44 {
45    (void) linenum;
46    while(m != NULL)
47      {
48 	if ((m->line == CLine) && (m->point > Point))
49 	  {
50 	     int tmp;
51 
52 	     /* BCC generates wrong code here with optimization.  So use a
53 	      * silly tmp variable as a way around the bug.
54 	      */
55 	     tmp = m->point;
56 	     tmp -= n;
57 	     if (tmp < Point) tmp = Point;
58 	     m->point = tmp;
59 
60 	     /*
61 	      BAD CODE:
62 	     m->point -= n;
63 	     if (m->point < Point) m->point = Point; */
64 	  }
65 	m = m->next;
66      }
67 }
68 
ldelete_update_marks(Mark * m,unsigned int linenum,int n)69 static void ldelete_update_marks (Mark *m, unsigned int linenum, int n)
70 {
71    (void) n;
72    while (m != NULL)
73      {
74 	if (CLine == m->line)
75 	  {
76 	     if (CLine->prev != NULL)
77 	       {
78 		  m->line = CLine->prev;
79 	       }
80 	     else m->line = CBuf->beg;
81 	     m->point = 0;
82 	  }
83 	if (linenum <= m->n) m->n -= 1;
84 	m = m->next;
85      }
86 }
87 
nldelete_update_marks(Mark * m,unsigned int linenum,int n)88 static void nldelete_update_marks (Mark *m, unsigned int linenum, int n)
89 {
90    /* deletion performed at end of a line (CLine->prev)  */
91 
92    (void) n;
93    while (m != NULL)
94       {
95 	 if (m->line == CLine)
96 	   {
97 	      m->line = CLine->prev;
98 	      m->point += Point;
99 	   }
100 	 if (linenum <= m->n) m->n -= 1;
101 	 m = m->next;
102       }
103 }
104 
105 
nlinsert_update_marks(Mark * m,unsigned int linenum,int n)106 static void nlinsert_update_marks (Mark *m, unsigned int linenum, int n)
107 {
108    /* newline added-- affects only marks onward from insertion point */
109    (void) n;
110    while (m != NULL)
111       {
112 	 /* This is a bit controversial if the mark corresponds to JWindow->beg.
113 	    In this case, JWindow beg gets shifted if Point = 0.  */
114 
115 	 if ((linenum < m->n)
116 	     || ((linenum == m->n) && (m->point > Point))) m->n += 1;
117 
118 	 if ((m->line == CLine) && (m->point > Point))
119             {
120 	       m->line = CLine->next;
121 	       m->point -= Point;
122 	       if (m->point > m->line->len) m->point = m->line->len;
123             }
124 	 m = m->next;
125       }
126 }
127 
128 
jed_update_marks(int type,int n)129 void jed_update_marks (int type, int n) /*{{{*/
130 {
131    register Window_Type *w;
132    register Buffer *b = CBuf;
133    Mark *m;
134 #if JED_HAS_SAVE_NARROW
135    Jed_Save_Narrow_Type *save_narrow;
136 #endif
137    void (*update_marks_fun) (Mark *, unsigned int, int);
138    unsigned int line_num;
139 
140    if (!n) return;
141 
142    switch (type)
143      {
144       case CINSERT:
145 	update_marks_fun = cinsert_update_marks;
146 	break;
147 
148       case CDELETE:
149 	update_marks_fun = cdelete_update_marks;
150 	break;
151 
152       case LDELETE:
153 	update_marks_fun = ldelete_update_marks;
154 	break;
155 
156       case NLINSERT:
157 	update_marks_fun = nlinsert_update_marks;
158 	break;
159 
160       case NLDELETE:
161 	update_marks_fun = nldelete_update_marks;
162 	break;
163 
164       default:
165 	update_marks_fun = NULL;       /* crash.  I want to know about this */
166      }
167 
168    Cursor_Motion = 0;
169 
170    if (b->flags & UNDO_ENABLED)
171      {
172 	if (b->undo == NULL) create_undo_ring();
173 	Undo_Buf_Unch_Flag = !(b->flags & BUFFER_MODIFIED);
174      }
175 
176    mark_buffer_modified (1);
177 
178    line_num = LineNum + CBuf->nup;
179 #if JED_HAS_LINE_ATTRIBUTES
180    if ((b->min_unparsed_line_num == 0)
181        || (b->min_unparsed_line_num > line_num))
182      b->min_unparsed_line_num = line_num;
183 
184    if ((b->max_unparsed_line_num == 0)
185        || (b->max_unparsed_line_num < line_num))
186      b->max_unparsed_line_num = line_num;
187 #endif
188    if ((m = b->spots) != NULL) (*update_marks_fun)(m, line_num, n);
189    if ((m = b->marks) != NULL) (*update_marks_fun)(m, line_num, n);
190    if ((m = b->user_marks) != NULL) (*update_marks_fun)(m, line_num, n);
191 
192 #if JED_HAS_SAVE_NARROW
193    save_narrow = b->save_narrow;
194    while (save_narrow != NULL)
195      {
196 	(*update_marks_fun) (save_narrow->beg, line_num, n);
197 	(*update_marks_fun) (save_narrow->end, line_num, n);
198 	save_narrow = save_narrow->next;
199      }
200 #endif
201 
202    w = JWindow;
203    do
204      {
205 	if (w->buffer == b)
206 	  {
207 	     (*update_marks_fun) (&w->mark, line_num, n);
208 	     (*update_marks_fun) (&w->beg, line_num, n);
209 	  }
210 
211 	w = w->next;
212      }
213    while (w != JWindow);
214 
215    if (!Suspend_Screen_Update) register_change(type);
216 }
217 
218 /*}}}*/
219 
ins(char c)220 void ins (char c) /*{{{*/
221 {
222    register unsigned char *p, *p1, *p2;
223 
224     if (CLine == NULL)
225       {
226           exit_error("ins: CLine is NULL", 1);
227       }
228 
229 #ifdef KEEP_SPACE_INFO
230    if (CLine->space <= CLine->len + 1)
231      remake_line(CLine->space + 15);
232 #else
233    remake_line (CLine->len + 1);
234 #endif
235 
236     p = CLine->data + Point;
237     if (Point < CLine->len)
238       {
239           p1 = CLine->data + (CLine->len - 1);
240 	 p2 = p1 + 1;
241           while(p1 >= p)
242             {
243 	       *p2 = *p1;
244 	       p2 = p1;
245 	       p1--;
246 	       /* *(p1 + 1) = *p1; p1--; */
247             }
248       }
249     *p = c;
250     CLine->len += 1;
251    jed_update_marks(CINSERT,1);
252    if ((c != '\n') || (CBuf == MiniBuffer)) record_insertion(1);
253     Point++;
254 }
255 
256 /*}}}*/
257 
del_newline(void)258 void del_newline(void) /*{{{*/
259 {
260    CHECK_READ_ONLY_VOID
261 #if JED_HAS_LINE_ATTRIBUTES
262    if ((CLine->next != NULL) && (CLine->next->flags & JED_LINE_IS_READONLY))
263      {
264 	msg_error (Line_Read_Only_Error);
265 	return;
266      }
267 #endif
268 
269    if (!eol() || eobp()) return;
270 #ifdef DEBUG_JED
271    if (CLine->len == 0)
272      {
273 	exit_error("del(): empty line", 1);
274      }
275 #endif
276 
277    CLine->len -= 1;
278    jed_update_marks(CDELETE,1);
279    record_deletion((unsigned char *) "\n", 1);
280    splice_line();
281 }
282 
283 /*}}}*/
284 
285 /* del *np chars up until newline.  Return actual number deleted */
deln(int * np)286 int deln(int *np) /*{{{*/
287 {
288    int n = *np;
289    register int nn;
290    register unsigned char *p, *pmax;
291 
292    if ((n == 0) || !CLine->len) return(0);
293 
294    nn = CLine->len - 1;
295    p = CLine->data + nn;
296    if ((*p == '\n') && (CBuf != MiniBuffer)) nn = nn - Point; else nn = nn - Point + 1;
297 
298    p = CLine->data + Point;
299 
300    nn = nn > n ? n : nn;
301    if(iskanji2nd(CLine->data, Point+nn) == TRUE) nn++;
302    if (!nn) return (0);
303    jed_update_marks(CDELETE, nn);
304    record_deletion(p, nn);
305    CLine->len -= nn;
306    pmax = CLine->data + CLine->len;
307    while (p < pmax)
308      {
309 	*p = *(p + nn);
310 	p++;
311      }
312    return(nn);
313 }
314 
315 /*}}}*/
316 
317 /* delete n characters, crossing nl if necessary */
generic_deln(int * np)318 void generic_deln(int *np) /*{{{*/
319 {
320    int n = *np;
321 
322    CHECK_READ_ONLY_VOID
323 
324    while ((n > 0) && (SLang_Error == 0))
325      {
326 	if (eobp())
327 	  {
328 	     msg_error("End of Buffer.");
329 	     return;
330 	  }
331 	n -= deln(&n);
332 	if (0 < n) del_newline();
333 	n--;
334      }
335 }
336 
337 /*}}}*/
338 
del()339 void del() /*{{{*/
340 {
341    generic_deln(&Number_One);
342 }
343 
344 /*}}}*/
345 
quick_insert(register unsigned char * s,int n)346 void quick_insert(register unsigned char *s, int n) /*{{{*/
347 {
348    register unsigned char *p, *p1;
349    int nl = 0;
350 
351    if (n == 0) return;
352    if ((*(s + (n - 1)) == '\n') && (CBuf != MiniBuffer))
353      {
354 	n--;
355 	nl = 1;
356      }
357 
358 #ifdef KEEP_SPACE_INFO
359    if (CLine->space <= CLine->len + n + 1) remake_line(CLine->space + n + 8);
360 #else
361    if (n) remake_line (CLine->len + n);
362 #endif
363 
364 
365    /* shove n chars over to make space */
366    p = CLine->data + Point;
367    if (Point < CLine->len)   /* could be equal for last line of buffer */
368      {
369 	p1 = CLine->data + CLine->len - 1;
370 	while(p1 >= p)
371 	  {
372 	     *(p1 + n) = *p1;
373 	     p1--;
374 	  }
375      }
376    CLine->len += n;
377    SLMEMCPY((char *) p, (char *) s, n);
378 
379    jed_update_marks(CINSERT, n);
380    record_insertion(n);
381    Point += n;
382 
383    if (nl)
384      {
385 	split_line();
386 	ins('\n');
387 	CLine = CLine->next;
388 	LineNum++;
389 	Point = 0;
390      }
391 }
392 
393 /*}}}*/
394 
ins_chars(unsigned char * ss,int n)395 void ins_chars(unsigned char *ss, int n) /*{{{*/
396 {
397    register unsigned char nl, *pmax;
398    register unsigned char *p, *p1, *s = ss;
399    int n1;
400 
401    if (CBuf == MiniBuffer) nl = 0; else nl = '\n';
402 
403    p1 = s;
404    while (1)
405      {
406 	p = p1;
407 	/* count the number until a new line is reached */
408 	pmax = p1 + n;
409 	while((p1 < pmax) && (*p1 != nl)) p1++;
410 
411 	n1 = (int) (p1 - p);
412 	if (p1 != pmax) n1++;
413 	quick_insert(p, n1);
414 	if (p1++ == pmax) return;
415 	n -= n1;
416      }
417 }
418 
419 /*}}}*/
420 
421 /* This needs fixed to handle large n */
ins_char_n_times(char c,int n)422 void ins_char_n_times(char c, int n) /*{{{*/
423 {
424     char b[256], *p;
425     int n1;
426 
427     if (n == 0) return;
428     if (n > 255) n = 255;
429     p = b;
430     n1 = n;
431     while(n1--) *p++ = c;
432     ins_chars((unsigned char *) b, n);
433 }
434 
435 /*}}}*/
436 
insert_buffer(Buffer * b)437 void insert_buffer(Buffer *b) /*{{{*/
438 {
439    Buffer *cb;
440 
441    if ((cb = CBuf) == b) return;
442 
443    switch_to_buffer(b);
444    push_spot();
445    bob(); push_mark();
446    eob();
447    copy_region_to_buffer(cb);
448    pop_spot();
449    switch_to_buffer(cb);
450 
451    touch_window();
452 }
453 
454 /*}}}*/
455 
replace_char(unsigned char ch)456 void replace_char(unsigned char ch) /*{{{*/
457 {
458    if (ch == '\n') return;
459    if (*(CLine->data + Point) == ch) return;
460    ins(ch); del(); Point--;
461 }
462 
463 /*}}}*/
464