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