Small change to the gcc argument.
[eco.git] / buffer.c
blob3b819a5c6768e41019d350e2e29da8b6b9251010
1 /*
2 * Copyright (C) 2008 Diego Hernan Borghetti.
3 * Eco
4 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
10 #include "debug.h"
11 #include "term.h"
12 #include "screen.h"
13 #include "buffer.h"
14 #include "view.h"
15 #include "eco.h"
16 #include "kill.h"
17 #include "file.h"
20 E_Line *e_line_alloc(void)
22 E_Line *ln;
24 ln= (E_Line *)malloc(sizeof(E_Line));
25 ln->next= NULL;
26 ln->prev= NULL;
27 ln->flag= 0;
28 ln->size= 16;
29 ln->used= 0;
30 ln->text= (char *)malloc(16);
31 return(ln);
34 void e_line_realloc(E_Line *ln)
36 ln->size+= 16;
37 ln->text= (char *)realloc((void *)ln->text, ln->size);
40 void e_line_free(E_Line *ln)
42 free((void *)ln->text);
43 free((void *)ln);
46 void e_line_add(E_Buffer *bf, E_Line *ln)
48 ln->next= bf->line->next;
49 ln->prev= bf->line;
51 if (ln->next)
52 ln->next->prev= ln;
53 bf->line->next= ln;
54 bf->line= ln;
55 bf->nlines++;
58 void e_line_add_first(E_Buffer *bf, E_Line *ln)
60 ln->next= bf->lines;
61 ln->prev= NULL;
63 if (ln->next)
64 ln->next->prev= ln;
66 bf->lines= ln;
67 bf->first= ln; /* auto-reframe. */
68 bf->nlines++;
71 void e_line_remove(E_Buffer *bf, E_Line *ln)
73 if (ln->next)
74 ln->next->prev= ln->prev;
75 if (ln->prev)
76 ln->prev->next= ln->next;
78 if (bf->lines == ln)
79 bf->lines= ln->next;
81 if (bf->first == ln) {
82 if (bf->first->prev)
83 bf->first= bf->first->prev;
84 else
85 bf->first= bf->first->next;
88 if (bf->line == ln) {
89 if (bf->line->next)
90 bf->line= bf->line->next;
91 else
92 bf->line= bf->line->prev;
95 ln->next= NULL;
96 ln->prev= NULL;
97 bf->nlines--;
100 E_Buffer *e_buffer_new(char *file)
102 E_Buffer *bf;
104 bf= (E_Buffer *)malloc(sizeof(E_Buffer));
105 bf->next= NULL;
106 bf->paths= e_file_get_paths(file);
108 if (!bf->paths) {
109 free((void *)bf);
110 return(NULL);
113 if (!bf->paths->path) {
114 free((void *)bf->paths);
115 free((void *)bf);
116 return(NULL);
119 if (!bf->paths->file) {
120 free((void *)bf->paths->path);
121 free((void *)bf->paths);
122 return(NULL);
125 /* remove the full path, only show the name. */
126 bf->name= strrchr(bf->paths->file, '/');
127 if (!bf->name)
128 bf->name= bf->paths->file;
129 else
130 bf->name++;
132 e_debug_printf("path: %s\n", bf->paths->path);
133 e_debug_printf("file: %s\n", bf->paths->file);
134 e_debug_printf("name: %s\n", bf->name);
136 bf->lines= e_line_alloc();
137 bf->first= bf->lines;
138 bf->line= bf->lines;
139 bf->dot= 0;
140 bf->dot_pad= 0;
141 bf->flag= 0;
142 bf->nlines= 1;
143 bf->nl= 1;
144 return(bf);
147 void e_buffer_free(E_Buffer *bf)
149 E_Line *p;
151 /* only remove the lock when we free the buffer. */
152 e_file_lock_rem(bf->paths);
154 free((void *)bf->paths->path);
155 free((void *)bf->paths->file);
156 free((void *)bf->paths->lock_file);
157 free((void *)bf->paths);
159 while (bf->lines) {
160 p= bf->lines->next;
161 e_line_free(bf->lines);
162 bf->lines= p;
164 free((void *)bf);
167 void e_buffer_recalc(E_Buffer *bf)
169 E_Line *p;
171 bf->nl= 1;
172 p= bf->lines;
173 while (p) {
174 if (p == bf->line)
175 break;
176 bf->nl++;
177 p= p->next;
181 /* Add a new line at the current position in the buffer. */
182 void e_buffer_newline(E_Buffer *bf)
184 E_Line *ln;
186 BUFFER_SET(bf, BUFFER_FLUSH);
188 ln= e_line_alloc();
189 e_line_add(bf, ln);
191 /* Always clean the current position, the new line don't
192 * have any text..
194 bf->dot= 0;
195 bf->nl++;
198 /* Add a new line at the begin of the buffer. */
199 void e_buffer_newline_first(E_Buffer *bf)
201 E_Line *ln;
203 BUFFER_SET(bf, BUFFER_FLUSH);
205 ln= e_line_alloc();
206 e_line_add_first(bf, ln);
207 bf->dot= 0;
208 bf->nl++;
211 /* Split the current line in two line, the starting
212 * point for split is the current cursor position.
214 void e_buffer_splitline(E_Buffer *bf)
216 E_Line *ln;
217 int i, dot;
219 /* save the current line. */
220 ln= bf->line;
222 /* and the cursor position. */
223 dot= bf->dot;
225 /* insert a new line and add all the character
226 * from the current position, to the end.
228 e_buffer_newline(bf);
229 for (i= dot; i < ln->used; i++)
230 e_buffer_insert(bf, ln->text[i]);
232 ln->used= dot;
234 /* Always go to the begin of the line. */
235 bf->dot= 0;
238 /* Join two line, the source line is the current line and
239 * the dest line is the prev.
241 void e_buffer_joinline(E_Buffer *bf)
243 E_Line *ln;
244 int i, dot;
246 /* if we are at the begin, return. */
247 if (!bf->line->prev)
248 return;
250 /* save the current line. */
251 ln= bf->line;
253 /* move to the previous. */
254 e_buffer_up(bf);
256 /* put the cursor to the end of the line. */
257 bf->dot= bf->line->used;
259 /* and save the position. */
260 dot= bf->dot;
262 /* insert all the characters. */
263 for (i= 0; i < ln->used; i++)
264 e_buffer_insert(bf, ln->text[i]);
266 /* remove the unused line. */
267 e_line_remove(bf, ln);
268 e_line_free(ln);
270 /* restore the original cursor position. */
271 bf->dot= dot;
272 e_buffer_recalc(bf);
275 /* Remove the current line from the buffer, this also
276 * can save the line in the cut-buffer.
278 * If 'cut' is equal to two, only copy the line to the
279 * cut-buffer.
281 void e_buffer_killline(E_Buffer *bf, int cut)
283 E_Line *ln;
285 if (cut) {
286 e_kill_cut(bf->line);
287 if (cut == 2) {
288 if (bf->line->used)
289 e_kill_cut(NULL);
290 return;
294 if ((!bf->line->prev) && (!bf->line->next)) {
295 /* If we don't have previous or next line,
296 * the only thing to do is clean the
297 * current line.
299 e_buffer_cleanline(bf);
300 return;
302 else if (!bf->line->next) {
303 /* If we don't have next line, only clean. */
304 e_buffer_cleanline(bf);
305 return;
308 if (bf->line->used) {
309 /* This work like emacs, if the line have text
310 * first clean the text.
312 e_buffer_cleanline(bf);
313 return;
316 /* And if the line don't have text, remove it. */
317 BUFFER_SET(bf, BUFFER_FLUSH);
319 ln= bf->line;
320 e_buffer_down(bf);
321 e_line_remove(bf, ln);
322 e_line_free(ln);
323 e_buffer_recalc(bf);
326 /* Insert a character in the current line at the current
327 * cursor position.
329 void e_buffer_insert(E_Buffer *bf, int c)
331 int i;
333 BUFFER_SET(bf, BUFFER_FLUSH);
335 /* check if we need reallocate the line. */
336 if ((bf->line->used+1) >= bf->line->size)
337 e_line_realloc(bf->line);
339 /* if the cursor is not at the end of the line,
340 * we need scroll the text to the right.
342 if (bf->dot != bf->line->used) {
343 for (i= bf->line->used; i > bf->dot; i--)
344 bf->line->text[i]= bf->line->text[i-1];
347 /* insert the new character. */
348 bf->line->text[bf->dot]= c;
349 bf->dot++;
350 bf->line->used++;
353 /* Just that, insert a backspace ;) */
354 void e_buffer_backspace(E_Buffer *bf)
356 int i;
358 /* The only case that we have here is if the cursor position
359 * is at the begin of the line, in that case we need join
360 * the two lines.
362 if (bf->dot > 0) {
363 BUFFER_SET(bf, BUFFER_FLUSH);
365 /* If the cursor is not at the end of the line,
366 * we need scroll the text.
368 for (i= bf->dot; i < bf->line->used; i++)
369 bf->line->text[i-1]= bf->line->text[i];
370 bf->dot--;
371 bf->line->used--;
373 else
374 e_buffer_joinline(bf);
377 void e_buffer_del(E_Buffer *bf)
379 if (bf->dot+1 < bf->line->used) {
380 bf->dot++;
381 e_buffer_backspace(bf);
385 void e_buffer_up(E_Buffer *bf)
387 if (bf->line->prev) {
388 bf->line= bf->line->prev;
389 if (bf->dot > bf->line->used)
390 bf->dot= bf->line->used;
391 bf->nl--;
392 BUFFER_SET(bf, BUFFER_UP);
396 void e_buffer_down(E_Buffer *bf)
398 if (bf->line->next) {
399 bf->line= bf->line->next;
400 if (bf->dot > bf->line->used)
401 bf->dot= bf->line->used;
402 bf->nl++;
403 BUFFER_SET(bf, BUFFER_DOWN);
407 void e_buffer_left(E_Buffer *bf)
409 if (bf->dot > 0)
410 bf->dot--;
411 else {
412 e_buffer_up(bf);
413 e_buffer_eol(bf);
417 void e_buffer_right(E_Buffer *bf)
419 if (bf->dot < bf->line->used)
420 bf->dot++;
421 else {
422 e_buffer_down(bf);
423 e_buffer_bol(bf);
427 void e_buffer_goto_begin(E_Buffer *bf)
429 bf->line= bf->lines;
430 bf->dot= 0;
431 bf->nl= 1;
434 void e_buffer_goto_end(E_Buffer *bf)
436 E_Line *p;
438 p= bf->line;
439 while (p->next)
440 p= p->next;
442 bf->line= p;
443 bf->dot= 0;
444 bf->nl= bf->nlines+1; /* zero */
447 void e_buffer_bol(E_Buffer *bf)
449 bf->dot= 0;
452 void e_buffer_eol(E_Buffer *bf)
454 bf->dot= bf->line->used;
457 void e_buffer_scroll(E_Buffer *bf, int nline, int dir)
459 int i;
461 for(i= 0; i < nline; i++) {
462 if (dir) {
463 if (!bf->first->prev)
464 break;
465 bf->first= bf->first->prev;
467 else {
468 if (!bf->first->next)
469 break;
470 bf->first= bf->first->next;
473 bf->line= bf->first;
474 if (bf->dot > bf->line->used)
475 bf->dot= bf->line->used;
476 e_buffer_recalc(bf);
479 void e_buffer_goto(E_Buffer *bf, int line)
481 E_Line *p;
482 int num;
484 num= 1;
485 p= bf->lines;
486 while (p) {
487 if (num == line)
488 break;
489 num++;
490 p= p->next;
493 if (!p)
494 return;
496 bf->nl= num;
497 bf->line= p;
498 if (bf->dot > bf->line->used)
499 bf->dot= 0;
502 void e_buffer_cleanline(E_Buffer *bf)
504 BUFFER_SET(bf, BUFFER_FLUSH);
506 bf->line->used= 0;
507 bf->dot= 0;
510 E_Line *__e_buffer_search(E_Buffer *bf, char *pattern, int *dot_found, int dir)
512 E_Line *ln;
513 int i, e, a, len, dot, found;
515 len= strlen(pattern);
516 found= 0;
517 dot= 0;
519 /* I know.. this is not the best backward.. but work. */
520 if (dir == BUFFER_SEARCH_FORWARD)
521 ln= bf->line;
522 else
523 ln= bf->line->prev;
525 while (ln) {
526 if (dir == BUFFER_SEARCH_FORWARD && ln == bf->line)
527 i= bf->dot;
528 else
529 i= 0;
531 for (; i < ln->used; i++) {
532 if (ln->text[i] == pattern[0]) {
533 /* save the current position of the cursor. */
534 a= i;
535 dot= i;
536 found= 1;
538 for (e= 0; e < len; e++) {
539 if (ln->text[i] != pattern[e]) {
540 found= 0;
541 break;
544 i++;
545 if (i > ln->used) {
546 found= 0;
547 break;
551 i= a;
554 if (found)
555 break;
558 if (found)
559 break;
561 if (dir == BUFFER_SEARCH_FORWARD)
562 ln= ln->next;
563 else
564 ln= ln->prev;
567 if (dir == BUFFER_SEARCH_FORWARD)
568 *dot_found= (dot+len);
569 else
570 *dot_found= dot;
572 return(ln);
575 void e_buffer_search(E_Buffer *bf, char *pattern, int dir)
577 E_Line *ln;
578 int dot;
580 ln= __e_buffer_search(bf, pattern, &dot, dir);
581 if (ln) {
582 bf->first= ln;
583 bf->line= ln;
584 bf->dot= dot;
585 e_buffer_recalc(bf);
589 int e_buffer_replace(E_Buffer *bf, char *pattern, char *replace)
591 E_Line *ln;
592 int i, c, len, ncount, dot;
594 c= strlen(pattern);
595 len= strlen(replace);
596 ncount= 0;
598 ln= __e_buffer_search(bf, pattern, &dot, BUFFER_SEARCH_FORWARD);
599 while (ln) {
600 /* first set the line, so all the next call
601 * work fine.
603 bf->first= ln;
604 bf->line= ln;
605 bf->dot= dot;
606 e_buffer_recalc(bf);
608 /* now remove the pattern. */
609 for (i= 0; i < c; i++)
610 e_buffer_backspace(bf);
612 /* and now insert the new string. */
613 for (i= 0; i < len; i++)
614 e_buffer_insert(bf, replace[i]);
616 ncount++;
617 ln= __e_buffer_search(bf, pattern, &dot, BUFFER_SEARCH_FORWARD);
619 return(ncount);