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