1 /* -*- mode: C; mode: fold; -*- */
2 /* Copyright (c) 1992, 1998, 2000, 2002, 2003, 2004, 2005, 2006 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 "file.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 (b, 1, 0);
177 
178    line_num = LineNum + b->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 
jed_prepare_for_modification(int check_line_readonly)220 int jed_prepare_for_modification (int check_line_readonly)
221 {
222    if (CBuf->flags & READ_ONLY)
223      {
224 	jed_verror ("Buffer %s is read-only", CBuf->name);
225 	return -1;
226      }
227 
228 #if JED_HAS_LINE_ATTRIBUTES
229    if (check_line_readonly
230        && (CLine->flags & JED_LINE_IS_READONLY))
231      {
232 	jed_verror ("This line is read-only");
233 	return -1;
234      }
235 #endif
236 
237    if (CBuf->flags & BUFFER_MODIFIED)
238      return 0;
239 
240    if (0 == CBuf->file[0])
241      return 0;			       /* not attached to a file */
242 
243    /* if ((SLang_get_error () == 0) */
244    if (0 == (CBuf->flags & BUFFER_NON_LOCKING))
245      {
246 	if (0 == (CBuf->flags & FILE_MODIFIED))
247 	  check_buffer (CBuf);
248 	if (CBuf->flags & FILE_MODIFIED)
249 	  {
250 	     if (1 != jed_get_y_n ("File changed on disk.  Do you really want to edit this buffer"))
251 	       return -1;
252 	  }
253 #if 0  /* If the buffer has had the read_only flag unset, then assume the user
254 	* knows what he/she is doing.
255 	*/
256 	if (1 == jed_buffer_file_is_readonly (CBuf))
257 	  {
258 	     if (1 != jed_get_y_n ("Disk file is read-only.  Do you really want to edit this buffer"))
259 	       {
260 		  CBuf->flags |= READ_ONLY;
261 		  return -1;
262 	       }
263 	  }
264 #endif
265 
266 	if ((-1 == jed_lock_buffer_file (CBuf))
267 	    && SLang_get_error ())
268 	  return -1;
269      }
270 #if 0
271    if (SLang_get_error ())
272      return -1;
273 #endif
274    return 0;
275 }
276 
277 /* This function does not handle newlines, that is, it does not split the
278  * line if one is inserted.
279  */
_jed_ins_byte(unsigned char c)280 int _jed_ins_byte (unsigned char c) /*{{{*/
281 {
282    register unsigned char *p, *p1, *p2;
283 
284    if (-1 == jed_prepare_for_modification (0))
285      return -1;
286 
287 #ifdef KEEP_SPACE_INFO
288    if (CLine->space <= CLine->len + 1)
289      remake_line(CLine->space + 15);
290 #else
291    remake_line (CLine->len + 1);
292 #endif
293 
294    p = CLine->data + Point;
295    if (Point < CLine->len)
296      {
297 	p1 = CLine->data + (CLine->len - 1);
298 	p2 = p1 + 1;
299 	while(p1 >= p)
300 	  {
301 	     *p2 = *p1;
302 	     p2 = p1;
303 	     p1--;
304 	     /* *(p1 + 1) = *p1; p1--; */
305 	  }
306      }
307    *p = c;
308    CLine->len += 1;
309    jed_update_marks(CINSERT,1);
310    if ((c != '\n') || (CBuf == MiniBuffer)) record_insertion(1);
311    Point++;
312 
313    return 0;
314 }
315 
316 /*}}}*/
317 
jed_del_newline(void)318 int jed_del_newline(void) /*{{{*/
319 {
320    if (-1 == jed_prepare_for_modification (1))
321      return -1;
322 
323 #if JED_HAS_LINE_ATTRIBUTES
324    if ((CLine->next != NULL)
325        && (CLine->len > 1)
326        && (CLine->next->flags & JED_LINE_IS_READONLY))
327      {
328 	msg_error (Line_Read_Only_Error);
329 	return -1;
330      }
331 #endif
332 
333    if (!eol() || eobp()) return -1;
334 
335    CLine->len -= 1;
336    jed_update_marks(CDELETE,1);
337    record_deletion((unsigned char *) "\n", 1);
338    splice_line();
339    return 0;
340 }
341 
342 /*}}}*/
343 
344 /* del *np chars up until newline.  Return actual number deleted. */
jed_del_nbytes(int n)345 int jed_del_nbytes (int n) /*{{{*/
346 {
347    register int nn;
348    register unsigned char *p, *pmax;
349 
350    if ((n == 0) || !CLine->len) return 0;
351 
352    nn = CLine->len - 1;
353    p = CLine->data + nn;
354    if ((*p == '\n') && (CBuf != MiniBuffer)) nn = nn - Point; else nn = nn - Point + 1;
355 
356    p = CLine->data + Point;
357 
358    nn = nn > n ? n : nn;
359    if (!nn) return (0);
360 
361    if (-1 == jed_prepare_for_modification (1))
362      return -1;
363 
364    jed_update_marks(CDELETE, nn);
365    record_deletion(p, nn);
366    CLine->len -= nn;
367    pmax = CLine->data + CLine->len;
368    while (p < pmax)
369      {
370 	*p = *(p + nn);
371 	p++;
372      }
373    return nn;
374 }
375 
376 /*}}}*/
377 
378 /* delete n characters, crossing nl if necessary */
jed_generic_del_nbytes(int n)379 int jed_generic_del_nbytes (int n) /*{{{*/
380 {
381    /* while ((n > 0) && (SLang_get_error () == 0)) */
382    while (n > 0)
383      {
384 	int dn;
385 
386 	if (eobp())
387 	  {
388 	     msg_error("End of Buffer.");
389 	     return -1;
390 	  }
391 
392 	dn = jed_del_nbytes (n);
393 	if (dn == -1)
394 	  return -1;
395 
396 	n -= dn;
397 
398 	if (n && (-1 == jed_del_newline()))
399 	  return -1;
400 
401 	n--;
402      }
403    return 0;
404 }
405 
406 /*}}}*/
407 
jed_del_through_eol(void)408 int jed_del_through_eol (void)
409 {
410    return jed_generic_del_nbytes (CLine->len - Point);
411 }
412 
jed_insert_newline(void)413 int jed_insert_newline (void)
414 {
415 #if JED_HAS_LINE_ATTRIBUTES
416    unsigned int flags = CLine->flags;
417 #endif
418    if (-1 == jed_prepare_for_modification (Point != 0))
419      return -1;
420 
421    split_line();
422 #if JED_HAS_LINE_ATTRIBUTES
423    if (Point == 0)
424      CLine->flags = 0;
425 #endif
426    if (-1 == _jed_ins_byte ('\n'))
427      return -1;
428    (void) jed_down (1);
429 #if JED_HAS_LINE_ATTRIBUTES
430    CLine->flags = flags;
431 #endif
432    return 0;
433 }
434 
435 
436 /* MULTIBYTE OK */
jed_del_wchar(void)437 int jed_del_wchar (void)
438 {
439    unsigned char *p, *pmax;
440 
441    if (eolp ())
442      return jed_del_through_eol ();
443 
444    p = CLine->data + Point;
445    pmax = jed_multibyte_chars_forward (p, CLine->data + CLine->len, 1, NULL, 1);
446    return jed_generic_del_nbytes (pmax - p);
447 }
448 
jed_quick_insert(register unsigned char * s,int n)449 int jed_quick_insert(register unsigned char *s, int n) /*{{{*/
450 {
451    register unsigned char *p, *p1;
452    int nl = 0;
453 
454    if (n == 0) return 0;
455 
456    if (-1 == jed_prepare_for_modification (0))
457      return -1;
458 
459 #if JED_HAS_LINE_ATTRIBUTES
460    if ((CLine->flags & JED_LINE_IS_READONLY)
461        && ((Point != 0) || (s[n-1] != '\n')))
462      {
463 	jed_verror (Line_Read_Only_Error);
464 	return -1;
465      }
466 #endif
467 
468    if ((*(s + (n - 1)) == '\n') && (CBuf != MiniBuffer))
469      {
470 	n--;
471 	nl = 1;
472 
473 	if (-1 == jed_insert_newline ())
474 	  return -1;
475 	(void) jed_up(1);
476      }
477 
478 #ifdef KEEP_SPACE_INFO
479    if (CLine->space <= CLine->len + n + 1) remake_line(CLine->space + n + 8);
480 #else
481    if (n) remake_line (CLine->len + n);
482 #endif
483 
484    if (n)
485      {
486 	/* shove n chars over to make space */
487 	p = CLine->data + Point;
488 	if (Point < CLine->len)   /* could be equal for last line of buffer */
489 	  {
490 	     p1 = CLine->data + CLine->len - 1;
491 	     while(p1 >= p)
492 	       {
493 		  *(p1 + n) = *p1;
494 		  p1--;
495 	       }
496 	  }
497 	CLine->len += n;
498 	SLMEMCPY((char *) p, (char *) s, n);
499 
500 	jed_update_marks(CINSERT, n);
501 	record_insertion(n);
502 	Point += n;
503      }
504 
505    if (nl)
506      jed_down (1);
507 
508    return 0;
509 }
510 
511 /*}}}*/
512 
jed_insert_nbytes(unsigned char * ss,int n)513 int jed_insert_nbytes (unsigned char *ss, int n) /*{{{*/
514 {
515    register unsigned char nl, *pmax;
516    register unsigned char *p, *p1, *s = ss;
517    int n1;
518 
519    if (CBuf == MiniBuffer) nl = 0; else nl = '\n';
520 
521    p1 = s;
522    while (1)
523      {
524 	p = p1;
525 	/* count the number until a new line is reached */
526 	pmax = p1 + n;
527 	while((p1 < pmax) && (*p1 != nl)) p1++;
528 
529 	n1 = (int) (p1 - p);
530 	if (p1 != pmax) n1++;
531 	if (-1 == jed_quick_insert(p, n1))
532 	  return -1;
533 	if (p1++ == pmax) return 0;
534 	n -= n1;
535      }
536 }
537 
538 /*}}}*/
539 
540 /* Multibyte-safe */
jed_insert_wchar_n_times(SLwchar_Type c,unsigned int n)541 int jed_insert_wchar_n_times (SLwchar_Type c, unsigned int n) /*{{{*/
542 {
543    unsigned char wchar_buf [JED_MAX_MULTIBYTE_SIZE];
544    unsigned char buf[20*JED_MAX_MULTIBYTE_SIZE];
545    unsigned char *pmax;
546    unsigned int len;
547 
548    if (n == 0)
549      return 0;
550 
551    if (NULL == (pmax = jed_wchar_to_multibyte (c, wchar_buf)))
552      return -1;
553 
554    len = pmax - wchar_buf;
555    pmax = buf + (sizeof (buf) - len);
556 
557    while (n)
558      {
559 	unsigned char *p = buf;
560 
561 	while ((p < pmax) && n)
562 	  {
563 	     memcpy (p, wchar_buf, len);
564 	     n--;
565 	     p += len;
566 	  }
567 	if (-1 == jed_insert_nbytes (buf, p - buf))
568 	  return -1;
569      }
570    return 0;
571 }
572 
573 /*}}}*/
574 
insert_buffer(Buffer * b)575 void insert_buffer(Buffer *b) /*{{{*/
576 {
577    Buffer *cb;
578 
579    if ((cb = CBuf) == b) return;
580 
581    switch_to_buffer(b);
582    push_spot();
583    bob(); jed_push_mark();
584    eob();
585    copy_region_to_buffer(cb);
586    pop_spot();
587    switch_to_buffer(cb);
588 
589    touch_window();
590 }
591 
592 /*}}}*/
593 
594 /* Multibyte safe */
_jed_replace_wchar(SLwchar_Type ch)595 int _jed_replace_wchar (SLwchar_Type ch) /*{{{*/
596 {
597    unsigned char buf[JED_MAX_MULTIBYTE_SIZE];
598    unsigned char *b, *bmax;
599    unsigned char *p, *pmax;
600 
601    if (ch == '\n') return -1;
602 
603    b = buf;
604    bmax = jed_wchar_to_multibyte (ch, buf);
605    if (bmax == NULL)
606      return -1;
607 
608    p = CLine->data + Point;
609    pmax = CLine->data + CLine->len;
610 
611    while ((p < pmax) && (b < bmax) && (*b == *p))
612      {
613 	b++;
614 	p++;
615      }
616    if (b == bmax)
617      return 0;
618 
619    if (-1 == jed_insert_nbytes (buf, bmax - buf))
620      return -1;
621 
622    if (-1 == jed_del_wchar ())
623      return -1;
624 
625    (void) jed_left(1);
626    return 0;
627 }
628 
629 /*}}}*/
630 
jed_insert_string(SLFUTURE_CONST char * s)631 int jed_insert_string (SLFUTURE_CONST char *s)
632 {
633    return jed_insert_nbytes ((unsigned char *) s, strlen (s));
634 }
635 
jed_insert_byte(unsigned char ch)636 int jed_insert_byte (unsigned char ch)
637 {
638    return jed_insert_nbytes (&ch, 1);
639 }
640 
jed_insert_wchar(SLwchar_Type ch)641 int jed_insert_wchar (SLwchar_Type ch)
642 {
643    unsigned char buf[JED_MAX_MULTIBYTE_SIZE];
644    unsigned char *b;
645 
646    if (NULL == (b = jed_wchar_to_multibyte (ch, buf)))
647      return -1;
648 
649    return jed_insert_nbytes (buf, b-buf);
650 }
651