rename some functions to use easier to understand names.
[blender-staging.git] / source / blender / blenkernel / intern / text.c
1 /* text.c
2  *
3  *
4  * $Id$
5  *
6  * ***** BEGIN GPL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL LICENSE BLOCK *****
30  */
31
32 #include <string.h> /* strstr */
33 #include <sys/types.h>
34 #include <sys/stat.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_blenlib.h"
39
40 #include "DNA_action_types.h"
41 #include "DNA_armature_types.h"
42 #include "DNA_constraint_types.h"
43 #include "DNA_controller_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_space_types.h"
47 #include "DNA_text_types.h"
48
49 #include "BKE_depsgraph.h"
50 #include "BKE_global.h"
51 #include "BKE_library.h"
52 #include "BKE_main.h"
53 #include "BKE_node.h"
54 #include "BKE_text.h"
55 #include "BKE_utildefines.h"
56
57 #ifndef DISABLE_PYTHON
58 #include "BPY_extern.h"
59 #endif
60
61 #ifdef HAVE_CONFIG_H
62 #include <config.h>
63 #endif
64
65 /***************/ /*
66
67 How Texts should work
68 --
69 A text should relate to a file as follows -
70 (Text *)->name should be the place where the 
71         file will or has been saved.
72         
73 (Text *)->flags has the following bits
74         TXT_ISDIRTY - should always be set if the file in mem. differs from
75                                         the file on disk, or if there is no file on disk.
76         TXT_ISMEM - should always be set if the Text has not been mapped to
77                                         a file, in which case (Text *)->name may be NULL or garbage.                    
78         TXT_ISEXT - should always be set if the Text is not to be written into
79                                         the .blend
80         TXT_ISSCRIPT - should be set if the user has designated the text
81                                         as a script. (NEW: this was unused, but now it is needed by
82                                         space handler script links (see header_view3d.c, for example)
83
84 ->>> see also: /makesdna/DNA_text_types.h
85
86 Display
87 --
88 The st->top determines at what line the top of the text is displayed.
89 If the user moves the cursor the st containing that cursor should
90 be popped ... other st's retain their own top location.
91
92 Markers
93 --
94 The mrk->flags define the behaviour and relationships between markers. The
95 upper two bytes are used to hold a group ID, the lower two are normal flags. If
96 TMARK_EDITALL is set the group ID defines which other markers should be edited.
97
98 The mrk->clr field is used to visually group markers where the flags may not
99 match. A template system, for example, may allow editing of repeating tokens
100 (in one group) but include other marked positions (in another group) all in the
101 same template with the same colour.
102
103 Undo
104 --
105 Undo/Redo works by storing
106 events in a queue, and a pointer
107 to the current position in the
108 queue...
109
110 Events are stored using an
111 arbitrary op-code system
112 to keep track of
113 a) the two cursors (normal and selected)
114 b) input (visible and control (ie backspace))
115
116 input data is stored as its
117 ASCII value, the opcodes are
118 then selected to not conflict.
119
120 opcodes with data in between are
121 written at the beginning and end
122 of the data to allow undo and redo
123 to simply check the code at the current
124 undo position
125
126 */ /***************/
127
128 /***/
129
130 static void txt_pop_first(Text *text);
131 static void txt_pop_last(Text *text);
132 static void txt_undo_add_op(Text *text, int op);
133 static void txt_undo_add_block(Text *text, int op, const char *buf);
134 static void txt_delete_line(Text *text, TextLine *line);
135 static void txt_delete_sel (Text *text);
136 static void txt_make_dirty (Text *text);
137
138 /***/
139
140 static unsigned char undoing;
141
142 /* allow to switch off undoing externally */
143 void txt_set_undostate(int u)
144 {
145         undoing = u;
146 }
147
148 int txt_get_undostate(void)
149 {
150         return undoing;
151 }
152
153 static void init_undo_text(Text *text)
154 {
155         text->undo_pos= -1;
156         text->undo_len= TXT_INIT_UNDO;
157         text->undo_buf= MEM_mallocN(text->undo_len, "undo buf");
158 }
159
160 void free_text(Text *text)
161 {
162         TextLine *tmp;
163
164         for (tmp= text->lines.first; tmp; tmp= tmp->next) {
165                 MEM_freeN(tmp->line);
166                 if (tmp->format)
167                   MEM_freeN(tmp->format);
168         }
169         
170         BLI_freelistN(&text->lines);
171         BLI_freelistN(&text->markers);
172
173         if(text->name) MEM_freeN(text->name);
174         MEM_freeN(text->undo_buf);
175 #ifndef DISABLE_PYTHON
176         if (text->compiled) BPY_free_compiled_text(text);
177 #endif
178 }
179
180 Text *add_empty_text(char *name) 
181 {
182         Text *ta;
183         TextLine *tmp;
184         
185         ta= alloc_libblock(&G.main->text, ID_TXT, name);
186         ta->id.us= 1;
187         
188         ta->name= NULL;
189
190     init_undo_text(ta);
191
192         ta->nlines=1;
193         ta->flags= TXT_ISDIRTY | TXT_ISMEM;
194         if((U.flag & USER_TXT_TABSTOSPACES_DISABLE)==0)
195                 ta->flags |= TXT_TABSTOSPACES;
196
197         ta->lines.first= ta->lines.last= NULL;
198         ta->markers.first= ta->markers.last= NULL;
199
200         tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
201         tmp->line= (char*) MEM_mallocN(1, "textline_string");
202         tmp->format= NULL;
203         
204         tmp->line[0]=0;
205         tmp->len= 0;
206                                 
207         tmp->next= NULL;
208         tmp->prev= NULL;
209                                 
210         BLI_addhead(&ta->lines, tmp);
211         
212         ta->curl= ta->lines.first;
213         ta->curc= 0;
214         ta->sell= ta->lines.first;
215         ta->selc= 0;
216
217         return ta;
218 }
219
220 // this function removes any control characters from
221 // a textline
222
223 static void cleanup_textline(TextLine * tl)
224 {
225         int i;
226
227         for (i = 0; i < tl->len; i++ ) {
228                 if (tl->line[i] < ' ' && tl->line[i] != '\t') {
229                         memmove(tl->line + i, tl->line + i + 1, tl->len - i);
230                         tl->len--;
231                         i--;
232                 }
233         }
234 }
235
236 int reopen_text(Text *text)
237 {
238         FILE *fp;
239         int i, llen, len, res;
240         unsigned char *buffer;
241         TextLine *tmp;
242         char sfile[FILE_MAXFILE];
243         char str[FILE_MAXDIR+FILE_MAXFILE];
244         struct stat st;
245
246         if (!text || !text->name) return 0;
247         
248         BLI_strncpy(str, text->name, FILE_MAXDIR+FILE_MAXFILE);
249         BLI_path_abs(str, G.sce);
250         BLI_split_dirfile(str, NULL, sfile);
251         
252         fp= fopen(str, "r");
253         if(fp==NULL) return 0;
254
255         /* free memory: */
256
257         for (tmp= text->lines.first; tmp; tmp= tmp->next) {
258                 MEM_freeN(tmp->line);
259                 if (tmp->format) MEM_freeN(tmp->format);
260         }
261         
262         BLI_freelistN(&text->lines);
263
264         text->lines.first= text->lines.last= NULL;
265         text->curl= text->sell= NULL;
266
267         /* clear undo buffer */
268         MEM_freeN(text->undo_buf);
269         init_undo_text(text);
270         
271         fseek(fp, 0L, SEEK_END);
272         len= ftell(fp);
273         fseek(fp, 0L, SEEK_SET);        
274
275         text->undo_pos= -1;
276         
277         buffer= MEM_mallocN(len, "text_buffer");
278         // under windows fread can return less then len bytes because
279         // of CR stripping
280         len = fread(buffer, 1, len, fp);
281
282         fclose(fp);
283
284         res= stat(str, &st);
285         text->mtime= st.st_mtime;
286         
287         text->nlines=0;
288         i=0;
289         llen=0;
290         for(i=0; i<len; i++) {
291                 if (buffer[i]=='\n') {
292                         tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
293                         tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
294                         tmp->format= NULL;
295                         
296                         if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
297                         tmp->line[llen]=0;
298                         tmp->len= llen;
299                                 
300                         cleanup_textline(tmp);
301
302                         BLI_addtail(&text->lines, tmp);
303                         text->nlines++;
304                                 
305                         llen=0;
306                         continue;
307                 }
308                 llen++;
309         }
310
311         if (llen!=0 || text->nlines==0) {
312                 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
313                 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
314                 tmp->format= NULL;
315                 
316                 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
317
318                 tmp->line[llen]=0;
319                 tmp->len= llen;
320                 
321                 cleanup_textline(tmp);
322
323                 BLI_addtail(&text->lines, tmp);
324                 text->nlines++;
325         }
326         
327         text->curl= text->sell= text->lines.first;
328         text->curc= text->selc= 0;
329         
330         MEM_freeN(buffer);      
331         return 1;
332 }
333
334 Text *add_text(char *file, const char *relpath) 
335 {
336         FILE *fp;
337         int i, llen, len, res;
338         unsigned char *buffer;
339         TextLine *tmp;
340         Text *ta;
341         char sfile[FILE_MAXFILE];
342         char str[FILE_MAXDIR+FILE_MAXFILE];
343         struct stat st;
344
345         BLI_strncpy(str, file, FILE_MAXDIR+FILE_MAXFILE);
346         if (relpath) /* can be NULL (bg mode) */
347                 BLI_path_abs(str, relpath);
348         BLI_split_dirfile(str, NULL, sfile);
349         
350         fp= fopen(str, "r");
351         if(fp==NULL) return NULL;
352         
353         ta= alloc_libblock(&G.main->text, ID_TXT, sfile);
354         ta->id.us= 1;
355
356         ta->lines.first= ta->lines.last= NULL;
357         ta->markers.first= ta->markers.last= NULL;
358         ta->curl= ta->sell= NULL;
359
360         if((U.flag & USER_TXT_TABSTOSPACES_DISABLE)==0)
361                 ta->flags= TXT_TABSTOSPACES;
362
363         fseek(fp, 0L, SEEK_END);
364         len= ftell(fp);
365         fseek(fp, 0L, SEEK_SET);        
366
367         ta->name= MEM_mallocN(strlen(file)+1, "text_name");
368         strcpy(ta->name, file);
369
370         init_undo_text(ta);
371         
372         buffer= MEM_mallocN(len, "text_buffer");
373         // under windows fread can return less then len bytes because
374         // of CR stripping
375         len = fread(buffer, 1, len, fp);
376
377         fclose(fp);
378
379         res= stat(str, &st);
380         ta->mtime= st.st_mtime;
381         
382         ta->nlines=0;
383         i=0;
384         llen=0;
385         for(i=0; i<len; i++) {
386                 if (buffer[i]=='\n') {
387                         tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
388                         tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
389                         tmp->format= NULL;
390                         
391                         if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
392                         tmp->line[llen]=0;
393                         tmp->len= llen;
394                         
395                         cleanup_textline(tmp);
396
397                         BLI_addtail(&ta->lines, tmp);
398                         ta->nlines++;
399                                 
400                         llen=0;
401                         continue;
402                 }
403                 llen++;
404         }
405
406         if (llen!=0 || ta->nlines==0) {
407                 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
408                 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
409                 tmp->format= NULL;
410                 
411                 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
412
413                 tmp->line[llen]=0;
414                 tmp->len= llen;
415                 
416                 cleanup_textline(tmp);
417
418                 BLI_addtail(&ta->lines, tmp);
419                 ta->nlines++;
420         }
421         
422         ta->curl= ta->sell= ta->lines.first;
423         ta->curc= ta->selc= 0;
424         
425         MEM_freeN(buffer);      
426
427         return ta;
428 }
429
430 Text *copy_text(Text *ta)
431 {
432         Text *tan;
433         TextLine *line, *tmp;
434         
435         tan= copy_libblock(ta);
436         
437         /* file name can be NULL */
438         if(ta->name) {
439                 tan->name= MEM_mallocN(strlen(ta->name)+1, "text_name");
440                 strcpy(tan->name, ta->name);
441         }
442         else {
443                 tan->name= NULL;
444         }
445
446         tan->flags = ta->flags | TXT_ISDIRTY;
447         
448         tan->lines.first= tan->lines.last= NULL;
449         tan->markers.first= tan->markers.last= NULL;
450         tan->curl= tan->sell= NULL;
451         
452         tan->nlines= ta->nlines;
453
454         line= ta->lines.first;  
455         /* Walk down, reconstructing */
456         while (line) {
457                 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
458                 tmp->line= MEM_mallocN(line->len+1, "textline_string");
459                 tmp->format= NULL;
460                 
461                 strcpy(tmp->line, line->line);
462
463                 tmp->len= line->len;
464                 
465                 BLI_addtail(&tan->lines, tmp);
466                 
467                 line= line->next;
468         }
469
470         tan->curl= tan->sell= tan->lines.first;
471         tan->curc= tan->selc= 0;
472
473         init_undo_text(tan);
474
475         return tan;
476 }
477
478 void unlink_text(Main *bmain, Text *text)
479 {
480         bScreen *scr;
481         ScrArea *area;
482         SpaceLink *sl;
483         Scene *scene;
484         Object *ob;
485         bController *cont;
486         bConstraint *con;
487         short update;
488
489         /* dome */
490         for(scene=bmain->scene.first; scene; scene=scene->id.next)
491                 if(scene->r.dometext == text)
492                         scene->r.dometext = NULL;
493         
494         for(ob=bmain->object.first; ob; ob=ob->id.next) {
495                 /* game controllers */
496                 for(cont=ob->controllers.first; cont; cont=cont->next) {
497                         if(cont->type==CONT_PYTHON) {
498                                 bPythonCont *pc;
499                                 
500                                 pc= cont->data;
501                                 if(pc->text==text) pc->text= NULL;
502                         }
503                 }
504
505                 /* pyconstraints */
506                 update = 0;
507
508                 if(ob->type==OB_ARMATURE && ob->pose) {
509                         bPoseChannel *pchan;
510                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
511                                 for(con = pchan->constraints.first; con; con=con->next) {
512                                         if(con->type==CONSTRAINT_TYPE_PYTHON) {
513                                                 bPythonConstraint *data = con->data;
514                                                 if (data->text==text) data->text = NULL;
515                                                 update = 1;
516                                                 
517                                         }
518                                 }
519                         }
520                 }
521
522                 for(con = ob->constraints.first; con; con=con->next) {
523                         if(con->type==CONSTRAINT_TYPE_PYTHON) {
524                                 bPythonConstraint *data = con->data;
525                                 if (data->text==text) data->text = NULL;
526                                 update = 1;
527                         }
528                 }
529                 
530                 if(update)
531                         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
532         }
533
534         /* pynodes */
535         // XXX nodeDynamicUnlinkText(&text->id);
536         
537         /* text space */
538         for(scr= bmain->screen.first; scr; scr= scr->id.next) {
539                 for(area= scr->areabase.first; area; area= area->next) {
540                         for(sl= area->spacedata.first; sl; sl= sl->next) {
541                                 if(sl->spacetype==SPACE_TEXT) {
542                                         SpaceText *st= (SpaceText*) sl;
543                                         
544                                         if(st->text==text) {
545                                                 st->text= NULL;
546                                                 st->top= 0;
547                                         }
548                                 }
549                         }
550                 }
551         }
552
553         text->id.us= 0;
554 }
555
556 void clear_text(Text *text) /* called directly from rna */
557 {
558         int oldstate;
559
560         oldstate = txt_get_undostate(  );
561         txt_set_undostate( 1 );
562         txt_sel_all( text );
563         txt_delete_sel(text);
564         txt_set_undostate( oldstate );
565
566         txt_make_dirty(text);
567 }
568
569 void write_text(Text *text, char *str) /* called directly from rna */
570 {
571         int oldstate;
572
573         oldstate = txt_get_undostate(  );
574         txt_insert_buf( text, str );
575         txt_move_eof( text, 0 );
576         txt_set_undostate( oldstate );
577
578         txt_make_dirty(text);
579 }
580
581 /*****************************/
582 /* Editing utility functions */
583 /*****************************/
584
585 static void make_new_line (TextLine *line, char *newline) 
586 {
587         if (line->line) MEM_freeN(line->line);
588         if (line->format) MEM_freeN(line->format);
589         
590         line->line= newline;
591         line->len= strlen(newline);
592         line->format= NULL;
593 }
594
595 static TextLine *txt_new_line(char *str)
596 {
597         TextLine *tmp;
598
599         if(!str) str= "";
600         
601         tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
602         tmp->line= MEM_mallocN(strlen(str)+1, "textline_string");
603         tmp->format= NULL;
604         
605         strcpy(tmp->line, str);
606         
607         tmp->len= strlen(str);
608         tmp->next= tmp->prev= NULL;
609         
610         return tmp;
611 }
612
613 static TextLine *txt_new_linen(const char *str, int n)
614 {
615         TextLine *tmp;
616
617         tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
618         tmp->line= MEM_mallocN(n+1, "textline_string");
619         tmp->format= NULL;
620         
621         BLI_strncpy(tmp->line, (str)? str: "", n+1);
622         
623         tmp->len= strlen(tmp->line);
624         tmp->next= tmp->prev= NULL;
625         
626         return tmp;
627 }
628
629 void txt_clean_text (Text *text) 
630 {       
631         TextLine **top, **bot;
632         
633         if (!text) return;
634         
635         if (!text->lines.first) {
636                 if (text->lines.last) text->lines.first= text->lines.last;
637                 else text->lines.first= text->lines.last= txt_new_line(NULL);
638         } 
639         
640         if (!text->lines.last) text->lines.last= text->lines.first;
641
642         top= (TextLine **) &text->lines.first;
643         bot= (TextLine **) &text->lines.last;
644         
645         while ((*top)->prev) *top= (*top)->prev;
646         while ((*bot)->next) *bot= (*bot)->next;
647
648         if(!text->curl) {
649                 if(text->sell) text->curl= text->sell;
650                 else text->curl= text->lines.first;
651                 text->curc= 0;
652         }
653
654         if(!text->sell) {
655                 text->sell= text->curl;
656                 text->selc= 0;
657         }
658 }
659
660 int txt_get_span (TextLine *from, TextLine *to)
661 {
662         int ret=0;
663         TextLine *tmp= from;
664
665         if (!to || !from) return 0;
666         if (from==to) return 0;
667
668         /* Look forwards */
669         while (tmp) {
670                 if (tmp == to) return ret;
671                 ret++;
672                 tmp= tmp->next;
673         }
674
675         /* Look backwards */
676         if (!tmp) {
677                 tmp= from;
678                 ret=0;
679                 while(tmp) {
680                         if (tmp == to) break;
681                         ret--;
682                         tmp= tmp->prev;
683                 }
684                 if(!tmp) ret=0;
685         }
686
687         return ret;     
688 }
689
690 static void txt_make_dirty (Text *text)
691 {
692         text->flags |= TXT_ISDIRTY;
693 #ifndef DISABLE_PYTHON
694         if (text->compiled) BPY_free_compiled_text(text);
695 #endif
696 }
697
698 /* 0:whitespace, 1:punct, 2:alphanumeric */
699 static short txt_char_type (char ch)
700 {
701         if (ch <= ' ') return 0; /* 32 */
702         if (ch <= '/') return 1; /* 47 */
703         if (ch <= '9') return 2; /* 57 */
704         if (ch <= '@') return 1; /* 64 */
705         if (ch <= 'Z') return 2; /* 90 */
706         if (ch == '_') return 2; /* 95, dont delimit '_' */
707         if (ch <= '`') return 1; /* 96 */
708         if (ch <= 'z') return 2; /* 122 */
709         return 1;
710 }
711
712 /****************************/
713 /* Cursor utility functions */
714 /****************************/
715
716 static void txt_curs_cur (Text *text, TextLine ***linep, int **charp)
717 {
718         *linep= &text->curl; *charp= &text->curc;
719 }
720
721 static void txt_curs_sel (Text *text, TextLine ***linep, int **charp)
722 {
723         *linep= &text->sell; *charp= &text->selc;
724 }
725
726 static void txt_curs_first (Text *text, TextLine **linep, int *charp)
727 {
728         if (text->curl==text->sell) {
729                 *linep= text->curl;
730                 if (text->curc<text->selc) *charp= text->curc;
731                 else *charp= text->selc;
732         } else if (txt_get_span(text->lines.first, text->curl)<txt_get_span(text->lines.first, text->sell)) {
733                 *linep= text->curl;
734                 *charp= text->curc;
735         } else {
736                 *linep= text->sell;
737                 *charp= text->selc;             
738         }
739 }
740
741 /****************************/
742 /* Cursor movement functions */
743 /****************************/
744
745 void txt_move_up(Text *text, short sel)
746 {
747         TextLine **linep;
748         int *charp, old;
749         
750         if (!text) return;
751         if(sel) txt_curs_sel(text, &linep, &charp);
752         else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
753         if (!*linep) return;
754         old= *charp;
755
756         if((*linep)->prev) {
757                 *linep= (*linep)->prev;
758                 if (*charp > (*linep)->len) {
759                         *charp= (*linep)->len;
760                         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);
761                 } else {
762                         if(!undoing) txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP);
763                 }
764         } else {
765                 txt_move_bol(text, sel);
766         }
767
768         if(!sel) txt_pop_sel(text);
769 }
770
771 void txt_move_down(Text *text, short sel) 
772 {
773         TextLine **linep;
774         int *charp, old;
775         
776         if (!text) return;
777         if(sel) txt_curs_sel(text, &linep, &charp);
778         else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
779         if (!*linep) return;
780         old= *charp;
781
782         if((*linep)->next) {
783                 *linep= (*linep)->next;
784                 if (*charp > (*linep)->len) {
785                         *charp= (*linep)->len;
786                         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);
787                 } else
788                         if(!undoing) txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN);  
789         } else {
790                 txt_move_eol(text, sel);
791         }
792
793         if(!sel) txt_pop_sel(text);
794 }
795
796 void txt_move_left(Text *text, short sel) 
797 {
798         TextLine **linep;
799         int *charp, oundoing= undoing;
800         
801         if (!text) return;
802         if(sel) txt_curs_sel(text, &linep, &charp);
803         else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
804         if (!*linep) return;
805
806         undoing= 1;
807         if (*charp== 0) {
808                 if ((*linep)->prev) {
809                         txt_move_up(text, sel);
810                         *charp= (*linep)->len;
811                 }
812         } else {
813                 (*charp)--;
814         }
815         undoing= oundoing;
816         if(!undoing) txt_undo_add_op(text, sel?UNDO_SLEFT:UNDO_CLEFT);
817         
818         if(!sel) txt_pop_sel(text);
819 }
820
821 void txt_move_right(Text *text, short sel) 
822 {
823         TextLine **linep;
824         int *charp, oundoing= undoing;
825         
826         if (!text) return;
827         if(sel) txt_curs_sel(text, &linep, &charp);
828         else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
829         if (!*linep) return;
830
831         undoing= 1;
832         if (*charp== (*linep)->len) {
833                 if ((*linep)->next) {
834                         txt_move_down(text, sel);
835                         *charp= 0;
836                 }
837         } else {
838                 (*charp)++;
839         }
840         undoing= oundoing;
841         if(!undoing) txt_undo_add_op(text, sel?UNDO_SRIGHT:UNDO_CRIGHT);
842
843         if(!sel) txt_pop_sel(text);
844 }
845
846 void txt_jump_left(Text *text, short sel)
847 {
848         TextLine **linep, *oldl;
849         int *charp, oldc, count, i;
850         unsigned char oldu;
851
852         if (!text) return;
853         if(sel) txt_curs_sel(text, &linep, &charp);
854         else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
855         if (!*linep) return;
856
857         oldl= *linep;
858         oldc= *charp;
859         oldu= undoing;
860         undoing= 1; /* Don't push individual moves to undo stack */
861
862         count= 0;
863         for (i=0; i<3; i++) {
864                 if (count < 2) {
865                         while (*charp>0 && txt_char_type((*linep)->line[*charp-1])==i) {
866                                 txt_move_left(text, sel);
867                                 count++;
868                         }
869                 }
870         }
871         if (count==0) txt_move_left(text, sel);
872
873         undoing= oldu;
874         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);
875 }
876
877 void txt_jump_right(Text *text, short sel)
878 {
879         TextLine **linep, *oldl;
880         int *charp, oldc, count, i;
881         unsigned char oldu;
882
883         if (!text) return;
884         if(sel) txt_curs_sel(text, &linep, &charp);
885         else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
886         if (!*linep) return;
887
888         oldl= *linep;
889         oldc= *charp;
890         oldu= undoing;
891         undoing= 1; /* Don't push individual moves to undo stack */
892
893         count= 0;
894         for (i=0; i<3; i++) {
895                 if (count < 2) {
896                         while (*charp<(*linep)->len && txt_char_type((*linep)->line[*charp])==i) {
897                                 txt_move_right(text, sel);
898                                 count++;
899                         }
900                 }
901         }
902         if (count==0) txt_move_right(text, sel);
903
904         undoing= oldu;
905         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);
906 }
907
908 void txt_move_bol (Text *text, short sel) 
909 {
910         TextLine **linep;
911         int *charp, old;
912         
913         if (!text) return;
914         if(sel) txt_curs_sel(text, &linep, &charp);
915         else txt_curs_cur(text, &linep, &charp);
916         if (!*linep) return;
917         old= *charp;
918         
919         *charp= 0;
920
921         if(!sel) txt_pop_sel(text);
922         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);
923 }
924
925 void txt_move_eol (Text *text, short sel) 
926 {
927         TextLine **linep;
928         int *charp, old;
929         
930         if (!text) return;
931         if(sel) txt_curs_sel(text, &linep, &charp);
932         else txt_curs_cur(text, &linep, &charp);
933         if (!*linep) return;
934         old= *charp;
935                 
936         *charp= (*linep)->len;
937
938         if(!sel) txt_pop_sel(text);
939         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);
940 }
941
942 void txt_move_bof (Text *text, short sel)
943 {
944         TextLine **linep;
945         int *charp, old;
946         
947         if (!text) return;
948         if(sel) txt_curs_sel(text, &linep, &charp);
949         else txt_curs_cur(text, &linep, &charp);
950         if (!*linep) return;
951         old= *charp;
952
953         *linep= text->lines.first;
954         *charp= 0;
955
956         if(!sel) txt_pop_sel(text);
957         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);
958 }
959
960 void txt_move_eof (Text *text, short sel)
961 {
962         TextLine **linep;
963         int *charp, old;
964         
965         if (!text) return;
966         if(sel) txt_curs_sel(text, &linep, &charp);
967         else txt_curs_cur(text, &linep, &charp);
968         if (!*linep) return;
969         old= *charp;
970
971         *linep= text->lines.last;
972         *charp= (*linep)->len;
973
974         if(!sel) txt_pop_sel(text);
975         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);     
976 }
977
978 void txt_move_toline (Text *text, unsigned int line, short sel)
979 {
980         txt_move_to(text, line, 0, sel);
981 }
982
983 void txt_move_to (Text *text, unsigned int line, unsigned int ch, short sel)
984 {
985         TextLine **linep, *oldl;
986         int *charp, oldc;
987         unsigned int i;
988         
989         if (!text) return;
990         if(sel) txt_curs_sel(text, &linep, &charp);
991         else txt_curs_cur(text, &linep, &charp);
992         if (!*linep) return;
993         oldc= *charp;
994         oldl= *linep;
995         
996         *linep= text->lines.first;
997         for (i=0; i<line; i++) {
998                 if ((*linep)->next) *linep= (*linep)->next;
999                 else break;
1000         }
1001         if (ch>(*linep)->len)
1002                 ch= (*linep)->len;
1003         *charp= ch;
1004         
1005         if(!sel) txt_pop_sel(text);
1006         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);
1007 }
1008
1009 /****************************/
1010 /* Text selection functions */
1011 /****************************/
1012
1013 static void txt_curs_swap (Text *text)
1014 {
1015         TextLine *tmpl;
1016         int tmpc;
1017                 
1018         tmpl= text->curl;
1019         text->curl= text->sell;
1020         text->sell= tmpl;
1021         
1022         tmpc= text->curc;
1023         text->curc= text->selc;
1024         text->selc= tmpc;
1025         
1026         if(!undoing) txt_undo_add_op(text, UNDO_SWAP);
1027 }
1028
1029 static void txt_pop_first (Text *text)
1030 {
1031                         
1032         if (txt_get_span(text->curl, text->sell)<0 ||
1033                 (text->curl==text->sell && text->curc>text->selc)) {    
1034                 txt_curs_swap(text);
1035         }
1036
1037         if(!undoing) txt_undo_add_toop(text, UNDO_STO,
1038                 txt_get_span(text->lines.first, text->sell), 
1039                 text->selc, 
1040                 txt_get_span(text->lines.first, text->curl), 
1041                 text->curc);            
1042         
1043         txt_pop_sel(text);
1044 }
1045
1046 static void txt_pop_last (Text *text)
1047 {
1048         if (txt_get_span(text->curl, text->sell)>0 ||
1049                 (text->curl==text->sell && text->curc<text->selc)) {
1050                 txt_curs_swap(text);
1051         }
1052
1053         if(!undoing) txt_undo_add_toop(text, UNDO_STO,
1054                 txt_get_span(text->lines.first, text->sell), 
1055                 text->selc, 
1056                 txt_get_span(text->lines.first, text->curl), 
1057                 text->curc);            
1058         
1059         txt_pop_sel(text);
1060 }
1061
1062 /* never used: CVS 1.19 */
1063 /*  static void txt_pop_selr (Text *text) */
1064
1065 void txt_pop_sel (Text *text)
1066 {
1067         text->sell= text->curl;
1068         text->selc= text->curc; 
1069 }
1070
1071 void txt_order_cursors(Text *text)
1072 {
1073         if (!text) return;
1074         if (!text->curl) return;
1075         if (!text->sell) return;
1076         
1077                 /* Flip so text->curl is before text->sell */
1078         if (txt_get_span(text->curl, text->sell)<0 ||
1079                         (text->curl==text->sell && text->curc>text->selc))
1080                 txt_curs_swap(text);
1081 }
1082
1083 int txt_has_sel(Text *text)
1084 {
1085         return ((text->curl!=text->sell) || (text->curc!=text->selc));
1086 }
1087
1088 static void txt_delete_sel (Text *text)
1089 {
1090         TextLine *tmpl;
1091         TextMarker *mrk;
1092         char *buf;
1093         int move, lineno;
1094         
1095         if (!text) return;
1096         if (!text->curl) return;
1097         if (!text->sell) return;
1098
1099         if (!txt_has_sel(text)) return;
1100         
1101         txt_order_cursors(text);
1102
1103         if(!undoing) {
1104                 buf= txt_sel_to_buf(text);
1105                 txt_undo_add_block(text, UNDO_DBLOCK, buf);
1106                 MEM_freeN(buf);
1107         }
1108
1109         buf= MEM_mallocN(text->curc+(text->sell->len - text->selc)+1, "textline_string");
1110         
1111         if (text->curl != text->sell) {
1112                 txt_clear_marker_region(text, text->curl, text->curc, text->curl->len, 0, 0);
1113                 move= txt_get_span(text->curl, text->sell);
1114         } else {
1115                 mrk= txt_find_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
1116                 if (mrk && (mrk->start > text->curc || mrk->end < text->selc))
1117                         txt_clear_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
1118                 move= 0;
1119         }
1120
1121         mrk= txt_find_marker_region(text, text->sell, text->selc-1, text->sell->len, 0, 0);
1122         if (mrk) {
1123                 lineno= mrk->lineno;
1124                 do {
1125                         mrk->lineno -= move;
1126                         if (mrk->start > text->curc) mrk->start -= text->selc - text->curc;
1127                         mrk->end -= text->selc - text->curc;
1128                         mrk= mrk->next;
1129                 } while (mrk && mrk->lineno==lineno);
1130         }
1131
1132         strncpy(buf, text->curl->line, text->curc);
1133         strcpy(buf+text->curc, text->sell->line + text->selc);
1134         buf[text->curc+(text->sell->len - text->selc)]=0;
1135
1136         make_new_line(text->curl, buf);
1137         
1138         tmpl= text->sell;
1139         while (tmpl != text->curl) {
1140                 tmpl= tmpl->prev;
1141                 if (!tmpl) break;
1142                 
1143                 txt_delete_line(text, tmpl->next);
1144         }
1145         
1146         text->sell= text->curl;
1147         text->selc= text->curc;
1148 }
1149
1150 void txt_sel_all (Text *text)
1151 {
1152         if (!text) return;
1153
1154         text->curl= text->lines.first;
1155         text->curc= 0;
1156         
1157         text->sell= text->lines.last;
1158         text->selc= text->sell->len;
1159 }
1160
1161 void txt_sel_line (Text *text)
1162 {
1163         if (!text) return;
1164         if (!text->curl) return;
1165         
1166         text->curc= 0;
1167         text->sell= text->curl;
1168         text->selc= text->sell->len;
1169 }
1170
1171 /***************************/
1172 /* Cut and paste functions */
1173 /***************************/
1174
1175 char *txt_to_buf (Text *text)
1176 {
1177         int length;
1178         TextLine *tmp, *linef, *linel;
1179         int charf, charl;
1180         char *buf;
1181         
1182         if (!text) return NULL;
1183         if (!text->curl) return NULL;
1184         if (!text->sell) return NULL;
1185         if (!text->lines.first) return NULL;
1186
1187         linef= text->lines.first;
1188         charf= 0;
1189                 
1190         linel= text->lines.last;
1191         charl= linel->len;
1192
1193         if (linef == text->lines.last) {
1194                 length= charl-charf;
1195
1196                 buf= MEM_mallocN(length+2, "text buffer");
1197                 
1198                 BLI_strncpy(buf, linef->line + charf, length+1);
1199                 buf[length]=0;
1200         } else {
1201                 length= linef->len - charf;
1202                 length+= charl;
1203                 length+= 2; /* For the 2 '\n' */
1204                 
1205                 tmp= linef->next;
1206                 while (tmp && tmp!= linel) {
1207                         length+= tmp->len+1;
1208                         tmp= tmp->next;
1209                 }
1210                 
1211                 buf= MEM_mallocN(length+1, "cut buffer");
1212
1213                 strncpy(buf, linef->line + charf, linef->len-charf);
1214                 length= linef->len - charf;
1215                 
1216                 buf[length++]='\n';
1217                 
1218                 tmp= linef->next;
1219                 while (tmp && tmp!=linel) {
1220                         strncpy(buf+length, tmp->line, tmp->len);
1221                         length+= tmp->len;
1222                         
1223                         buf[length++]='\n';                     
1224                         
1225                         tmp= tmp->next;
1226                 }
1227                 strncpy(buf+length, linel->line, charl);
1228                 length+= charl;
1229                 
1230                 /* python compiler wants an empty end line */
1231                 buf[length++]='\n';                     
1232                 buf[length]=0;
1233         }
1234         
1235         return buf;
1236 }
1237
1238 int txt_find_string(Text *text, char *findstr, int wrap)
1239 {
1240         TextLine *tl, *startl;
1241         char *s= NULL;
1242         int oldcl, oldsl, oldcc, oldsc;
1243
1244         if (!text || !text->curl || !text->sell) return 0;
1245         
1246         txt_order_cursors(text);
1247
1248         oldcl= txt_get_span(text->lines.first, text->curl);
1249         oldsl= txt_get_span(text->lines.first, text->sell);
1250         tl= startl= text->sell;
1251         oldcc= text->curc;
1252         oldsc= text->selc;
1253         
1254         s= strstr(&tl->line[text->selc], findstr);
1255         while (!s) {
1256                 tl= tl->next;
1257                 if (!tl) {
1258                         if (wrap)
1259                                 tl= text->lines.first;
1260                         else
1261                                 break;
1262                 }
1263
1264                 s= strstr(tl->line, findstr);
1265                 if (tl==startl)
1266                         break;
1267         }
1268         
1269         if (s) {
1270                 int newl= txt_get_span(text->lines.first, tl);
1271                 int newc= (int)(s-tl->line);
1272                 txt_move_to(text, newl, newc, 0);
1273                 txt_move_to(text, newl, newc + strlen(findstr), 1);
1274                 return 1;                               
1275         } else
1276                 return 0;
1277 }
1278
1279 char *txt_sel_to_buf (Text *text)
1280 {
1281         char *buf;
1282         int length=0;
1283         TextLine *tmp, *linef, *linel;
1284         int charf, charl;
1285         
1286         if (!text) return NULL;
1287         if (!text->curl) return NULL;
1288         if (!text->sell) return NULL;
1289         
1290         if (text->curl==text->sell) {
1291                 linef= linel= text->curl;
1292                 
1293                 if (text->curc < text->selc) {
1294                         charf= text->curc;
1295                         charl= text->selc;
1296                 } else{
1297                         charf= text->selc;
1298                         charl= text->curc;
1299                 }
1300         } else if (txt_get_span(text->curl, text->sell)<0) {
1301                 linef= text->sell;
1302                 linel= text->curl;
1303
1304                 charf= text->selc;              
1305                 charl= text->curc;
1306         } else {
1307                 linef= text->curl;
1308                 linel= text->sell;
1309                 
1310                 charf= text->curc;
1311                 charl= text->selc;
1312         }
1313
1314         if (linef == linel) {
1315                 length= charl-charf;
1316
1317                 buf= MEM_mallocN(length+1, "sel buffer");
1318                 
1319                 BLI_strncpy(buf, linef->line + charf, length+1);
1320         } else {
1321                 length+= linef->len - charf;
1322                 length+= charl;
1323                 length++; /* For the '\n' */
1324                 
1325                 tmp= linef->next;
1326                 while (tmp && tmp!= linel) {
1327                         length+= tmp->len+1;
1328                         tmp= tmp->next;
1329                 }
1330                 
1331                 buf= MEM_mallocN(length+1, "sel buffer");
1332                 
1333                 strncpy(buf, linef->line+ charf, linef->len-charf);
1334                 length= linef->len-charf;
1335                 
1336                 buf[length++]='\n';
1337                 
1338                 tmp= linef->next;
1339                 while (tmp && tmp!=linel) {
1340                         strncpy(buf+length, tmp->line, tmp->len);
1341                         length+= tmp->len;
1342                         
1343                         buf[length++]='\n';                     
1344                         
1345                         tmp= tmp->next;
1346                 }
1347                 strncpy(buf+length, linel->line, charl);
1348                 length+= charl;
1349                 
1350                 buf[length]=0;
1351         }       
1352
1353         return buf;
1354 }
1355
1356 void txt_insert_buf(Text *text, const char *in_buffer)
1357 {
1358         int i=0, l=0, j, u, len;
1359         TextLine *add;
1360
1361         if (!text) return;
1362         if (!in_buffer) return;
1363
1364         txt_delete_sel(text);
1365         
1366         if(!undoing) txt_undo_add_block (text, UNDO_IBLOCK, in_buffer);         
1367
1368         u= undoing;
1369         undoing= 1;
1370
1371         /* Read the first line (or as close as possible */
1372         while (in_buffer[i] && in_buffer[i]!='\n') {
1373                 txt_add_char(text, in_buffer[i]);
1374                 i++;
1375         }
1376         
1377         if (in_buffer[i]=='\n') txt_split_curline(text);
1378         else { undoing = u; return; }
1379         i++;
1380
1381         /* Read as many full lines as we can */
1382         len= strlen(in_buffer);
1383
1384         while (i<len) {
1385                 l=0;
1386
1387                 while (in_buffer[i] && in_buffer[i]!='\n') {
1388                         i++; l++;
1389                 }
1390         
1391                 if(in_buffer[i]=='\n') {
1392                         add= txt_new_linen(in_buffer +(i-l), l);
1393                         BLI_insertlinkbefore(&text->lines, text->curl, add);
1394                         i++;
1395                 } else {
1396                         for (j= i-l; j<i && j<(int)strlen(in_buffer); j++) {
1397                                 txt_add_char(text, in_buffer[j]);
1398                         }
1399                         break;
1400                 }
1401         }
1402         
1403         undoing= u;
1404 }
1405
1406 /******************/
1407 /* Undo functions */
1408 /******************/
1409
1410 static int max_undo_test(Text *text, int x)
1411 {
1412         while (text->undo_pos+x >= text->undo_len) {
1413                 if(text->undo_len*2 > TXT_MAX_UNDO) {
1414                         /* XXX error("Undo limit reached, buffer cleared\n"); */
1415                         MEM_freeN(text->undo_buf);
1416                         init_undo_text(text);
1417                         return 0;
1418                 } else {
1419                         void *tmp= text->undo_buf;
1420                         text->undo_buf= MEM_callocN(text->undo_len*2, "undo buf");
1421                         memcpy(text->undo_buf, tmp, text->undo_len);
1422                         text->undo_len*=2;
1423                         MEM_freeN(tmp);
1424                 }
1425         }
1426
1427         return 1;
1428 }
1429
1430 static void dump_buffer(Text *text) 
1431 {
1432         int i= 0;
1433         
1434         while (i++<text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]);
1435 }
1436
1437 void txt_print_undo(Text *text)
1438 {
1439         int i= 0;
1440         int op;
1441         char *ops;
1442         int linep, charp;
1443         
1444         dump_buffer(text);
1445         
1446         printf ("---< Undo Buffer >---\n");
1447         
1448         printf ("UndoPosition is %d\n", text->undo_pos);
1449         
1450         while (i<=text->undo_pos) {
1451                 op= text->undo_buf[i];
1452                 
1453                 if (op==UNDO_CLEFT) {
1454                         ops= "Cursor left";
1455                 } else if (op==UNDO_CRIGHT) {
1456                         ops= "Cursor right";
1457                 } else if (op==UNDO_CUP) {
1458                         ops= "Cursor up";
1459                 } else if (op==UNDO_CDOWN) {
1460                         ops= "Cursor down";
1461                 } else if (op==UNDO_SLEFT) {
1462                         ops= "Selection left";
1463                 } else if (op==UNDO_SRIGHT) {
1464                         ops= "Selection right";
1465                 } else if (op==UNDO_SUP) {
1466                         ops= "Selection up";
1467                 } else if (op==UNDO_SDOWN) {
1468                         ops= "Selection down";
1469                 } else if (op==UNDO_STO) {
1470                         ops= "Selection ";
1471                 } else if (op==UNDO_CTO) {
1472                         ops= "Cursor ";
1473                 } else if (op==UNDO_INSERT) {
1474                         ops= "Insert";
1475                 } else if (op==UNDO_BS) {
1476                         ops= "Backspace";
1477                 } else if (op==UNDO_DEL) {
1478                         ops= "Delete";
1479                 } else if (op==UNDO_SWAP) {
1480                         ops= "Cursor swap";
1481                 } else if (op==UNDO_DBLOCK) {
1482                         ops= "Delete text block";
1483                 } else if (op==UNDO_IBLOCK) {
1484                         ops= "Insert text block";
1485                 } else if (op==UNDO_INDENT) {
1486                         ops= "Indent ";
1487                 } else if (op==UNDO_UNINDENT) {
1488                         ops= "Unindent ";
1489                 } else if (op==UNDO_COMMENT) {
1490                         ops= "Comment ";
1491                 } else if (op==UNDO_UNCOMMENT) {
1492                         ops= "Uncomment ";
1493                 } else {
1494                         ops= "Unknown";
1495                 }
1496                 
1497                 printf ("Op (%o) at %d = %s", op, i, ops);
1498                 if (op==UNDO_INSERT || op==UNDO_BS || op==UNDO_DEL) {
1499                         i++;
1500                         printf (" - Char is %c", text->undo_buf[i]);  
1501                         i++;
1502                 } else if (op==UNDO_STO || op==UNDO_CTO) {
1503                         i++;
1504
1505                         charp= text->undo_buf[i]; i++;
1506                         charp= charp+(text->undo_buf[i]<<8); i++;
1507
1508                         linep= text->undo_buf[i]; i++;
1509                         linep= linep+(text->undo_buf[i]<<8); i++;
1510                         linep= linep+(text->undo_buf[i]<<16); i++;
1511                         linep= linep+(text->undo_buf[i]<<24); i++;
1512                         
1513                         printf ("to <%d, %d> ", linep, charp);
1514
1515                         charp= text->undo_buf[i]; i++;
1516                         charp= charp+(text->undo_buf[i]<<8); i++;
1517
1518                         linep= text->undo_buf[i]; i++;
1519                         linep= linep+(text->undo_buf[i]<<8); i++;
1520                         linep= linep+(text->undo_buf[i]<<16); i++;
1521                         linep= linep+(text->undo_buf[i]<<24); i++;
1522                         
1523                         printf ("from <%d, %d>", linep, charp);
1524                 } else if (op==UNDO_DBLOCK || op==UNDO_IBLOCK) {
1525                         i++;
1526
1527                         linep= text->undo_buf[i]; i++;
1528                         linep= linep+(text->undo_buf[i]<<8); i++;
1529                         linep= linep+(text->undo_buf[i]<<16); i++;
1530                         linep= linep+(text->undo_buf[i]<<24); i++;
1531                         
1532                         printf (" (length %d) <", linep);
1533                         
1534                         while (linep>0) {
1535                                 putchar(text->undo_buf[i]);
1536                                 linep--; i++;
1537                         }
1538                         
1539                         linep= text->undo_buf[i]; i++;
1540                         linep= linep+(text->undo_buf[i]<<8); i++;
1541                         linep= linep+(text->undo_buf[i]<<16); i++;
1542                         linep= linep+(text->undo_buf[i]<<24); i++;
1543                         printf ("> (%d)", linep);
1544                 } else if (op==UNDO_INDENT || op==UNDO_UNINDENT) {
1545                         i++;
1546
1547                         charp= text->undo_buf[i]; i++;
1548                         charp= charp+(text->undo_buf[i]<<8); i++;
1549
1550                         linep= text->undo_buf[i]; i++;
1551                         linep= linep+(text->undo_buf[i]<<8); i++;
1552                         linep= linep+(text->undo_buf[i]<<16); i++;
1553                         linep= linep+(text->undo_buf[i]<<24); i++;
1554                         
1555                         printf ("to <%d, %d> ", linep, charp);
1556
1557                         charp= text->undo_buf[i]; i++;
1558                         charp= charp+(text->undo_buf[i]<<8); i++;
1559
1560                         linep= text->undo_buf[i]; i++;
1561                         linep= linep+(text->undo_buf[i]<<8); i++;
1562                         linep= linep+(text->undo_buf[i]<<16); i++;
1563                         linep= linep+(text->undo_buf[i]<<24); i++;
1564                         
1565                         printf ("from <%d, %d>", linep, charp);
1566                 }
1567                 
1568                 printf (" %d\n",  i);
1569                 i++;
1570         }
1571 }
1572
1573 static void txt_undo_add_op(Text *text, int op)
1574 {
1575         if(!max_undo_test(text, 2))
1576                 return;
1577         
1578         text->undo_pos++;
1579         text->undo_buf[text->undo_pos]= op;
1580         text->undo_buf[text->undo_pos+1]= 0;
1581 }
1582
1583 static void txt_undo_add_block(Text *text, int op, const char *buf)
1584 {
1585         int length;
1586         
1587         length= strlen(buf);
1588         
1589         if(!max_undo_test(text, length+11))
1590                 return;
1591
1592         text->undo_pos++;
1593         text->undo_buf[text->undo_pos]= op;
1594         
1595         text->undo_pos++;
1596         text->undo_buf[text->undo_pos]= (length)&0xff;
1597         text->undo_pos++;
1598         text->undo_buf[text->undo_pos]= (length>>8)&0xff;
1599         text->undo_pos++;
1600         text->undo_buf[text->undo_pos]= (length>>16)&0xff;
1601         text->undo_pos++;
1602         text->undo_buf[text->undo_pos]= (length>>24)&0xff;
1603
1604         text->undo_pos++;
1605         strncpy(text->undo_buf+text->undo_pos, buf, length);
1606         text->undo_pos+=length;
1607
1608         text->undo_buf[text->undo_pos]= (length)&0xff;
1609         text->undo_pos++;
1610         text->undo_buf[text->undo_pos]= (length>>8)&0xff;
1611         text->undo_pos++;
1612         text->undo_buf[text->undo_pos]= (length>>16)&0xff;
1613         text->undo_pos++;
1614         text->undo_buf[text->undo_pos]= (length>>24)&0xff;
1615
1616         text->undo_pos++;
1617         text->undo_buf[text->undo_pos]= op;
1618         
1619         text->undo_buf[text->undo_pos+1]= 0;
1620 }
1621
1622 void txt_undo_add_toop(Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc)
1623 {
1624         if(!max_undo_test(text, 15))
1625                 return;
1626
1627         if (froml==tol && fromc==toc) return;
1628
1629         text->undo_pos++;
1630         text->undo_buf[text->undo_pos]= op;
1631
1632         text->undo_pos++;
1633         text->undo_buf[text->undo_pos]= (fromc)&0xff;
1634         text->undo_pos++;
1635         text->undo_buf[text->undo_pos]= (fromc>>8)&0xff;
1636
1637         text->undo_pos++;
1638         text->undo_buf[text->undo_pos]= (froml)&0xff;
1639         text->undo_pos++;
1640         text->undo_buf[text->undo_pos]= (froml>>8)&0xff;
1641         text->undo_pos++;
1642         text->undo_buf[text->undo_pos]= (froml>>16)&0xff;
1643         text->undo_pos++;
1644         text->undo_buf[text->undo_pos]= (froml>>24)&0xff;
1645
1646         text->undo_pos++;
1647         text->undo_buf[text->undo_pos]= (toc)&0xff;
1648         text->undo_pos++;
1649         text->undo_buf[text->undo_pos]= (toc>>8)&0xff;
1650
1651         text->undo_pos++;
1652         text->undo_buf[text->undo_pos]= (tol)&0xff;
1653         text->undo_pos++;
1654         text->undo_buf[text->undo_pos]= (tol>>8)&0xff;
1655         text->undo_pos++;
1656         text->undo_buf[text->undo_pos]= (tol>>16)&0xff;
1657         text->undo_pos++;
1658         text->undo_buf[text->undo_pos]= (tol>>24)&0xff;
1659
1660         text->undo_pos++;
1661         text->undo_buf[text->undo_pos]= op;
1662
1663         text->undo_buf[text->undo_pos+1]= 0;
1664 }
1665
1666 static void txt_undo_add_charop(Text *text, int op, char c)
1667 {
1668         if(!max_undo_test(text, 4))
1669                 return;
1670
1671         text->undo_pos++;
1672         text->undo_buf[text->undo_pos]= op;
1673         text->undo_pos++;
1674         text->undo_buf[text->undo_pos]= c;
1675         text->undo_pos++;
1676         text->undo_buf[text->undo_pos]= op;
1677         text->undo_buf[text->undo_pos+1]= 0;
1678 }
1679
1680 void txt_do_undo(Text *text)
1681 {
1682         int op= text->undo_buf[text->undo_pos];
1683         unsigned int linep, i;
1684         unsigned short charp;
1685         TextLine *holdl;
1686         int holdc, holdln;
1687         char *buf;
1688         
1689         if (text->undo_pos<0) {
1690                 return;
1691         }
1692
1693         text->undo_pos--;
1694
1695         undoing= 1;
1696         
1697         switch(op) {
1698                 case UNDO_CLEFT:
1699                         txt_move_right(text, 0);
1700                         break;
1701                         
1702                 case UNDO_CRIGHT:
1703                         txt_move_left(text, 0);
1704                         break;
1705                         
1706                 case UNDO_CUP:
1707                         txt_move_down(text, 0);
1708                         break;
1709                         
1710                 case UNDO_CDOWN:
1711                         txt_move_up(text, 0);
1712                         break;
1713
1714                 case UNDO_SLEFT:
1715                         txt_move_right(text, 1);
1716                         break;
1717
1718                 case UNDO_SRIGHT:
1719                         txt_move_left(text, 1);
1720                         break;
1721
1722                 case UNDO_SUP:
1723                         txt_move_down(text, 1);
1724                         break;
1725
1726                 case UNDO_SDOWN:
1727                         txt_move_up(text, 1);
1728                         break;
1729                 
1730                 case UNDO_CTO:
1731                 case UNDO_STO:
1732                         text->undo_pos--;
1733                         text->undo_pos--;
1734                         text->undo_pos--;
1735                         text->undo_pos--;
1736                 
1737                         text->undo_pos--;
1738                         text->undo_pos--;
1739                 
1740                         linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1741                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1742                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1743                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1744
1745                         charp= text->undo_buf[text->undo_pos]; text->undo_pos--;
1746                         charp= (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1747                         
1748                         if (op==UNDO_CTO) {
1749                                 txt_move_toline(text, linep, 0);
1750                                 text->curc= charp;
1751                                 txt_pop_sel(text);
1752                         } else {
1753                                 txt_move_toline(text, linep, 1);
1754                                 text->selc= charp;
1755                         }
1756                         
1757                         text->undo_pos--;
1758                         break;
1759                         
1760                 case UNDO_INSERT:
1761                         txt_backspace_char(text);
1762                         text->undo_pos--;
1763                         text->undo_pos--;
1764                         break;
1765
1766                 case UNDO_BS:
1767                         txt_add_char(text, text->undo_buf[text->undo_pos]);
1768                         text->undo_pos--;
1769                         text->undo_pos--;
1770                         break;
1771
1772                 case UNDO_DEL:
1773                         txt_add_char(text, text->undo_buf[text->undo_pos]);
1774                         txt_move_left(text, 0);
1775                         text->undo_pos--;
1776                         text->undo_pos--;
1777                         break;
1778
1779                 case UNDO_SWAP:
1780                         txt_curs_swap(text);
1781                         break;
1782
1783                 case UNDO_DBLOCK:
1784                         linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1785                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1786                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1787                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1788
1789                         buf= MEM_mallocN(linep+1, "dblock buffer");
1790                         for (i=0; i < linep; i++){
1791                                 buf[(linep-1)-i]= text->undo_buf[text->undo_pos]; 
1792                                 text->undo_pos--;
1793                         }
1794                         buf[i]= 0;
1795                         
1796                         txt_curs_first(text, &holdl, &holdc);
1797                         holdln= txt_get_span(text->lines.first, holdl);
1798                         
1799                         txt_insert_buf(text, buf);                      
1800                         MEM_freeN(buf);
1801
1802                         text->curl= text->lines.first;
1803                         while (holdln>0) {
1804                                 if(text->curl->next)
1805                                         text->curl= text->curl->next;
1806                                         
1807                                 holdln--;
1808                         }
1809                         text->curc= holdc;
1810
1811                         linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1812                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1813                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1814                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1815
1816                         text->undo_pos--;
1817                         
1818                         break;
1819
1820                 case UNDO_IBLOCK:
1821                         linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1822                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1823                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1824                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1825
1826                         txt_delete_sel(text);
1827                         while (linep>0) {
1828                                 txt_backspace_char(text);
1829                                 text->undo_pos--;
1830                                 linep--;
1831                         }
1832
1833                         text->undo_pos--;
1834                         text->undo_pos--;
1835                         text->undo_pos--; 
1836                         text->undo_pos--;
1837                         
1838                         text->undo_pos--;
1839
1840                         break;
1841                 case UNDO_INDENT:
1842                 case UNDO_UNINDENT:
1843                 case UNDO_COMMENT:
1844                 case UNDO_UNCOMMENT:
1845                         linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1846                         linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1847                         linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1848                         linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1849                         //linep is now the end line of the selection
1850                         
1851                         charp = text->undo_buf[text->undo_pos]; text->undo_pos--;
1852                         charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1853                         //charp is the last char selected or text->line->len
1854                         //set the selcetion for this now
1855                         text->selc = charp;
1856                         text->sell = text->lines.first;
1857                         for (i= 0; i < linep; i++) {
1858                                 text->sell = text->sell->next;
1859                         }
1860
1861                         linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1862                         linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1863                         linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1864                         linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1865                         //first line to be selected
1866                         
1867                         charp = text->undo_buf[text->undo_pos]; text->undo_pos--;
1868                         charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1869                         //first postion to be selected
1870                         text->curc = charp;
1871                         text->curl = text->lines.first;
1872                         for (i = 0; i < linep; i++) {
1873                                 text->curl = text->curl->next;
1874                         }
1875
1876                         
1877                         if (op==UNDO_INDENT) {
1878                                 unindent(text);
1879                         } else if (op== UNDO_UNINDENT) {
1880                                 indent(text);
1881                         } else if (op == UNDO_COMMENT) {
1882                                 uncomment(text);
1883                         } else if (op == UNDO_UNCOMMENT) {
1884                                 comment(text);
1885                         }
1886
1887                         text->undo_pos--;
1888                         break;
1889                 default:
1890                         //XXX error("Undo buffer error - resetting");
1891                         text->undo_pos= -1;
1892                         
1893                         break;
1894         }
1895
1896         /* next undo step may need evaluating */
1897         if (text->undo_pos>=0) {
1898                 switch (text->undo_buf[text->undo_pos]) {
1899                         case UNDO_STO:
1900                                 txt_do_undo(text);
1901                                 txt_do_redo(text); /* selections need restoring */
1902                                 break;
1903                         case UNDO_SWAP:
1904                                 txt_do_undo(text); /* swaps should appear transparent */
1905                                 break;
1906                 }
1907         }
1908         
1909         undoing= 0;     
1910 }
1911
1912 void txt_do_redo(Text *text)
1913 {
1914         char op;
1915         unsigned int linep, i;
1916         unsigned short charp;
1917         char *buf;
1918         
1919         text->undo_pos++;       
1920         op= text->undo_buf[text->undo_pos];
1921         
1922         if (!op) {
1923                 text->undo_pos--;
1924                 return;
1925         }
1926         
1927         undoing= 1;
1928
1929         switch(op) {
1930                 case UNDO_CLEFT:
1931                         txt_move_left(text, 0);
1932                         break;
1933                         
1934                 case UNDO_CRIGHT:
1935                         txt_move_right(text, 0);
1936                         break;
1937                         
1938                 case UNDO_CUP:
1939                         txt_move_up(text, 0);
1940                         break;
1941                         
1942                 case UNDO_CDOWN:
1943                         txt_move_down(text, 0);
1944                         break;
1945
1946                 case UNDO_SLEFT:
1947                         txt_move_left(text, 1);
1948                         break;
1949
1950                 case UNDO_SRIGHT:
1951                         txt_move_right(text, 1);
1952                         break;
1953
1954                 case UNDO_SUP:
1955                         txt_move_up(text, 1);
1956                         break;
1957
1958                 case UNDO_SDOWN:
1959                         txt_move_down(text, 1);
1960                         break;
1961                 
1962                 case UNDO_INSERT:
1963                         text->undo_pos++;
1964                         txt_add_char(text, text->undo_buf[text->undo_pos]);
1965                         text->undo_pos++;
1966                         break;
1967
1968                 case UNDO_BS:
1969                         text->undo_pos++;
1970                         txt_backspace_char(text);
1971                         text->undo_pos++;
1972                         break;
1973
1974                 case UNDO_DEL:
1975                         text->undo_pos++;
1976                         txt_delete_char(text);
1977                         text->undo_pos++;
1978                         break;
1979
1980                 case UNDO_SWAP:
1981                         txt_curs_swap(text);
1982                         txt_do_redo(text); /* swaps should appear transparent a*/
1983                         break;
1984                         
1985                 case UNDO_CTO:
1986                 case UNDO_STO:
1987                         text->undo_pos++;
1988                         text->undo_pos++;
1989
1990                         text->undo_pos++;
1991                         text->undo_pos++;
1992                         text->undo_pos++;
1993                         text->undo_pos++;
1994
1995                         text->undo_pos++;
1996
1997                         charp= text->undo_buf[text->undo_pos];
1998                         text->undo_pos++;
1999                         charp= charp+(text->undo_buf[text->undo_pos]<<8);
2000
2001                         text->undo_pos++;
2002                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2003                         linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2004                         linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2005                         linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2006                         
2007                         if (op==UNDO_CTO) {
2008                                 txt_move_toline(text, linep, 0);
2009                                 text->curc= charp;
2010                                 txt_pop_sel(text);
2011                         } else {
2012                                 txt_move_toline(text, linep, 1);
2013                                 text->selc= charp;
2014                         }
2015
2016                         break;
2017
2018                 case UNDO_DBLOCK:
2019                         text->undo_pos++;
2020                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2021                         linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2022                         linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2023                         linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2024
2025                         txt_delete_sel(text);
2026                         text->undo_pos+=linep;
2027
2028                         text->undo_pos++;
2029                         text->undo_pos++;
2030                         text->undo_pos++; 
2031                         text->undo_pos++;
2032                         
2033                         break;
2034
2035                 case UNDO_IBLOCK:
2036                         text->undo_pos++;
2037                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2038                         linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2039                         linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2040                         linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2041
2042                         buf= MEM_mallocN(linep+1, "iblock buffer");
2043                         memcpy (buf, &text->undo_buf[text->undo_pos], linep);
2044                         text->undo_pos+= linep;
2045                         buf[linep]= 0;
2046                         
2047                         txt_insert_buf(text, buf);                      
2048                         MEM_freeN(buf);
2049
2050                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2051                         linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2052                         linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2053                         linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2054
2055                         break;
2056                 case UNDO_INDENT:
2057                 case UNDO_UNINDENT:
2058                 case UNDO_COMMENT:
2059                 case UNDO_UNCOMMENT:
2060                         text->undo_pos++;
2061                         charp = text->undo_buf[text->undo_pos]; text->undo_pos++;
2062                         charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2063                         //charp is the first char selected or 0
2064                         
2065                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2066                         linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2067                         linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2068                         linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2069                         //linep is now the first line of the selection                  
2070                         //set the selcetion for this now
2071                         text->curc = charp;
2072                         text->curl = text->lines.first;
2073                         for (i= 0; i < linep; i++) {
2074                                 text->curl = text->curl->next;
2075                         }
2076                         
2077                         charp = text->undo_buf[text->undo_pos]; text->undo_pos++;
2078                         charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2079                         //last postion to be selected
2080                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2081                         linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2082                         linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2083                         linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2084                         //Last line to be selected
2085                         
2086                         text->selc = charp;
2087                         text->sell = text->lines.first;
2088                         for (i = 0; i < linep; i++) {
2089                                 text->sell = text->sell->next;
2090                         }
2091
2092                         if (op==UNDO_INDENT) {
2093                                 indent(text);
2094                         } else if (op== UNDO_UNINDENT) {
2095                                 unindent(text);
2096                         } else if (op == UNDO_COMMENT) {
2097                                 comment(text);
2098                         } else if (op == UNDO_UNCOMMENT) {
2099                                 uncomment(text);
2100                         }
2101                         break;
2102                 default:
2103                         //XXX error("Undo buffer error - resetting");
2104                         text->undo_pos= -1;
2105
2106                         break;
2107         }
2108         
2109         undoing= 0;     
2110 }
2111
2112 /**************************/
2113 /* Line editing functions */ 
2114 /**************************/
2115
2116 void txt_split_curline (Text *text) 
2117 {
2118         TextLine *ins;
2119         TextMarker *mrk;
2120         char *left, *right;
2121         int lineno= -1;
2122         
2123         if (!text) return;
2124         if (!text->curl) return;
2125
2126         txt_delete_sel(text);
2127
2128         /* Move markers */
2129
2130         lineno= txt_get_span(text->lines.first, text->curl);
2131         mrk= text->markers.first;
2132         while (mrk) {
2133                 if (mrk->lineno==lineno && mrk->start>text->curc) {
2134                         mrk->lineno++;
2135                         mrk->start -= text->curc;
2136                         mrk->end -= text->curc;
2137                 } else if (mrk->lineno > lineno) {
2138                         mrk->lineno++;
2139                 }
2140                 mrk= mrk->next;
2141         }
2142
2143         /* Make the two half strings */
2144
2145         left= MEM_mallocN(text->curc+1, "textline_string");
2146         if (text->curc) memcpy(left, text->curl->line, text->curc);
2147         left[text->curc]=0;
2148         
2149         right= MEM_mallocN(text->curl->len - text->curc+1, "textline_string");
2150         if (text->curl->len - text->curc) memcpy(right, text->curl->line+text->curc, text->curl->len-text->curc);
2151         right[text->curl->len - text->curc]=0;
2152
2153         MEM_freeN(text->curl->line);
2154         if (text->curl->format) MEM_freeN(text->curl->format);
2155
2156         /* Make the new TextLine */
2157         
2158         ins= MEM_mallocN(sizeof(TextLine), "textline");
2159         ins->line= left;
2160         ins->format= NULL;
2161         ins->len= text->curc;
2162         
2163         text->curl->line= right;
2164         text->curl->format= NULL;
2165         text->curl->len= text->curl->len - text->curc;
2166         
2167         BLI_insertlinkbefore(&text->lines, text->curl, ins);    
2168         
2169         text->curc=0;
2170         
2171         txt_make_dirty(text);
2172         txt_clean_text(text);
2173         
2174         txt_pop_sel(text);
2175         if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, '\n');
2176 }
2177
2178 static void txt_delete_line (Text *text, TextLine *line) 
2179 {
2180         TextMarker *mrk=NULL, *nxt;
2181         int lineno= -1;
2182
2183         if (!text) return;
2184         if (!text->curl) return;
2185
2186         lineno= txt_get_span(text->lines.first, line);
2187         mrk= text->markers.first;
2188         while (mrk) {
2189                 nxt= mrk->next;
2190                 if (mrk->lineno==lineno)
2191                         BLI_freelinkN(&text->markers, mrk);
2192                 else if (mrk->lineno > lineno)
2193                         mrk->lineno--;
2194                 mrk= nxt;
2195         }
2196
2197         BLI_remlink (&text->lines, line);
2198         
2199         if (line->line) MEM_freeN(line->line);
2200         if (line->format) MEM_freeN(line->format);
2201
2202         MEM_freeN(line);
2203
2204         txt_make_dirty(text);
2205         txt_clean_text(text);
2206 }
2207
2208 static void txt_combine_lines (Text *text, TextLine *linea, TextLine *lineb)
2209 {
2210         char *tmp;
2211         TextMarker *mrk= NULL;
2212         int lineno=-1;
2213         
2214         if (!text) return;
2215         
2216         if(!linea || !lineb) return;
2217
2218         mrk= txt_find_marker_region(text, lineb, 0, lineb->len, 0, 0);
2219         if (mrk) {
2220                 lineno= mrk->lineno;
2221                 do {
2222                         mrk->lineno--;
2223                         mrk->start += linea->len;
2224                         mrk->end += linea->len;
2225                         mrk= mrk->next;
2226                 } while (mrk && mrk->lineno==lineno);
2227         }
2228         if (lineno==-1) lineno= txt_get_span(text->lines.first, lineb);
2229         if (!mrk) mrk= text->markers.first;
2230         
2231         tmp= MEM_mallocN(linea->len+lineb->len+1, "textline_string");
2232         
2233         strcpy(tmp, linea->line);
2234         strcat(tmp, lineb->line);
2235
2236         make_new_line(linea, tmp);
2237         
2238         txt_delete_line(text, lineb);
2239         
2240         txt_make_dirty(text);
2241         txt_clean_text(text);
2242 }
2243
2244 void txt_delete_char (Text *text) 
2245 {
2246         char c='\n';
2247         
2248         if (!text) return;
2249         if (!text->curl) return;
2250
2251         if (txt_has_sel(text)) { /* deleting a selection */
2252                 txt_delete_sel(text);
2253                 txt_make_dirty(text);
2254                 return;
2255         }
2256         else if (text->curc== text->curl->len) { /* Appending two lines */
2257                 if (text->curl->next) {
2258                         txt_combine_lines(text, text->curl, text->curl->next);
2259                         txt_pop_sel(text);
2260                 }
2261         } else { /* Just deleting a char */
2262                 int i= text->curc;
2263
2264                 TextMarker *mrk= txt_find_marker_region(text, text->curl, i-1, text->curl->len, 0, 0);
2265                 if (mrk) {
2266                         int lineno= mrk->lineno;
2267                         if (mrk->end==i) {
2268                                 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
2269                                         txt_clear_markers(text, mrk->group, TMARK_TEMP);
2270                                 } else {
2271                                         BLI_freelinkN(&text->markers, mrk);
2272                                 }
2273                                 return;
2274                         }
2275                         do {
2276                                 if (mrk->start>i) mrk->start--;
2277                                 mrk->end--;
2278                                 mrk= mrk->next;
2279                         } while (mrk && mrk->lineno==lineno);
2280                 }
2281                 
2282                 c= text->curl->line[i];
2283                 while(i< text->curl->len) {
2284                         text->curl->line[i]= text->curl->line[i+1];
2285                         i++;
2286                 }
2287                 text->curl->len--;
2288
2289                 txt_pop_sel(text);
2290         }
2291
2292         txt_make_dirty(text);
2293         txt_clean_text(text);
2294         
2295         if(!undoing) txt_undo_add_charop(text, UNDO_DEL, c);
2296 }
2297
2298 void txt_delete_word (Text *text) 
2299 {
2300         txt_jump_right(text, 1);
2301         txt_delete_sel(text);
2302 }
2303
2304 void txt_backspace_char (Text *text) 
2305 {
2306         char c='\n';
2307         
2308         if (!text) return;
2309         if (!text->curl) return;
2310         
2311         if (txt_has_sel(text)) { /* deleting a selection */
2312                 txt_delete_sel(text);
2313                 txt_make_dirty(text);
2314                 return;
2315         }
2316         else if (text->curc==0) { /* Appending two lines */
2317                 if (!text->curl->prev) return;
2318                 
2319                 text->curl= text->curl->prev;
2320                 text->curc= text->curl->len;
2321                 
2322                 txt_combine_lines(text, text->curl, text->curl->next);
2323                 txt_pop_sel(text);
2324         }
2325         else { /* Just backspacing a char */
2326                 int i= text->curc-1;
2327
2328                 TextMarker *mrk= txt_find_marker_region(text, text->curl, i, text->curl->len, 0, 0);
2329                 if (mrk) {
2330                         int lineno= mrk->lineno;
2331                         if (mrk->start==i+1) {
2332                                 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
2333                                         txt_clear_markers(text, mrk->group, TMARK_TEMP);
2334                                 } else {
2335                                         BLI_freelinkN(&text->markers, mrk);
2336                                 }
2337                                 return;
2338                         }
2339                         do {
2340                                 if (mrk->start>i) mrk->start--;
2341                                 mrk->end--;
2342                                 mrk= mrk->next;
2343                         } while (mrk && mrk->lineno==lineno);
2344                 }
2345                 
2346                 c= text->curl->line[i];
2347                 while(i< text->curl->len) {
2348                         text->curl->line[i]= text->curl->line[i+1];
2349                         i++;
2350                 }
2351                 text->curl->len--;
2352                 text->curc--;
2353
2354                 txt_pop_sel(text);
2355         }
2356
2357         txt_make_dirty(text);
2358         txt_clean_text(text);
2359         
2360         if(!undoing) txt_undo_add_charop(text, UNDO_BS, c);
2361 }
2362
2363 void txt_backspace_word (Text *text) 
2364 {
2365         txt_jump_left(text, 1);
2366         txt_delete_sel(text);
2367 }
2368
2369 /* Max spaces to replace a tab with, currently hardcoded to TXT_TABSIZE = 4.
2370  * Used by txt_convert_tab_to_spaces, indent and unintent.
2371  * Remember to change this string according to max tab size */
2372 static char tab_to_spaces[] = "    ";
2373
2374 static void txt_convert_tab_to_spaces (Text *text)
2375 {
2376         /* sb aims to pad adjust the tab-width needed so that the right number of spaces
2377          * is added so that the indention of the line is the right width (i.e. aligned
2378          * to multiples of TXT_TABSIZE)
2379          */
2380         char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE];
2381         txt_insert_buf(text, sb);
2382 }
2383
2384 int txt_add_char (Text *text, char add) 
2385 {
2386         int len, lineno;
2387         char *tmp;
2388         TextMarker *mrk;
2389         
2390         if (!text) return 0;
2391         if (!text->curl) return 0;
2392
2393         if (add=='\n') {
2394                 txt_split_curline(text);
2395                 return 1;
2396         }
2397         
2398         /* insert spaces rather then tabs */
2399         if (add == '\t' && text->flags & TXT_TABSTOSPACES) {
2400                 txt_convert_tab_to_spaces(text);
2401                 return 1;
2402         }
2403
2404         txt_delete_sel(text);
2405         
2406         mrk= txt_find_marker_region(text, text->curl, text->curc-1, text->curl->len, 0, 0);
2407         if (mrk) {
2408                 lineno= mrk->lineno;
2409                 do {
2410                         if (mrk->start>text->curc) mrk->start++;
2411                         mrk->end++;
2412                         mrk= mrk->next;
2413                 } while (mrk && mrk->lineno==lineno);
2414         }
2415         
2416         tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2417         
2418         if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2419         tmp[text->curc]= add;
2420         
2421         len= text->curl->len - text->curc;
2422         if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2423         tmp[text->curl->len+1]=0;
2424         make_new_line(text->curl, tmp);
2425                 
2426         text->curc++;
2427
2428         txt_pop_sel(text);
2429         
2430         txt_make_dirty(text);
2431         txt_clean_text(text);
2432
2433         if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, add);
2434         return 1;
2435 }
2436
2437 void txt_delete_selected(Text *text)
2438 {
2439         txt_delete_sel(text);
2440         txt_make_dirty(text);
2441 }
2442
2443 int txt_replace_char (Text *text, char add)
2444 {
2445         char del;
2446         
2447         if (!text) return 0;
2448         if (!text->curl) return 0;
2449
2450         /* If text is selected or we're at the end of the line just use txt_add_char */
2451         if (text->curc==text->curl->len || txt_has_sel(text) || add=='\n') {
2452                 TextMarker *mrk;
2453                 int i= txt_add_char(text, add);
2454                 mrk= txt_find_marker(text, text->curl, text->curc, 0, 0);
2455                 if (mrk && mrk->end==text->curc) mrk->end--;
2456                 return i;
2457         }
2458         
2459         del= text->curl->line[text->curc];
2460         text->curl->line[text->curc]= (unsigned char) add;
2461         text->curc++;
2462         txt_pop_sel(text);
2463         
2464         txt_make_dirty(text);
2465         txt_clean_text(text);
2466
2467         /* Should probably create a new op for this */
2468         if(!undoing) {
2469                 txt_undo_add_charop(text, UNDO_DEL, del);
2470                 txt_undo_add_charop(text, UNDO_INSERT, add);
2471         }
2472         return 1;
2473 }
2474
2475 void indent(Text *text)
2476 {
2477         int len, num;
2478         char *tmp;
2479
2480         char *add = "\t";
2481         int indentlen = 1;
2482         
2483         /* hardcoded: TXT_TABSIZE = 4 spaces: */
2484         int spaceslen = TXT_TABSIZE;
2485
2486         /* insert spaces rather then tabs */
2487         if (text->flags & TXT_TABSTOSPACES){
2488                 add = tab_to_spaces;
2489                 indentlen = spaceslen;
2490         }
2491         
2492         if (!text) return;
2493         if (!text->curl) return;
2494         if (!text->sell) return;
2495
2496         num = 0;
2497         while (TRUE)
2498         {
2499                 tmp= MEM_mallocN(text->curl->len+indentlen+1, "textline_string");
2500                 
2501                 text->curc = 0; 
2502                 if(text->curc) memcpy(tmp, text->curl->line, text->curc); /* XXX never true, check prev line */
2503                 memcpy(tmp+text->curc, add, indentlen);
2504                 
2505                 len= text->curl->len - text->curc;
2506                 if(len>0) memcpy(tmp+text->curc+indentlen, text->curl->line+text->curc, len);
2507                 tmp[text->curl->len+indentlen]= 0;
2508
2509                 make_new_line(text->curl, tmp);
2510                         
2511                 text->curc+= indentlen;
2512                 
2513                 txt_make_dirty(text);
2514                 txt_clean_text(text);
2515                 
2516                 if(text->curl == text->sell) 
2517                 {
2518                         text->selc = text->sell->len;
2519                         break;
2520                 } else {
2521                         text->curl = text->curl->next;
2522                         num++;
2523                 }
2524         }
2525         text->curc = 0;
2526         while( num > 0 )
2527         {
2528                 text->curl = text->curl->prev;
2529                 num--;
2530         }
2531         
2532         if(!undoing) 
2533         {
2534                 txt_undo_add_toop(text, UNDO_INDENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
2535         }
2536 }
2537
2538 void unindent(Text *text)
2539 {
2540         int num = 0;
2541         char *remove = "\t";
2542         int indent = 1;
2543         
2544         /* hardcoded: TXT_TABSIZE = 4 spaces: */
2545         int spaceslen = TXT_TABSIZE;
2546
2547         /* insert spaces rather then tabs */
2548         if (text->flags & TXT_TABSTOSPACES){
2549                 remove = tab_to_spaces;
2550                 indent = spaceslen;
2551         }
2552
2553         if (!text) return;
2554         if (!text->curl) return;
2555         if (!text->sell) return;
2556
2557         while(TRUE)
2558         {
2559                 int i = 0;
2560                 
2561                 if (BLI_strncasecmp(text->curl->line, remove, indent) == 0)
2562                 {
2563                         while(i< text->curl->len) {
2564                                 text->curl->line[i]= text->curl->line[i+indent];
2565                                 i++;
2566                         }
2567                         text->curl->len-= indent;
2568                 }
2569         
2570                 txt_make_dirty(text);
2571                 txt_clean_text(text);
2572                 
2573                 if(text->curl == text->sell) 
2574                 {
2575                         text->selc = text->sell->len;
2576                         break;
2577                 } else {
2578                         text->curl = text->curl->next;
2579                         num++;
2580                 }
2581                 
2582         }
2583         text->curc = 0;
2584         while( num > 0 )
2585         {
2586                 text->curl = text->curl->prev;
2587                 num--;
2588         }
2589         
2590         if(!undoing) 
2591         {
2592                 txt_undo_add_toop(text, UNDO_UNINDENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
2593         }
2594 }
2595
2596 void comment(Text *text)
2597 {
2598         int len, num;
2599         char *tmp;
2600         char add = '#';
2601         
2602         if (!text) return;
2603         if (!text->curl) return;
2604         if (!text->sell) return;// Need to change this need to check if only one line is selected ot more then one
2605
2606         num = 0;
2607         while (TRUE)
2608         {
2609                 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2610                 
2611                 text->curc = 0; 
2612                 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2613                 tmp[text->curc]= add;
2614                 
2615                 len= text->curl->len - text->curc;
2616                 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2617                 tmp[text->curl->len+1]=0;
2618
2619                 make_new_line(text->curl, tmp);
2620                         
2621                 text->curc++;
2622                 
2623                 txt_make_dirty(text);
2624                 txt_clean_text(text);
2625                 
2626                 if(text->curl == text->sell) 
2627                 {
2628                         text->selc = text->sell->len;
2629                         break;
2630                 } else {
2631                         text->curl = text->curl->next;
2632                         num++;
2633                 }
2634         }
2635         text->curc = 0;
2636         while( num > 0 )
2637         {
2638                 text->curl = text->curl->prev;
2639                 num--;
2640         }
2641         
2642         if(!undoing) 
2643         {
2644                 txt_undo_add_toop(text, UNDO_COMMENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
2645         }
2646 }
2647
2648 void uncomment(Text *text)
2649 {
2650         int num = 0;
2651         char remove = '#';
2652         
2653         if (!text) return;
2654         if (!text->curl) return;
2655         if (!text->sell) return;
2656
2657         while(TRUE)
2658         {
2659                 int i = 0;
2660                 
2661                 if (text->curl->line[i] == remove)
2662                 {
2663                         while(i< text->curl->len) {
2664                                 text->curl->line[i]= text->curl->line[i+1];
2665                                 i++;
2666                         }
2667                         text->curl->len--;
2668                 }
2669                          
2670         
2671                 txt_make_dirty(text);
2672                 txt_clean_text(text);
2673                 
2674                 if(text->curl == text->sell) 
2675                 {
2676                         text->selc = text->sell->len;
2677                         break;
2678                 } else {
2679                         text->curl = text->curl->next;
2680                         num++;
2681                 }
2682                 
2683         }
2684         text->curc = 0;
2685         while( num > 0 )
2686         {
2687                 text->curl = text->curl->prev;
2688                 num--;
2689         }
2690         
2691         if(!undoing) 
2692         {
2693                 txt_undo_add_toop(text, UNDO_UNCOMMENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
2694         }
2695 }
2696
2697 int setcurr_tab (Text *text)
2698 {
2699         int i = 0;
2700         int test = 0;
2701         char *word = ":";
2702         char *comm = "#";
2703         char back_words[4][7] = {"return", "break", "pass", "yield"};
2704         if (!text) return 0;
2705         if (!text->curl) return 0;
2706         
2707         while (text->curl->line[i] == '\t')
2708         {
2709                 //we only count thos tabs that are before any text or before the curs;
2710                 if (i == text->curc)
2711                 {
2712                         return i;
2713                 } else {
2714                         i++;
2715                 }
2716         }
2717         if(strstr(text->curl->line, word))
2718         {
2719                 //if we find a : then add a tab but not if it is in a comment
2720                 int a, indent = 0;
2721                 for(a=0; text->curl->line[a] != '\0'; a++)
2722                 {
2723                         if (text->curl->line[a]=='#') {
2724                                 break;
2725                         } else if (text->curl->line[a]==':') {
2726                                 indent = 1;
2727                         } else if (text->curl->line[a]==']') {
2728                                 indent = 0;
2729                         }
2730                 }
2731                 if (indent) {
2732                         i++;
2733                 }
2734         }
2735
2736         for(test=0; test < 4; test++)
2737         {
2738                 //if there are these 4 key words then remove a tab because we are done with the block
2739                 if(strstr(text->curl->line, back_words[test]) && i > 0)
2740                 {
2741                         if(strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm))
2742                         {
2743                                 i--;
2744                         }
2745                 }
2746         }
2747         return i;
2748 }
2749
2750 /*********************************/
2751 /* Text marker utility functions */
2752 /*********************************/
2753
2754 /* Creates and adds a marker to the list maintaining sorted order */
2755 void txt_add_marker(Text *text, TextLine *line, int start, int end, char color[4], int group, int flags) {
2756         TextMarker *tmp, *marker;
2757
2758         marker= MEM_mallocN(sizeof(TextMarker), "text_marker");
2759         
2760         marker->lineno= txt_get_span(text->lines.first, line);
2761         marker->start= MIN2(start, end);
2762         marker->end= MAX2(start, end);
2763         marker->group= group;
2764         marker->flags= flags;
2765
2766         marker->color[0]= color[0];
2767         marker->color[1]= color[1];
2768         marker->color[2]= color[2];
2769         marker->color[3]= color[3];
2770
2771         for (tmp=text->markers.last; tmp; tmp=tmp->prev)
2772                 if (tmp->lineno < marker->lineno || (tmp->lineno==marker->lineno && tmp->start < marker->start))
2773                         break;
2774
2775         if (tmp) BLI_insertlinkafter(&text->markers, tmp, marker);
2776         else BLI_addhead(&text->markers, marker);
2777 }
2778
2779 /* Returns the first matching marker on the specified line between two points.
2780    If the group or flags fields are non-zero the returned flag must be in the
2781    specified group and have at least the specified flags set. */
2782 TextMarker *txt_find_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
2783         TextMarker *marker, *next;
2784         int lineno= txt_get_span(text->lines.first, line);
2785         
2786         for (marker=text->markers.first; marker; marker=next) {
2787                 next= marker->next;
2788
2789                 if (group && marker->group != group) continue;
2790                 else if ((marker->flags & flags) != flags) continue;
2791                 else if (marker->lineno < lineno) continue;
2792                 else if (marker->lineno > lineno) break;
2793
2794                 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
2795                                 (marker->start<end && marker->end>start))
2796                         return marker;
2797         }
2798         return NULL;
2799 }
2800
2801 /* Clears all markers on the specified line between two points. If the group or
2802    flags fields are non-zero the returned flag must be in the specified group
2803    and have at least the specified flags set. */
2804 short txt_clear_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
2805         TextMarker *marker, *next;
2806         int lineno= txt_get_span(text->lines.first, line);
2807         short cleared= 0;
2808         
2809         for (marker=text->markers.first; marker; marker=next) {
2810                 next= marker->next;
2811
2812                 if (group && marker->group != group) continue;
2813                 else if ((marker->flags & flags) != flags) continue;
2814                 else if (marker->lineno < lineno) continue;
2815                 else if (marker->lineno > lineno) break;
2816
2817                 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
2818                         (marker->start<end && marker->end>start)) {
2819                         BLI_freelinkN(&text->markers, marker);
2820                         cleared= 1;
2821                 }
2822         }
2823         return cleared;
2824 }
2825
2826 /* Clears all markers in the specified group (if given) with at least the
2827    specified flags set. Useful for clearing temporary markers (group=0,
2828    flags=TMARK_TEMP) */
2829 short txt_clear_markers(Text *text, int group, int flags) {
2830         TextMarker *marker, *next;
2831         short cleared= 0;
2832         
2833         for (marker=text->markers.first; marker; marker=next) {
2834                 next= marker->next;
2835
2836                 if ((!group || marker->group==group) &&
2837                                 (marker->flags & flags) == flags) {
2838                         BLI_freelinkN(&text->markers, marker);
2839                         cleared= 1;
2840                 }
2841         }
2842         return cleared;
2843 }
2844
2845 /* Finds the marker at the specified line and cursor position with at least the
2846    specified flags set in the given group (if non-zero). */
2847 TextMarker *txt_find_marker(Text *text, TextLine *line, int curs, int group, int flags) {
2848         TextMarker *marker;
2849         int lineno= txt_get_span(text->lines.first, line);
2850         
2851         for (marker=text->markers.first; marker; marker=marker->next) {
2852                 if (group && marker->group != group) continue;
2853                 else if ((marker->flags & flags) != flags) continue;
2854                 else if (marker->lineno < lineno) continue;
2855                 else if (marker->lineno > lineno) break;
2856
2857                 if (marker->start <= curs && curs <= marker->end)
2858                         return marker;
2859         }
2860         return NULL;
2861 }
2862
2863 /* Finds the previous marker in the same group. If no other is found, the same
2864    marker will be returned */
2865 TextMarker *txt_prev_marker(Text *text, TextMarker *marker) {
2866         TextMarker *tmp= marker;
2867         while (tmp) {
2868                 if (tmp->prev) tmp= tmp->prev;
2869                 else tmp= text->markers.last;
2870                 if (tmp->group == marker->group)
2871                         return tmp;
2872         }
2873         return NULL; /* Only if marker==NULL */
2874 }
2875
2876 /* Finds the next marker in the same group. If no other is found, the same
2877    marker will be returned */
2878 TextMarker *txt_next_marker(Text *text, TextMarker *marker) {
2879         TextMarker *tmp= marker;
2880         while (tmp) {
2881                 if (tmp->next) tmp= tmp->next;
2882                 else tmp= text->markers.first;
2883                 if (tmp->group == marker->group)
2884                         return tmp;
2885         }
2886         return NULL; /* Only if marker==NULL */
2887 }
2888
2889
2890 /*******************************/
2891 /* Character utility functions */
2892 /*******************************/
2893
2894 int text_check_bracket(char ch)
2895 {
2896         int a;
2897         char opens[] = "([{";
2898         char close[] = ")]}";
2899
2900         for(a=0; a<(sizeof(opens)-1); a++) {
2901                 if(ch==opens[a])
2902                         return a+1;
2903                 else if(ch==close[a])
2904                         return -(a+1);
2905         }
2906         return 0;
2907 }
2908
2909 int text_check_delim(char ch)
2910 {
2911         int a;
2912         char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,";
2913
2914         for(a=0; a<(sizeof(delims)-1); a++) {
2915                 if(ch==delims[a])
2916                         return 1;
2917         }
2918         return 0;
2919 }
2920
2921 int text_check_digit(char ch)
2922 {
2923         if(ch < '0') return 0;
2924         if(ch <= '9') return 1;
2925         return 0;
2926 }
2927
2928 int text_check_identifier(char ch)
2929 {
2930         if(ch < '0') return 0;
2931         if(ch <= '9') return 1;
2932         if(ch < 'A') return 0;
2933         if(ch <= 'Z' || ch == '_') return 1;
2934         if(ch < 'a') return 0;
2935         if(ch <= 'z') return 1;
2936         return 0;
2937 }
2938
2939 int text_check_whitespace(char ch)
2940 {
2941         if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
2942                 return 1;
2943         return 0;
2944 }