Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/text.c')
-rw-r--r--source/blender/blenkernel/intern/text.c1986
1 files changed, 1986 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
new file mode 100644
index 00000000000..7f1c6f4935b
--- /dev/null
+++ b/source/blender/blenkernel/intern/text.c
@@ -0,0 +1,1986 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <ctype.h> /* isprint() */
+#include <string.h> /* strstr */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "DNA_text_types.h"
+
+#include "BKE_bad_level_calls.h"
+#include "BKE_utildefines.h"
+#include "BKE_text.h"
+#include "BKE_library.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BPY_extern.h" // Blender Python library
+
+/***************/ /*
+
+How Texts should work
+--
+A text should relate to a file as follows -
+(Text *)->name should be the place where the
+ file will or has been saved.
+
+(Text *)->flags has the following bits
+ TXT_ISDIRTY - should always be set if the file in mem. differs from
+ the file on disk, or if there is no file on disk.
+ TXT_ISTMP - should always be set if the (Text *)->name file has not
+ been written before, and attempts to save should result
+ in "Save over?"
+ TXT_ISMEM - should always be set if the Text has not been mapped to
+ a file, in which case (Text *)->name may be NULL or garbage.
+ TXT_ISEXT - should always be set if the Text is not to be written into
+ the .blend
+ TXT_ISSCRIPT - should be set if the user has designated the text
+ as a script.
+
+->>> see also: /makesdna/DNA_text_types.h
+
+Display
+--
+The st->top determines at what line the top of the text is displayed.
+If the user moves the cursor the st containing that cursor should
+be popped ... other st's retain their own top location.
+
+*/ /***************/
+
+
+/****************/ /*
+ Undo
+
+Undo/Redo works by storing
+events in a queue, and a pointer
+to the current position in the
+queue...
+
+Events are stored using an
+arbitrary op-code system
+to keep track of
+a) the two cursors (normal and selected)
+b) input (visible and control (ie backspace))
+
+input data is stored as its
+ASCII value, the opcodes are
+then selected to not conflict.
+
+opcodes with data in between are
+written at the beginning and end
+of the data to allow undo and redo
+to simply check the code at the current
+undo position
+
+*/ /***************/
+
+/***/
+
+static void txt_pop_first(Text *text);
+static void txt_pop_last(Text *text);
+static void txt_undo_add_op(Text *text, int op);
+static void txt_undo_add_block(Text *text, int op, char *buf);
+static void txt_delete_line(Text *text, TextLine *line);
+
+/***/
+
+static char *txt_cut_buffer= NULL;
+static unsigned char undoing;
+
+/* allow to switch off undoing externally */
+void txt_set_undostate(int u)
+{
+ undoing = u;
+}
+
+int txt_get_undostate(void)
+{
+ return undoing;
+}
+
+void free_text(Text *text)
+{
+ TextLine *tmp;
+
+ for (tmp= text->lines.first; tmp; tmp= tmp->next)
+ MEM_freeN(tmp->line);
+
+ BLI_freelistN(&text->lines);
+
+ if(text->name) MEM_freeN(text->name);
+ MEM_freeN(text->undo_buf);
+}
+
+Text *add_empty_text(void)
+{
+ Text *ta;
+ TextLine *tmp;
+
+ ta= alloc_libblock(&G.main->text, ID_TXT, "Text");
+ ta->id.us= 1;
+
+ ta->name= NULL;
+
+ ta->undo_pos= -1;
+ ta->undo_len= TXT_INIT_UNDO;
+ ta->undo_buf= MEM_mallocN(ta->undo_len, "undo buf");
+
+ ta->nlines=1;
+ ta->flags= TXT_ISDIRTY | TXT_ISTMP | TXT_ISMEM;
+
+ ta->lines.first= ta->lines.last= NULL;
+
+ tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line= (char*) MEM_mallocN(1, "textline_string");
+
+ tmp->line[0]=0;
+ tmp->len= 0;
+
+ tmp->next= NULL;
+ tmp->prev= NULL;
+
+ BLI_addhead(&ta->lines, tmp);
+
+ ta->curl= ta->lines.first;
+ ta->curc= 0;
+ ta->sell= ta->lines.first;
+ ta->selc= 0;
+
+ return ta;
+}
+
+// this function removes any control characters from
+// a textline
+
+static void cleanup_textline(TextLine * tl)
+{
+ int i;
+
+ for (i = 0; i < tl->len; i++ ) {
+ if (tl->line[i] < ' ' && tl->line[i] != '\t') {
+ memmove(tl->line + i, tl->line + i + 1, tl->len - i);
+ tl->len--;
+ i--;
+ }
+ }
+}
+
+int reopen_text(Text *text)
+{
+ FILE *fp;
+ int i, llen, len;
+ unsigned char *buffer;
+ TextLine *tmp;
+ char sdir[FILE_MAXDIR];
+ char sfile[FILE_MAXFILE];
+
+ if (!text || !text->name) return 0;
+
+ BLI_split_dirfile(text->name, sdir, sfile);
+
+ fp= fopen(text->name, "r");
+ if(fp==NULL) return 0;
+
+ /* free memory: */
+
+ for (tmp= text->lines.first; tmp; tmp= tmp->next)
+ MEM_freeN(tmp->line);
+
+ BLI_freelistN(&text->lines);
+
+ text->lines.first= text->lines.last= NULL;
+ text->curl= text->sell= NULL;
+
+ /* clear undo buffer */
+ MEM_freeN(text->undo_buf);
+ text->undo_pos= -1;
+ text->undo_len= TXT_INIT_UNDO;
+ text->undo_buf= MEM_mallocN(text->undo_len, "undo buf");
+
+ text->flags= TXT_ISDIRTY | TXT_ISTMP;
+
+ fseek(fp, 0L, SEEK_END);
+ len= ftell(fp);
+ fseek(fp, 0L, SEEK_SET);
+
+ text->undo_pos= -1;
+
+ buffer= MEM_mallocN(len, "text_buffer");
+ // under windows fread can return less then len bytes because
+ // of CR stripping
+ len = fread(buffer, 1, len, fp);
+
+ fclose(fp);
+
+ text->nlines=0;
+ i=0;
+ llen=0;
+ for(i=0; i<len; i++) {
+ if (buffer[i]=='\n') {
+ tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
+
+ if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
+ tmp->line[llen]=0;
+ tmp->len= llen;
+
+ cleanup_textline(tmp);
+
+ BLI_addtail(&text->lines, tmp);
+ text->nlines++;
+
+ llen=0;
+ continue;
+ }
+ llen++;
+ }
+
+ if (llen!=0 || text->nlines==0) {
+ tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
+
+ if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
+
+ tmp->line[llen]=0;
+ tmp->len= llen;
+
+ cleanup_textline(tmp);
+
+ BLI_addtail(&text->lines, tmp);
+ text->nlines++;
+ }
+
+ text->curl= text->sell= text->lines.first;
+ text->curc= text->selc= 0;
+
+ MEM_freeN(buffer);
+ return 1;
+}
+
+Text *add_text(char *file)
+{
+ FILE *fp;
+ int i, llen, len;
+ unsigned char *buffer;
+ TextLine *tmp;
+ Text *ta;
+ char sdir[FILE_MAXDIR];
+ char sfile[FILE_MAXFILE];
+
+ BLI_split_dirfile(file, sdir, sfile);
+
+ fp= fopen(file, "r");
+ if(fp==NULL) return NULL;
+
+ ta= alloc_libblock(&G.main->text, ID_TXT, sfile);
+ ta->id.us= 1;
+
+ ta->lines.first= ta->lines.last= NULL;
+ ta->curl= ta->sell= NULL;
+
+/* ta->flags= TXT_ISTMP | TXT_ISEXT; */
+ ta->flags= TXT_ISTMP;
+
+ fseek(fp, 0L, SEEK_END);
+ len= ftell(fp);
+ fseek(fp, 0L, SEEK_SET);
+
+ ta->name= MEM_mallocN(strlen(file)+1, "text_name");
+ strcpy(ta->name, file);
+
+ ta->undo_pos= -1;
+ ta->undo_len= TXT_INIT_UNDO;
+ ta->undo_buf= MEM_mallocN(ta->undo_len, "undo buf");
+
+ buffer= MEM_mallocN(len, "text_buffer");
+ // under windows fread can return less then len bytes because
+ // of CR stripping
+ len = fread(buffer, 1, len, fp);
+
+ fclose(fp);
+
+ ta->nlines=0;
+ i=0;
+ llen=0;
+ for(i=0; i<len; i++) {
+ if (buffer[i]=='\n') {
+ tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
+
+ if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
+ tmp->line[llen]=0;
+ tmp->len= llen;
+
+ cleanup_textline(tmp);
+
+ BLI_addtail(&ta->lines, tmp);
+ ta->nlines++;
+
+ llen=0;
+ continue;
+ }
+ llen++;
+ }
+
+ if (llen!=0 || ta->nlines==0) {
+ tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
+
+ if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
+
+ tmp->line[llen]=0;
+ tmp->len= llen;
+
+ cleanup_textline(tmp);
+
+ BLI_addtail(&ta->lines, tmp);
+ ta->nlines++;
+ }
+
+ ta->curl= ta->sell= ta->lines.first;
+ ta->curc= ta->selc= 0;
+
+ MEM_freeN(buffer);
+
+ return ta;
+}
+
+Text *copy_text(Text *ta)
+{
+ Text *tan;
+ TextLine *line, *tmp;
+
+ tan= copy_libblock(ta);
+
+ tan->name= MEM_mallocN(strlen(ta->name)+1, "text_name");
+ strcpy(tan->name, ta->name);
+
+ tan->flags = ta->flags | TXT_ISDIRTY | TXT_ISTMP;
+
+ tan->lines.first= tan->lines.last= NULL;
+ tan->curl= tan->sell= NULL;
+
+ tan->nlines= ta->nlines;
+
+ line= ta->lines.first;
+ /* Walk down, reconstructing */
+ while (line) {
+ tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line= MEM_mallocN(line->len+1, "textline_string");
+ strcpy(tmp->line, line->line);
+
+ tmp->len= line->len;
+
+ BLI_addtail(&tan->lines, tmp);
+
+ line= line->next;
+ }
+
+ tan->curl= tan->sell= tan->lines.first;
+ tan->curc= tan->selc= 0;
+
+ return tan;
+}
+
+/*****************************/
+/* Editing utility functions */
+/*****************************/
+
+static void make_new_line (TextLine *line, char *newline)
+{
+ MEM_freeN(line->line);
+
+ line->line= newline;
+ line->len= strlen(newline);
+}
+
+static TextLine *txt_new_line(char *str)
+{
+ TextLine *tmp;
+
+ if(!str) str= "";
+
+ tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line= MEM_mallocN(strlen(str)+1, "textline_string");
+ strcpy(tmp->line, str);
+
+ tmp->len= strlen(str);
+ tmp->next= tmp->prev= NULL;
+
+ return tmp;
+}
+
+static TextLine *txt_new_linen(char *str, int n)
+{
+ TextLine *tmp;
+
+ if(!str) str= "";
+
+ tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line= MEM_mallocN(n+1, "textline_string");
+ BLI_strncpy(tmp->line, str, n+1);
+
+ tmp->len= strlen(tmp->line);
+ tmp->next= tmp->prev= NULL;
+
+ return tmp;
+}
+
+void txt_clean_text (Text *text)
+{
+ TextLine **top, **bot;
+
+ if (!text) return;
+
+ if (!text->lines.first) {
+ if (text->lines.last) text->lines.first= text->lines.last;
+ else text->lines.first= text->lines.last= txt_new_line(NULL);
+ }
+
+ if (!text->lines.last) text->lines.last= text->lines.first;
+
+ top= (TextLine **) &text->lines.first;
+ bot= (TextLine **) &text->lines.last;
+
+ while ((*top)->prev) *top= (*top)->prev;
+ while ((*bot)->next) *bot= (*bot)->next;
+
+ if(!text->curl) {
+ if(text->sell) text->curl= text->sell;
+ else text->curl= text->lines.first;
+ text->curc= 0;
+ }
+
+ if(!text->sell) {
+ text->sell= text->curl;
+ text->selc= 0;
+ }
+}
+
+int txt_get_span (TextLine *from, TextLine *to)
+{
+ int ret=0;
+ TextLine *tmp= from;
+
+ if (!to || !from) return 0;
+ if (from==to) return 0;
+
+ /* Look forwards */
+ while (tmp) {
+ if (tmp == to) return ret;
+ ret++;
+ tmp= tmp->next;
+ }
+
+ /* Look backwards */
+ if (!tmp) {
+ tmp= from;
+ ret=0;
+ while(tmp) {
+ if (tmp == to) break;
+ ret--;
+ tmp= tmp->prev;
+ }
+ if(!tmp) ret=0;
+ }
+
+ return ret;
+}
+
+static int txt_illegal_char (char c)
+{
+ if (isprint(c) || c=='\t') return 0;
+
+ return 1;
+}
+
+static void txt_make_dirty (Text *text)
+{
+ text->flags |= TXT_ISDIRTY;
+ if (text->compiled) BPY_free_compiled_text(text);
+}
+
+/****************************/
+/* Cursor utility functions */
+/****************************/
+
+static void txt_curs_cur (Text *text, TextLine ***linep, int **charp)
+{
+ *linep= &text->curl; *charp= &text->curc;
+}
+
+static void txt_curs_sel (Text *text, TextLine ***linep, int **charp)
+{
+ *linep= &text->sell; *charp= &text->selc;
+}
+
+static void txt_curs_first (Text *text, TextLine **linep, int *charp)
+{
+ if (text->curl==text->sell) {
+ *linep= text->curl;
+ if (text->curc<text->selc) *charp= text->curc;
+ else *charp= text->selc;
+ } else if (txt_get_span(text->lines.first, text->curl)<txt_get_span(text->lines.first, text->sell)) {
+ *linep= text->curl;
+ *charp= text->curc;
+ } else {
+ *linep= text->sell;
+ *charp= text->selc;
+ }
+}
+
+/****************************/
+/* Cursor movement functions */
+/****************************/
+
+void txt_move_up(Text *text, short sel)
+{
+ TextLine **linep;
+ int *charp, old;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
+ if (!*linep) return;
+ old= *charp;
+
+ if((*linep)->prev) {
+ *linep= (*linep)->prev;
+ if (*charp > (*linep)->len) {
+ *charp= (*linep)->len;
+ if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, (*linep)->next), old, txt_get_span(text->lines.first, *linep), (unsigned short) *charp);
+ } else {
+ if(!undoing) txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP);
+ }
+ } else {
+ *charp= 0;
+ if(!undoing) txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP);
+ }
+
+ if(!sel) txt_pop_sel(text);
+}
+
+void txt_move_down(Text *text, short sel)
+{
+ TextLine **linep;
+ int *charp, old;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
+ if (!*linep) return;
+ old= *charp;
+
+ if((*linep)->next) {
+ *linep= (*linep)->next;
+ if (*charp > (*linep)->len) {
+ *charp= (*linep)->len;
+ if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, (*linep)->prev), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
+ } else
+ if(!undoing) txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN);
+ } else {
+ *charp= (*linep)->len;
+ if(!undoing) txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN);
+ }
+
+ if(!sel) txt_pop_sel(text);
+}
+
+void txt_move_left(Text *text, short sel)
+{
+ TextLine **linep;
+ int *charp, oundoing= undoing;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
+ if (!*linep) return;
+
+ undoing= 1;
+ if (*charp== 0) {
+ if ((*linep)->prev) {
+ txt_move_up(text, sel);
+ *charp= (*linep)->len;
+ }
+ } else {
+ (*charp)--;
+ }
+ undoing= oundoing;
+ if(!undoing) txt_undo_add_op(text, sel?UNDO_SLEFT:UNDO_CLEFT);
+
+ if(!sel) txt_pop_sel(text);
+}
+
+void txt_move_right(Text *text, short sel)
+{
+ TextLine **linep;
+ int *charp, oundoing= undoing;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
+ if (!*linep) return;
+
+ undoing= 1;
+ if (*charp== (*linep)->len) {
+ if ((*linep)->next) {
+ txt_move_down(text, sel);
+ *charp= 0;
+ }
+ } else {
+ (*charp)++;
+ }
+ undoing= oundoing;
+ if(!undoing) txt_undo_add_op(text, sel?UNDO_SRIGHT:UNDO_CRIGHT);
+
+ if(!sel) txt_pop_sel(text);
+}
+
+void txt_move_bol (Text *text, short sel)
+{
+ TextLine **linep;
+ int *charp, old;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else txt_curs_cur(text, &linep, &charp);
+ if (!*linep) return;
+ old= *charp;
+
+ *charp= 0;
+
+ if(!sel) txt_pop_sel(text);
+ if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
+}
+
+void txt_move_eol (Text *text, short sel)
+{
+ TextLine **linep;
+ int *charp, old;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else txt_curs_cur(text, &linep, &charp);
+ if (!*linep) return;
+ old= *charp;
+
+ *charp= (*linep)->len;
+
+ if(!sel) txt_pop_sel(text);
+ if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
+}
+
+void txt_move_bof (Text *text, short sel)
+{
+ TextLine **linep;
+ int *charp, old;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else txt_curs_cur(text, &linep, &charp);
+ if (!*linep) return;
+ old= *charp;
+
+ *linep= text->lines.first;
+ *charp= 0;
+
+ if(!sel) txt_pop_sel(text);
+ if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
+}
+
+void txt_move_eof (Text *text, short sel)
+{
+ TextLine **linep;
+ int *charp, old;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else txt_curs_cur(text, &linep, &charp);
+ if (!*linep) return;
+ old= *charp;
+
+ *linep= text->lines.last;
+ *charp= (*linep)->len;
+
+ if(!sel) txt_pop_sel(text);
+ if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
+}
+
+void txt_move_toline (Text *text, unsigned int line, short sel)
+{
+ TextLine **linep, *oldl;
+ int *charp, oldc;
+ unsigned int i;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else txt_curs_cur(text, &linep, &charp);
+ if (!*linep) return;
+ oldc= *charp;
+ oldl= *linep;
+
+ *linep= text->lines.first;
+ for (i=0; i<line; i++) {
+ if ((*linep)->next) *linep= (*linep)->next;
+ else break;
+ }
+ *charp= 0;
+
+ if(!sel) txt_pop_sel(text);
+ if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, oldl), oldc, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
+}
+
+/****************************/
+/* Text selection functions */
+/****************************/
+
+static void txt_curs_swap (Text *text)
+{
+ TextLine *tmpl;
+ int tmpc;
+
+ tmpl= text->curl;
+ text->curl= text->sell;
+ text->sell= tmpl;
+
+ tmpc= text->curc;
+ text->curc= text->selc;
+ text->selc= tmpc;
+
+ if(!undoing) txt_undo_add_op(text, UNDO_SWAP);
+}
+
+static void txt_pop_first (Text *text)
+{
+
+ if (txt_get_span(text->curl, text->sell)<0 ||
+ (text->curl==text->sell && text->curc>text->selc)) {
+ txt_curs_swap(text);
+ }
+
+ if(!undoing) txt_undo_add_toop(text, UNDO_STO,
+ txt_get_span(text->lines.first, text->sell),
+ text->selc,
+ txt_get_span(text->lines.first, text->curl),
+ text->curc);
+
+ txt_pop_sel(text);
+}
+
+static void txt_pop_last (Text *text)
+{
+ if (txt_get_span(text->curl, text->sell)>0 ||
+ (text->curl==text->sell && text->curc<text->selc)) {
+ txt_curs_swap(text);
+ }
+
+ if(!undoing) txt_undo_add_toop(text, UNDO_STO,
+ txt_get_span(text->lines.first, text->sell),
+ text->selc,
+ txt_get_span(text->lines.first, text->curl),
+ text->curc);
+
+ txt_pop_sel(text);
+}
+
+/* never used: CVS 1.19 */
+/* static void txt_pop_selr (Text *text) */
+
+void txt_pop_sel (Text *text)
+{
+ text->sell= text->curl;
+ text->selc= text->curc;
+}
+
+void txt_order_cursors(Text *text)
+{
+ if (!text) return;
+ if (!text->curl) return;
+ if (!text->sell) return;
+
+ /* Flip so text->curl is before text->sell */
+ if (txt_get_span(text->curl, text->sell)<0 ||
+ (text->curl==text->sell && text->curc>text->selc))
+ txt_curs_swap(text);
+}
+
+int txt_has_sel(Text *text)
+{
+ return ((text->curl!=text->sell) || (text->curc!=text->selc));
+}
+
+static void txt_delete_sel (Text *text)
+{
+ TextLine *tmpl;
+ char *buf;
+
+ if (!text) return;
+ if (!text->curl) return;
+ if (!text->sell) return;
+
+ if (!txt_has_sel(text)) return;
+
+ txt_order_cursors(text);
+
+ if(!undoing) {
+ buf= txt_sel_to_buf(text);
+ txt_undo_add_block(text, UNDO_DBLOCK, buf);
+ MEM_freeN(buf);
+ }
+
+ buf= MEM_mallocN(text->curc+(text->sell->len - text->selc)+1, "textline_string");
+
+ strncpy(buf, text->curl->line, text->curc);
+ strcpy(buf+text->curc, text->sell->line + text->selc);
+ buf[text->curc+(text->sell->len - text->selc)]=0;
+
+ make_new_line(text->curl, buf);
+
+ tmpl= text->sell;
+ while (tmpl != text->curl) {
+ tmpl= tmpl->prev;
+ if (!tmpl) break;
+
+ txt_delete_line(text, tmpl->next);
+ }
+
+ text->sell= text->curl;
+ text->selc= text->curc;
+}
+
+void txt_sel_all (Text *text)
+{
+ if (!text) return;
+
+ text->curl= text->lines.first;
+ text->curc= 0;
+
+ text->sell= text->lines.last;
+ text->selc= text->sell->len;
+}
+
+void txt_sel_line (Text *text)
+{
+ if (!text) return;
+ if (!text->curl) return;
+
+ text->curc= 0;
+ text->sell= text->curl;
+ text->selc= text->sell->len;
+}
+
+/***************************/
+/* Cut and paste functions */
+/***************************/
+
+void txt_print_cutbuffer (void)
+{
+ printf ("Cut buffer\n--\n%s\n--\n", txt_cut_buffer);
+}
+
+char *txt_to_buf (Text *text)
+{
+ int length;
+ TextLine *tmp, *linef, *linel;
+ int charf, charl;
+ char *buf;
+
+ if (!text) return NULL;
+ if (!text->curl) return NULL;
+ if (!text->sell) return NULL;
+
+ linef= text->lines.first;
+ charf= 0;
+
+ linel= text->lines.last;
+ charl= linel->len;
+
+ if (linef == text->lines.last) {
+ length= charl-charf;
+
+ buf= MEM_mallocN(length+2, "text buffer");
+
+ BLI_strncpy(buf, linef->line + charf, length+1);
+ buf[length]=0;
+ } else {
+ length= linef->len - charf;
+ length+= charl;
+ length+= 2; /* For the 2 '\n' */
+
+ tmp= linef->next;
+ while (tmp && tmp!= linel) {
+ length+= tmp->len+1;
+ tmp= tmp->next;
+ }
+
+ buf= MEM_mallocN(length+1, "cut buffer");
+
+ strncpy(buf, linef->line + charf, linef->len-charf);
+ length= linef->len - charf;
+
+ buf[length++]='\n';
+
+ tmp= linef->next;
+ while (tmp && tmp!=linel) {
+ strncpy(buf+length, tmp->line, tmp->len);
+ length+= tmp->len;
+
+ buf[length++]='\n';
+
+ tmp= tmp->next;
+ }
+ strncpy(buf+length, linel->line, charl);
+ length+= charl;
+
+ /* python compiler wants an empty end line */
+ buf[length++]='\n';
+ buf[length]=0;
+ }
+
+ return buf;
+}
+
+int txt_find_string(Text *text, char *findstr)
+{
+ TextLine *tl, *startl;
+ char *s= NULL;
+
+ if (!text || !text->curl || !text->sell) return 0;
+
+ txt_order_cursors(text);
+
+ tl= startl= text->sell;
+
+ s= strstr(&tl->line[text->selc], findstr);
+ while (!s) {
+ tl= tl->next;
+ if (!tl)
+ tl= text->lines.first;
+
+ s= strstr(tl->line, findstr);
+ if (tl==startl)
+ break;
+ }
+
+ if (s) {
+ text->curl= text->sell= tl;
+ text->curc= (int) (s-tl->line);
+ text->selc= text->curc + strlen(findstr);
+
+ return 1;
+ } else
+ return 0;
+}
+
+void txt_cut_sel (Text *text)
+{
+ txt_copy_sel(text);
+
+ txt_delete_sel(text);
+}
+
+char *txt_sel_to_buf (Text *text)
+{
+ char *buf;
+ int length=0;
+ TextLine *tmp, *linef, *linel;
+ int charf, charl;
+
+ if (!text) return NULL;
+ if (!text->curl) return NULL;
+ if (!text->sell) return NULL;
+
+ if (text->curl==text->sell) {
+ linef= linel= text->curl;
+
+ if (text->curc < text->selc) {
+ charf= text->curc;
+ charl= text->selc;
+ } else{
+ charf= text->selc;
+ charl= text->curc;
+ }
+ } else if (txt_get_span(text->curl, text->sell)<0) {
+ linef= text->sell;
+ linel= text->curl;
+
+ charf= text->selc;
+ charl= text->curc;
+ } else {
+ linef= text->curl;
+ linel= text->sell;
+
+ charf= text->curc;
+ charl= text->selc;
+ }
+
+ if (linef == linel) {
+ length= charl-charf;
+
+ buf= MEM_mallocN(length+1, "sel buffer");
+
+ BLI_strncpy(buf, linef->line + charf, length+1);
+ } else {
+ length+= linef->len - charf;
+ length+= charl;
+ length++; /* For the '\n' */
+
+ tmp= linef->next;
+ while (tmp && tmp!= linel) {
+ length+= tmp->len+1;
+ tmp= tmp->next;
+ }
+
+ buf= MEM_mallocN(length+1, "sel buffer");
+
+ strncpy(buf, linef->line+ charf, linef->len-charf);
+ length= linef->len-charf;
+
+ buf[length++]='\n';
+
+ tmp= linef->next;
+ while (tmp && tmp!=linel) {
+ strncpy(buf+length, tmp->line, tmp->len);
+ length+= tmp->len;
+
+ buf[length++]='\n';
+
+ tmp= tmp->next;
+ }
+ strncpy(buf+length, linel->line, charl);
+ length+= charl;
+
+ buf[length]=0;
+ }
+
+ return buf;
+}
+
+void txt_copy_sel (Text *text)
+{
+ int length=0;
+ TextLine *tmp, *linef, *linel;
+ int charf, charl;
+
+ if (!text) return;
+ if (!text->curl) return;
+ if (!text->sell) return;
+
+ if (!txt_has_sel(text)) return;
+
+ if (txt_cut_buffer) MEM_freeN(txt_cut_buffer);
+ txt_cut_buffer= NULL;
+
+ if (text->curl==text->sell) {
+ linef= linel= text->curl;
+
+ if (text->curc < text->selc) {
+ charf= text->curc;
+ charl= text->selc;
+ } else{
+ charf= text->selc;
+ charl= text->curc;
+ }
+ } else if (txt_get_span(text->curl, text->sell)<0) {
+ linef= text->sell;
+ linel= text->curl;
+
+ charf= text->selc;
+ charl= text->curc;
+ } else {
+ linef= text->curl;
+ linel= text->sell;
+
+ charf= text->curc;
+ charl= text->selc;
+ }
+
+ if (linef == linel) {
+ length= charl-charf;
+
+ txt_cut_buffer= MEM_mallocN(length+1, "cut buffera");
+
+ BLI_strncpy(txt_cut_buffer, linef->line + charf, length+1);
+ } else {
+ length+= linef->len - charf;
+ length+= charl;
+ length++; /* For the '\n' */
+
+ tmp= linef->next;
+ while (tmp && tmp!= linel) {
+ length+= tmp->len+1;
+ tmp= tmp->next;
+ }
+
+ txt_cut_buffer= MEM_mallocN(length+1, "cut bufferb");
+
+ strncpy(txt_cut_buffer, linef->line+ charf, linef->len-charf);
+ length= linef->len-charf;
+
+ txt_cut_buffer[length++]='\n';
+
+ tmp= linef->next;
+ while (tmp && tmp!=linel) {
+ strncpy(txt_cut_buffer+length, tmp->line, tmp->len);
+ length+= tmp->len;
+
+ txt_cut_buffer[length++]='\n';
+
+ tmp= tmp->next;
+ }
+ strncpy(txt_cut_buffer+length, linel->line, charl);
+ length+= charl;
+
+ txt_cut_buffer[length]=0;
+ }
+}
+
+void txt_insert_buf(Text *text, char *in_buffer)
+{
+ int i=0, l=0, j, u, len;
+ TextLine *add;
+
+ if (!text) return;
+ if (!in_buffer) return;
+
+ txt_delete_sel(text);
+
+ if(!undoing) txt_undo_add_block (text, UNDO_IBLOCK, in_buffer);
+
+ u= undoing;
+ undoing= 1;
+
+ /* Read the first line (or as close as possible */
+ while (in_buffer[i] && in_buffer[i]!='\n') {
+ txt_add_char(text, in_buffer[i]);
+ i++;
+ }
+
+ if (in_buffer[i]=='\n') txt_split_curline(text);
+ else { undoing = u; return; }
+ i++;
+
+ /* Read as many full lines as we can */
+ len= strlen(in_buffer);
+
+ while (i<len) {
+ l=0;
+
+ while (in_buffer[i] && in_buffer[i]!='\n') {
+ i++; l++;
+ }
+
+ if(in_buffer[i]=='\n') {
+ add= txt_new_linen(in_buffer +(i-l), l);
+ BLI_insertlinkbefore(&text->lines, text->curl, add);
+ i++;
+ } else {
+ for (j= i-l; j<i && j<(int)strlen(in_buffer); j++) {
+ txt_add_char(text, in_buffer[j]);
+ }
+ break;
+ }
+ }
+
+ undoing= u;
+}
+
+void txt_free_cut_buffer(void)
+{
+ if (txt_cut_buffer) MEM_freeN(txt_cut_buffer);
+}
+
+void txt_paste(Text *text)
+{
+ txt_insert_buf(text, txt_cut_buffer);
+}
+
+/******************/
+/* Undo functions */
+/******************/
+
+#define MAX_UNDO_TEST(x) \
+ while (text->undo_pos+x >= text->undo_len) { \
+ if(text->undo_len*2 > TXT_MAX_UNDO) { \
+ error("Undo limit reached, buffer cleared\n"); \
+ MEM_freeN(text->undo_buf); \
+ text->undo_len= TXT_INIT_UNDO; \
+ text->undo_buf= MEM_mallocN(text->undo_len, "undo buf"); \
+ text->undo_pos=-1; \
+ return; \
+ } else { \
+ void *tmp= text->undo_buf; \
+ text->undo_buf= MEM_callocN(text->undo_len*2, "undo buf"); \
+ memcpy(text->undo_buf, tmp, text->undo_len); \
+ text->undo_len*=2; \
+ MEM_freeN(tmp); \
+ } \
+ }
+
+static void dump_buffer(Text *text) {
+ int i= 0;
+
+ while (i++<text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]);
+}
+
+void txt_print_undo(Text *text)
+{
+ int i= 0;
+ int op;
+ char *ops;
+ int linep, charp;
+
+ dump_buffer(text);
+
+ printf ("---< Undo Buffer >---\n");
+
+ printf ("UndoPosition is %d\n", text->undo_pos);
+
+ while (i<=text->undo_pos) {
+ op= text->undo_buf[i];
+
+ if (op==UNDO_CLEFT) {
+ ops= "Cursor left";
+ } else if (op==UNDO_CRIGHT) {
+ ops= "Cursor right";
+ } else if (op==UNDO_CUP) {
+ ops= "Cursor up";
+ } else if (op==UNDO_CDOWN) {
+ ops= "Cursor down";
+ } else if (op==UNDO_SLEFT) {
+ ops= "Selection left";
+ } else if (op==UNDO_SRIGHT) {
+ ops= "Selection right";
+ } else if (op==UNDO_SUP) {
+ ops= "Selection up";
+ } else if (op==UNDO_SDOWN) {
+ ops= "Selection down";
+ } else if (op==UNDO_STO) {
+ ops= "Selection ";
+ } else if (op==UNDO_CTO) {
+ ops= "Cursor ";
+ } else if (op==UNDO_INSERT) {
+ ops= "Insert";
+ } else if (op==UNDO_BS) {
+ ops= "Backspace";
+ } else if (op==UNDO_DEL) {
+ ops= "Delete";
+ } else if (op==UNDO_SWAP) {
+ ops= "Cursor swap";
+ } else if (op==UNDO_DBLOCK) {
+ ops= "Delete text block";
+ } else if (op==UNDO_IBLOCK) {
+ ops= "Insert text block";
+ } else {
+ ops= "Unknown";
+ }
+
+ printf ("Op (%o) at %d = %s", op, i, ops);
+ if (op==UNDO_INSERT || op==UNDO_BS || op==UNDO_DEL) {
+ i++;
+ printf (" - Char is %c", text->undo_buf[i]);
+ i++;
+ } else if (op==UNDO_STO || op==UNDO_CTO) {
+ i++;
+
+ charp= text->undo_buf[i]; i++;
+ charp= charp+(text->undo_buf[i]<<8); i++;
+
+ linep= text->undo_buf[i]; i++;
+ linep= linep+(text->undo_buf[i]<<8); i++;
+ linep= linep+(text->undo_buf[i]<<16); i++;
+ linep= linep+(text->undo_buf[i]<<24); i++;
+
+ printf ("to <%d, %d> ", linep, charp);
+
+ charp= text->undo_buf[i]; i++;
+ charp= charp+(text->undo_buf[i]<<8); i++;
+
+ linep= text->undo_buf[i]; i++;
+ linep= linep+(text->undo_buf[i]<<8); i++;
+ linep= linep+(text->undo_buf[i]<<16); i++;
+ linep= linep+(text->undo_buf[i]<<24); i++;
+
+ printf ("from <%d, %d>", linep, charp);
+ } else if (op==UNDO_DBLOCK || op==UNDO_IBLOCK) {
+ i++;
+
+ linep= text->undo_buf[i]; i++;
+ linep= linep+(text->undo_buf[i]<<8); i++;
+ linep= linep+(text->undo_buf[i]<<16); i++;
+ linep= linep+(text->undo_buf[i]<<24); i++;
+
+ printf (" (length %d) <", linep);
+
+ while (linep>0) {
+ putchar(text->undo_buf[i]);
+ linep--; i++;
+ }
+
+ linep= text->undo_buf[i]; i++;
+ linep= linep+(text->undo_buf[i]<<8); i++;
+ linep= linep+(text->undo_buf[i]<<16); i++;
+ linep= linep+(text->undo_buf[i]<<24); i++;
+ printf ("> (%d)", linep);
+ }
+
+ printf (" %d\n", i);
+ i++;
+ }
+}
+
+static void txt_undo_add_op(Text *text, int op)
+{
+ MAX_UNDO_TEST(2);
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= op;
+ text->undo_buf[text->undo_pos+1]= 0;
+}
+
+static void txt_undo_add_block(Text *text, int op, char *buf)
+{
+ unsigned int length;
+
+ length= strlen(buf);
+
+ MAX_UNDO_TEST(length+11);
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= op;
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (length)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (length>>8)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (length>>16)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (length>>24)&0xff;
+
+ text->undo_pos++;
+ strncpy(text->undo_buf+text->undo_pos, buf, length);
+ text->undo_pos+=length;
+
+ text->undo_buf[text->undo_pos]= (length)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (length>>8)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (length>>16)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (length>>24)&0xff;
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= op;
+
+ text->undo_buf[text->undo_pos+1]= 0;
+}
+
+void txt_undo_add_toop(Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc)
+{
+ MAX_UNDO_TEST(15);
+
+ if (froml==tol && fromc==toc) return;
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= op;
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (fromc)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (fromc>>8)&0xff;
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (froml)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (froml>>8)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (froml>>16)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (froml>>24)&0xff;
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (toc)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (toc>>8)&0xff;
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (tol)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (tol>>8)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (tol>>16)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (tol>>24)&0xff;
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= op;
+
+ text->undo_buf[text->undo_pos+1]= 0;
+}
+
+static void txt_undo_add_charop(Text *text, int op, char c)
+{
+ MAX_UNDO_TEST(4);
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= op;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= c;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= op;
+ text->undo_buf[text->undo_pos+1]= 0;
+}
+
+void txt_do_undo(Text *text)
+{
+ int op= text->undo_buf[text->undo_pos], i;
+ unsigned int linep;
+ unsigned short charp;
+ TextLine *holdl;
+ int holdc, holdln;
+ char *buf;
+
+ if (text->undo_pos<0) {
+ return;
+ }
+
+ text->undo_pos--;
+
+ undoing= 1;
+
+ switch(op) {
+ case UNDO_CLEFT:
+ txt_move_right(text, 0);
+ break;
+
+ case UNDO_CRIGHT:
+ txt_move_left(text, 0);
+ break;
+
+ case UNDO_CUP:
+ txt_move_down(text, 0);
+ break;
+
+ case UNDO_CDOWN:
+ txt_move_up(text, 0);
+ break;
+
+ case UNDO_SLEFT:
+ txt_move_right(text, 1);
+ break;
+
+ case UNDO_SRIGHT:
+ txt_move_left(text, 1);
+ break;
+
+ case UNDO_SUP:
+ txt_move_down(text, 1);
+ break;
+
+ case UNDO_SDOWN:
+ txt_move_up(text, 1);
+ break;
+
+ case UNDO_CTO:
+ case UNDO_STO:
+ text->undo_pos--;
+ text->undo_pos--;
+ text->undo_pos--;
+ text->undo_pos--;
+
+ text->undo_pos--;
+ text->undo_pos--;
+
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+
+ charp= text->undo_buf[text->undo_pos]; text->undo_pos--;
+ charp= (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+
+ if (op==UNDO_CTO) {
+ txt_move_toline(text, linep, 0);
+ text->curc= charp;
+ txt_pop_sel(text);
+ } else {
+ txt_move_toline(text, linep, 1);
+ text->selc= charp;
+ }
+
+ text->undo_pos--;
+ break;
+
+ case UNDO_INSERT:
+ txt_backspace_char(text);
+ text->undo_pos--;
+ text->undo_pos--;
+ break;
+
+ case UNDO_BS:
+ txt_add_char(text, text->undo_buf[text->undo_pos]);
+ text->undo_pos--;
+ text->undo_pos--;
+ break;
+
+ case UNDO_DEL:
+ txt_add_char(text, text->undo_buf[text->undo_pos]);
+ txt_move_left(text, 0);
+ text->undo_pos--;
+ text->undo_pos--;
+ break;
+
+ case UNDO_SWAP:
+ txt_curs_swap(text);
+ txt_do_undo(text); /* swaps should appear transparent */
+ break;
+
+ case UNDO_DBLOCK:
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+
+ buf= MEM_mallocN(linep+1, "dblock buffer");
+ for (i=0; i < (int)linep; i++){
+ buf[(linep-1)-i]= text->undo_buf[text->undo_pos];
+ text->undo_pos--;
+ }
+ buf[i]= 0;
+
+ txt_curs_first(text, &holdl, &holdc);
+ holdln= txt_get_span(text->lines.first, holdl);
+
+ txt_insert_buf(text, buf);
+ MEM_freeN(buf);
+
+ text->curl= text->lines.first;
+ while (holdln>0) {
+ if(text->curl->next)
+ text->curl= text->curl->next;
+
+ holdln--;
+ }
+ text->curc= holdc;
+
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+
+ text->undo_pos--;
+
+ break;
+
+ case UNDO_IBLOCK:
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+
+ txt_delete_sel(text);
+ while (linep>0) {
+ txt_backspace_char(text);
+ text->undo_pos--;
+ linep--;
+ }
+
+ text->undo_pos--;
+ text->undo_pos--;
+ text->undo_pos--;
+ text->undo_pos--;
+
+ text->undo_pos--;
+
+ break;
+
+ default:
+ error("Undo buffer error - resetting");
+ text->undo_pos= -1;
+
+ break;
+ }
+
+ undoing= 0;
+}
+
+void txt_do_redo(Text *text)
+{
+ char op;
+ unsigned int linep;
+ unsigned short charp;
+ char *buf;
+
+ text->undo_pos++;
+ op= text->undo_buf[text->undo_pos];
+
+ if (!op) {
+ text->undo_pos--;
+ return;
+ }
+
+ undoing= 1;
+
+ switch(op) {
+ case UNDO_CLEFT:
+ txt_move_left(text, 0);
+ break;
+
+ case UNDO_CRIGHT:
+ txt_move_right(text, 0);
+ break;
+
+ case UNDO_CUP:
+ txt_move_up(text, 0);
+ break;
+
+ case UNDO_CDOWN:
+ txt_move_down(text, 0);
+ break;
+
+ case UNDO_SLEFT:
+ txt_move_left(text, 1);
+ break;
+
+ case UNDO_SRIGHT:
+ txt_move_right(text, 1);
+ break;
+
+ case UNDO_SUP:
+ txt_move_up(text, 1);
+ break;
+
+ case UNDO_SDOWN:
+ txt_move_down(text, 1);
+ break;
+
+ case UNDO_INSERT:
+ text->undo_pos++;
+ txt_add_char(text, text->undo_buf[text->undo_pos]);
+ text->undo_pos++;
+ break;
+
+ case UNDO_BS:
+ text->undo_pos++;
+ txt_backspace_char(text);
+ text->undo_pos++;
+ break;
+
+ case UNDO_DEL:
+ text->undo_pos++;
+ txt_delete_char(text);
+ text->undo_pos++;
+ break;
+
+ case UNDO_SWAP:
+ txt_curs_swap(text);
+ txt_do_undo(text); /* swaps should appear transparent a*/
+ break;
+
+ case UNDO_CTO:
+ case UNDO_STO:
+ text->undo_pos++;
+ text->undo_pos++;
+
+ text->undo_pos++;
+ text->undo_pos++;
+ text->undo_pos++;
+ text->undo_pos++;
+
+ text->undo_pos++;
+
+ charp= text->undo_buf[text->undo_pos];
+ text->undo_pos++;
+ charp= charp+(text->undo_buf[text->undo_pos]<<8);
+
+ text->undo_pos++;
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
+
+ if (op==UNDO_CTO) {
+ txt_move_toline(text, linep, 0);
+ text->curc= charp;
+ txt_pop_sel(text);
+ } else {
+ txt_move_toline(text, linep, 1);
+ text->selc= charp;
+ }
+
+ break;
+
+ case UNDO_DBLOCK:
+ text->undo_pos++;
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
+
+ txt_delete_sel(text);
+ text->undo_pos+=linep;
+
+ text->undo_pos++;
+ text->undo_pos++;
+ text->undo_pos++;
+ text->undo_pos++;
+
+ break;
+
+ case UNDO_IBLOCK:
+ text->undo_pos++;
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
+
+ buf= MEM_mallocN(linep+1, "iblock buffer");
+ memcpy (buf, &text->undo_buf[text->undo_pos], linep);
+ text->undo_pos+= linep;
+ buf[linep]= 0;
+
+ txt_insert_buf(text, buf);
+ MEM_freeN(buf);
+
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
+
+ break;
+
+ default:
+ error("Undo buffer error - resetting");
+ text->undo_pos= -1;
+
+ break;
+ }
+
+ undoing= 0;
+}
+
+/**************************/
+/* Line editing functions */
+/**************************/
+
+void txt_split_curline (Text *text) {
+ TextLine *ins;
+ char *left, *right;
+
+ if (!text) return;
+ if (!text->curl) return;
+
+ txt_delete_sel(text);
+
+ /* Make the two half strings */
+
+ left= MEM_mallocN(text->curc+1, "textline_string");
+ if (text->curc) memcpy(left, text->curl->line, text->curc);
+ left[text->curc]=0;
+
+ right= MEM_mallocN(text->curl->len - text->curc+1, "textline_string");
+ if (text->curl->len - text->curc) memcpy(right, text->curl->line+text->curc, text->curl->len-text->curc);
+ right[text->curl->len - text->curc]=0;
+
+ MEM_freeN(text->curl->line);
+
+ /* Make the new TextLine */
+
+ ins= MEM_mallocN(sizeof(TextLine), "textline");
+ ins->line= left;
+ ins->len= text->curc;
+
+ text->curl->line= right;
+ text->curl->len= text->curl->len - text->curc;
+
+ BLI_insertlinkbefore(&text->lines, text->curl, ins);
+
+ text->curc=0;
+
+ txt_make_dirty(text);
+ txt_clean_text(text);
+
+ txt_pop_sel(text);
+ if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, '\n');
+}
+
+static void txt_delete_line (Text *text, TextLine *line)
+{
+ if (!text) return;
+ if (!text->curl) return;
+
+ BLI_remlink (&text->lines, line);
+
+ if (line->line) MEM_freeN(line->line);
+ MEM_freeN(line);
+
+ txt_make_dirty(text);
+ txt_clean_text(text);
+}
+
+static void txt_combine_lines (Text *text, TextLine *linea, TextLine *lineb)
+{
+ char *tmp;
+
+ if (!text) return;
+
+ if(!linea || !lineb) return;
+
+ tmp= MEM_mallocN(linea->len+lineb->len+1, "textline_string");
+
+ strcpy(tmp, linea->line);
+ strcat(tmp, lineb->line);
+
+ make_new_line(linea, tmp);
+
+ txt_delete_line(text, lineb);
+
+ txt_make_dirty(text);
+ txt_clean_text(text);
+}
+
+void txt_delete_char (Text *text)
+{
+ char c='\n';
+
+ if (!text) return;
+ if (!text->curl) return;
+
+ if (txt_has_sel(text)) {
+ txt_delete_sel(text);
+ return;
+ }
+
+ if (text->curc== text->curl->len) { /* Appending two lines */
+ if (text->curl->next) {
+ txt_combine_lines(text, text->curl, text->curl->next);
+ txt_pop_sel(text);
+ }
+ } else { /* Just deleting a char */
+ int i= text->curc;
+
+ c= text->curl->line[i];
+ while(i< text->curl->len) {
+ text->curl->line[i]= text->curl->line[i+1];
+ i++;
+ }
+ text->curl->len--;
+
+ txt_pop_sel(text);
+ }
+
+ txt_make_dirty(text);
+ txt_clean_text(text);
+
+ if(!undoing) txt_undo_add_charop(text, UNDO_DEL, c);
+}
+
+void txt_backspace_char (Text *text) {
+ char c='\n';
+
+ if (!text) return;
+ if (!text->curl) return;
+
+ if (txt_has_sel(text)) {
+ txt_delete_sel(text);
+ return;
+ }
+
+ if (text->curc==0) { /* Appending two lines */
+ if (text->curl->prev) {
+ text->curl= text->curl->prev;
+ text->curc= text->curl->len;
+
+ txt_combine_lines(text, text->curl, text->curl->next);
+ txt_pop_sel(text);
+ }
+ } else { /* Just backspacing a char */
+ int i= text->curc-1;
+
+ c= text->curl->line[i];
+ while(i< text->curl->len) {
+ text->curl->line[i]= text->curl->line[i+1];
+ i++;
+ }
+ text->curl->len--;
+ text->curc--;
+
+ txt_pop_sel(text);
+ }
+
+ txt_make_dirty(text);
+ txt_clean_text(text);
+
+ if(!undoing) txt_undo_add_charop(text, UNDO_BS, c);
+}
+
+int txt_add_char (Text *text, char add) {
+ int len;
+ char *tmp;
+
+ if (!text) return 0;
+ if (!text->curl) return 0;
+
+ if (add=='\n') {
+ txt_split_curline(text);
+ return 1;
+ }
+
+ if(txt_illegal_char(add)) return 0;
+
+ txt_delete_sel(text);
+
+ tmp= MEM_mallocN(text->curl->len+2, "textline_string");
+
+ if(text->curc) memcpy(tmp, text->curl->line, text->curc);
+ tmp[text->curc]= add;
+
+ len= text->curl->len - text->curc;
+ if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
+ tmp[text->curl->len+1]=0;
+
+ make_new_line(text->curl, tmp);
+
+ text->curc++;
+
+ txt_pop_sel(text);
+
+ txt_make_dirty(text);
+ txt_clean_text(text);
+
+ if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, add);
+ return 1;
+}