|
Blender
V2.59
|
00001 /* text.c 00002 * 00003 * 00004 * $Id: text.c 38751 2011-07-27 06:55:20Z campbellbarton $ 00005 * 00006 * ***** BEGIN GPL LICENSE BLOCK ***** 00007 * 00008 * This program is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU General Public License 00010 * as published by the Free Software Foundation; either version 2 00011 * of the License, or (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software Foundation, 00020 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00021 * 00022 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00023 * All rights reserved. 00024 * 00025 * The Original Code is: all of this file. 00026 * 00027 * Contributor(s): none yet. 00028 * 00029 * ***** END GPL LICENSE BLOCK ***** 00030 */ 00031 00037 #include <string.h> /* strstr */ 00038 #include <sys/types.h> 00039 #include <sys/stat.h> 00040 00041 #include "MEM_guardedalloc.h" 00042 00043 #include "BLI_blenlib.h" 00044 #include "BLI_utildefines.h" 00045 00046 #include "DNA_constraint_types.h" 00047 #include "DNA_controller_types.h" 00048 #include "DNA_scene_types.h" 00049 #include "DNA_screen_types.h" 00050 #include "DNA_space_types.h" 00051 #include "DNA_text_types.h" 00052 #include "DNA_userdef_types.h" 00053 #include "DNA_object_types.h" 00054 00055 #include "BKE_depsgraph.h" 00056 #include "BKE_global.h" 00057 #include "BKE_library.h" 00058 #include "BKE_main.h" 00059 #include "BKE_text.h" 00060 00061 00062 #ifdef WITH_PYTHON 00063 #include "BPY_extern.h" 00064 #endif 00065 00066 /***************/ /* 00067 00068 How Texts should work 00069 -- 00070 A text should relate to a file as follows - 00071 (Text *)->name should be the place where the 00072 file will or has been saved. 00073 00074 (Text *)->flags has the following bits 00075 TXT_ISDIRTY - should always be set if the file in mem. differs from 00076 the file on disk, or if there is no file on disk. 00077 TXT_ISMEM - should always be set if the Text has not been mapped to 00078 a file, in which case (Text *)->name may be NULL or garbage. 00079 TXT_ISEXT - should always be set if the Text is not to be written into 00080 the .blend 00081 TXT_ISSCRIPT - should be set if the user has designated the text 00082 as a script. (NEW: this was unused, but now it is needed by 00083 space handler script links (see header_view3d.c, for example) 00084 00085 ->>> see also: /makesdna/DNA_text_types.h 00086 00087 Display 00088 -- 00089 The st->top determines at what line the top of the text is displayed. 00090 If the user moves the cursor the st containing that cursor should 00091 be popped ... other st's retain their own top location. 00092 00093 Markers 00094 -- 00095 The mrk->flags define the behaviour and relationships between markers. The 00096 upper two bytes are used to hold a group ID, the lower two are normal flags. If 00097 TMARK_EDITALL is set the group ID defines which other markers should be edited. 00098 00099 The mrk->clr field is used to visually group markers where the flags may not 00100 match. A template system, for example, may allow editing of repeating tokens 00101 (in one group) but include other marked positions (in another group) all in the 00102 same template with the same color. 00103 00104 Undo 00105 -- 00106 Undo/Redo works by storing 00107 events in a queue, and a pointer 00108 to the current position in the 00109 queue... 00110 00111 Events are stored using an 00112 arbitrary op-code system 00113 to keep track of 00114 a) the two cursors (normal and selected) 00115 b) input (visible and control (ie backspace)) 00116 00117 input data is stored as its 00118 ASCII value, the opcodes are 00119 then selected to not conflict. 00120 00121 opcodes with data in between are 00122 written at the beginning and end 00123 of the data to allow undo and redo 00124 to simply check the code at the current 00125 undo position 00126 00127 */ /***************/ 00128 00129 /***/ 00130 00131 static void txt_pop_first(Text *text); 00132 static void txt_pop_last(Text *text); 00133 static void txt_undo_add_op(Text *text, int op); 00134 static void txt_undo_add_block(Text *text, int op, const char *buf); 00135 static void txt_delete_line(Text *text, TextLine *line); 00136 static void txt_delete_sel (Text *text); 00137 static void txt_make_dirty (Text *text); 00138 00139 /***/ 00140 00141 static unsigned char undoing; 00142 00143 /* allow to switch off undoing externally */ 00144 void txt_set_undostate(int u) 00145 { 00146 undoing = u; 00147 } 00148 00149 int txt_get_undostate(void) 00150 { 00151 return undoing; 00152 } 00153 00154 static void init_undo_text(Text *text) 00155 { 00156 text->undo_pos= -1; 00157 text->undo_len= TXT_INIT_UNDO; 00158 text->undo_buf= MEM_mallocN(text->undo_len, "undo buf"); 00159 } 00160 00161 void free_text(Text *text) 00162 { 00163 TextLine *tmp; 00164 00165 for (tmp= text->lines.first; tmp; tmp= tmp->next) { 00166 MEM_freeN(tmp->line); 00167 if (tmp->format) 00168 MEM_freeN(tmp->format); 00169 } 00170 00171 BLI_freelistN(&text->lines); 00172 BLI_freelistN(&text->markers); 00173 00174 if(text->name) MEM_freeN(text->name); 00175 MEM_freeN(text->undo_buf); 00176 #ifdef WITH_PYTHON 00177 if (text->compiled) BPY_text_free_code(text); 00178 #endif 00179 } 00180 00181 Text *add_empty_text(const char *name) 00182 { 00183 Main *bmain= G.main; 00184 Text *ta; 00185 TextLine *tmp; 00186 00187 ta= alloc_libblock(&bmain->text, ID_TXT, name); 00188 ta->id.us= 1; 00189 00190 ta->name= NULL; 00191 00192 init_undo_text(ta); 00193 00194 ta->nlines=1; 00195 ta->flags= TXT_ISDIRTY | TXT_ISMEM; 00196 if((U.flag & USER_TXT_TABSTOSPACES_DISABLE)==0) 00197 ta->flags |= TXT_TABSTOSPACES; 00198 00199 ta->lines.first= ta->lines.last= NULL; 00200 ta->markers.first= ta->markers.last= NULL; 00201 00202 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); 00203 tmp->line= (char*) MEM_mallocN(1, "textline_string"); 00204 tmp->format= NULL; 00205 00206 tmp->line[0]=0; 00207 tmp->len= 0; 00208 00209 tmp->next= NULL; 00210 tmp->prev= NULL; 00211 00212 BLI_addhead(&ta->lines, tmp); 00213 00214 ta->curl= ta->lines.first; 00215 ta->curc= 0; 00216 ta->sell= ta->lines.first; 00217 ta->selc= 0; 00218 00219 return ta; 00220 } 00221 00222 // this function removes any control characters from 00223 // a textline 00224 00225 static void cleanup_textline(TextLine * tl) 00226 { 00227 int i; 00228 00229 for (i = 0; i < tl->len; i++ ) { 00230 if (tl->line[i] < ' ' && tl->line[i] != '\t') { 00231 memmove(tl->line + i, tl->line + i + 1, tl->len - i); 00232 tl->len--; 00233 i--; 00234 } 00235 } 00236 } 00237 00238 int reopen_text(Text *text) 00239 { 00240 FILE *fp; 00241 int i, llen, len; 00242 unsigned char *buffer; 00243 TextLine *tmp; 00244 char str[FILE_MAXDIR+FILE_MAXFILE]; 00245 struct stat st; 00246 00247 if (!text || !text->name) return 0; 00248 00249 BLI_strncpy(str, text->name, FILE_MAXDIR+FILE_MAXFILE); 00250 BLI_path_abs(str, G.main->name); 00251 00252 fp= fopen(str, "r"); 00253 if(fp==NULL) return 0; 00254 00255 /* free memory: */ 00256 00257 for (tmp= text->lines.first; tmp; tmp= tmp->next) { 00258 MEM_freeN(tmp->line); 00259 if (tmp->format) MEM_freeN(tmp->format); 00260 } 00261 00262 BLI_freelistN(&text->lines); 00263 00264 text->lines.first= text->lines.last= NULL; 00265 text->curl= text->sell= NULL; 00266 00267 /* clear undo buffer */ 00268 MEM_freeN(text->undo_buf); 00269 init_undo_text(text); 00270 00271 fseek(fp, 0L, SEEK_END); 00272 len= ftell(fp); 00273 fseek(fp, 0L, SEEK_SET); 00274 00275 text->undo_pos= -1; 00276 00277 buffer= MEM_mallocN(len, "text_buffer"); 00278 // under windows fread can return less then len bytes because 00279 // of CR stripping 00280 len = fread(buffer, 1, len, fp); 00281 00282 fclose(fp); 00283 00284 stat(str, &st); 00285 text->mtime= st.st_mtime; 00286 00287 text->nlines=0; 00288 llen=0; 00289 for(i=0; i<len; i++) { 00290 if (buffer[i]=='\n') { 00291 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); 00292 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string"); 00293 tmp->format= NULL; 00294 00295 if(llen) memcpy(tmp->line, &buffer[i-llen], llen); 00296 tmp->line[llen]=0; 00297 tmp->len= llen; 00298 00299 cleanup_textline(tmp); 00300 00301 BLI_addtail(&text->lines, tmp); 00302 text->nlines++; 00303 00304 llen=0; 00305 continue; 00306 } 00307 llen++; 00308 } 00309 00310 if (llen!=0 || text->nlines==0) { 00311 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); 00312 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string"); 00313 tmp->format= NULL; 00314 00315 if(llen) memcpy(tmp->line, &buffer[i-llen], llen); 00316 00317 tmp->line[llen]=0; 00318 tmp->len= llen; 00319 00320 cleanup_textline(tmp); 00321 00322 BLI_addtail(&text->lines, tmp); 00323 text->nlines++; 00324 } 00325 00326 text->curl= text->sell= text->lines.first; 00327 text->curc= text->selc= 0; 00328 00329 MEM_freeN(buffer); 00330 return 1; 00331 } 00332 00333 Text *add_text(const char *file, const char *relpath) 00334 { 00335 Main *bmain= G.main; 00336 FILE *fp; 00337 int i, llen, len; 00338 unsigned char *buffer; 00339 TextLine *tmp; 00340 Text *ta; 00341 char str[FILE_MAXDIR+FILE_MAXFILE]; 00342 struct stat st; 00343 00344 BLI_strncpy(str, file, FILE_MAXDIR+FILE_MAXFILE); 00345 if (relpath) /* can be NULL (bg mode) */ 00346 BLI_path_abs(str, relpath); 00347 00348 fp= fopen(str, "r"); 00349 if(fp==NULL) return NULL; 00350 00351 ta= alloc_libblock(&bmain->text, ID_TXT, BLI_path_basename(str)); 00352 ta->id.us= 1; 00353 00354 ta->lines.first= ta->lines.last= NULL; 00355 ta->markers.first= ta->markers.last= NULL; 00356 ta->curl= ta->sell= NULL; 00357 00358 if((U.flag & USER_TXT_TABSTOSPACES_DISABLE)==0) 00359 ta->flags= TXT_TABSTOSPACES; 00360 00361 fseek(fp, 0L, SEEK_END); 00362 len= ftell(fp); 00363 fseek(fp, 0L, SEEK_SET); 00364 00365 ta->name= MEM_mallocN(strlen(file)+1, "text_name"); 00366 strcpy(ta->name, file); 00367 00368 init_undo_text(ta); 00369 00370 buffer= MEM_mallocN(len, "text_buffer"); 00371 // under windows fread can return less then len bytes because 00372 // of CR stripping 00373 len = fread(buffer, 1, len, fp); 00374 00375 fclose(fp); 00376 00377 stat(str, &st); 00378 ta->mtime= st.st_mtime; 00379 00380 ta->nlines=0; 00381 llen=0; 00382 for(i=0; i<len; i++) { 00383 if (buffer[i]=='\n') { 00384 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); 00385 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string"); 00386 tmp->format= NULL; 00387 00388 if(llen) memcpy(tmp->line, &buffer[i-llen], llen); 00389 tmp->line[llen]=0; 00390 tmp->len= llen; 00391 00392 cleanup_textline(tmp); 00393 00394 BLI_addtail(&ta->lines, tmp); 00395 ta->nlines++; 00396 00397 llen=0; 00398 continue; 00399 } 00400 llen++; 00401 } 00402 00403 /* create new line in cases: 00404 - rest of line (if last line in file hasn't got \n terminator). 00405 in this case content of such line would be used to fill text line buffer 00406 - file is empty. in this case new line is needed to start editing from. 00407 - last characted in buffer is \n. in this case new line is needed to 00408 deal with newline at end of file. (see [#28087]) (sergey) */ 00409 if (llen!=0 || ta->nlines==0 || buffer[len-1]=='\n') { 00410 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); 00411 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string"); 00412 tmp->format= NULL; 00413 00414 if(llen) memcpy(tmp->line, &buffer[i-llen], llen); 00415 00416 tmp->line[llen]=0; 00417 tmp->len= llen; 00418 00419 cleanup_textline(tmp); 00420 00421 BLI_addtail(&ta->lines, tmp); 00422 ta->nlines++; 00423 } 00424 00425 ta->curl= ta->sell= ta->lines.first; 00426 ta->curc= ta->selc= 0; 00427 00428 MEM_freeN(buffer); 00429 00430 return ta; 00431 } 00432 00433 Text *copy_text(Text *ta) 00434 { 00435 Text *tan; 00436 TextLine *line, *tmp; 00437 00438 tan= copy_libblock(ta); 00439 00440 /* file name can be NULL */ 00441 if(ta->name) { 00442 tan->name= MEM_mallocN(strlen(ta->name)+1, "text_name"); 00443 strcpy(tan->name, ta->name); 00444 } 00445 else { 00446 tan->name= NULL; 00447 } 00448 00449 tan->flags = ta->flags | TXT_ISDIRTY; 00450 00451 tan->lines.first= tan->lines.last= NULL; 00452 tan->markers.first= tan->markers.last= NULL; 00453 tan->curl= tan->sell= NULL; 00454 00455 tan->nlines= ta->nlines; 00456 00457 line= ta->lines.first; 00458 /* Walk down, reconstructing */ 00459 while (line) { 00460 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); 00461 tmp->line= MEM_mallocN(line->len+1, "textline_string"); 00462 tmp->format= NULL; 00463 00464 strcpy(tmp->line, line->line); 00465 00466 tmp->len= line->len; 00467 00468 BLI_addtail(&tan->lines, tmp); 00469 00470 line= line->next; 00471 } 00472 00473 tan->curl= tan->sell= tan->lines.first; 00474 tan->curc= tan->selc= 0; 00475 00476 init_undo_text(tan); 00477 00478 return tan; 00479 } 00480 00481 void unlink_text(Main *bmain, Text *text) 00482 { 00483 bScreen *scr; 00484 ScrArea *area; 00485 SpaceLink *sl; 00486 Scene *scene; 00487 Object *ob; 00488 bController *cont; 00489 bConstraint *con; 00490 short update; 00491 00492 /* dome */ 00493 for(scene=bmain->scene.first; scene; scene=scene->id.next) 00494 if(scene->r.dometext == text) 00495 scene->r.dometext = NULL; 00496 00497 for(ob=bmain->object.first; ob; ob=ob->id.next) { 00498 /* game controllers */ 00499 for(cont=ob->controllers.first; cont; cont=cont->next) { 00500 if(cont->type==CONT_PYTHON) { 00501 bPythonCont *pc; 00502 00503 pc= cont->data; 00504 if(pc->text==text) pc->text= NULL; 00505 } 00506 } 00507 00508 /* pyconstraints */ 00509 update = 0; 00510 00511 if(ob->type==OB_ARMATURE && ob->pose) { 00512 bPoseChannel *pchan; 00513 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { 00514 for(con = pchan->constraints.first; con; con=con->next) { 00515 if(con->type==CONSTRAINT_TYPE_PYTHON) { 00516 bPythonConstraint *data = con->data; 00517 if (data->text==text) data->text = NULL; 00518 update = 1; 00519 00520 } 00521 } 00522 } 00523 } 00524 00525 for(con = ob->constraints.first; con; con=con->next) { 00526 if(con->type==CONSTRAINT_TYPE_PYTHON) { 00527 bPythonConstraint *data = con->data; 00528 if (data->text==text) data->text = NULL; 00529 update = 1; 00530 } 00531 } 00532 00533 if(update) 00534 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 00535 } 00536 00537 /* pynodes */ 00538 // XXX nodeDynamicUnlinkText(&text->id); 00539 00540 /* text space */ 00541 for(scr= bmain->screen.first; scr; scr= scr->id.next) { 00542 for(area= scr->areabase.first; area; area= area->next) { 00543 for(sl= area->spacedata.first; sl; sl= sl->next) { 00544 if(sl->spacetype==SPACE_TEXT) { 00545 SpaceText *st= (SpaceText*) sl; 00546 00547 if(st->text==text) { 00548 st->text= NULL; 00549 st->top= 0; 00550 } 00551 } 00552 } 00553 } 00554 } 00555 00556 text->id.us= 0; 00557 } 00558 00559 void clear_text(Text *text) /* called directly from rna */ 00560 { 00561 int oldstate; 00562 00563 oldstate = txt_get_undostate( ); 00564 txt_set_undostate( 1 ); 00565 txt_sel_all( text ); 00566 txt_delete_sel(text); 00567 txt_set_undostate( oldstate ); 00568 00569 txt_make_dirty(text); 00570 } 00571 00572 void write_text(Text *text, const char *str) /* called directly from rna */ 00573 { 00574 int oldstate; 00575 00576 oldstate = txt_get_undostate( ); 00577 txt_insert_buf( text, str ); 00578 txt_move_eof( text, 0 ); 00579 txt_set_undostate( oldstate ); 00580 00581 txt_make_dirty(text); 00582 } 00583 00584 /*****************************/ 00585 /* Editing utility functions */ 00586 /*****************************/ 00587 00588 static void make_new_line (TextLine *line, char *newline) 00589 { 00590 if (line->line) MEM_freeN(line->line); 00591 if (line->format) MEM_freeN(line->format); 00592 00593 line->line= newline; 00594 line->len= strlen(newline); 00595 line->format= NULL; 00596 } 00597 00598 static TextLine *txt_new_line(const char *str) 00599 { 00600 TextLine *tmp; 00601 00602 if(!str) str= ""; 00603 00604 tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline"); 00605 tmp->line= MEM_mallocN(strlen(str)+1, "textline_string"); 00606 tmp->format= NULL; 00607 00608 strcpy(tmp->line, str); 00609 00610 tmp->len= strlen(str); 00611 tmp->next= tmp->prev= NULL; 00612 00613 return tmp; 00614 } 00615 00616 static TextLine *txt_new_linen(const char *str, int n) 00617 { 00618 TextLine *tmp; 00619 00620 tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline"); 00621 tmp->line= MEM_mallocN(n+1, "textline_string"); 00622 tmp->format= NULL; 00623 00624 BLI_strncpy(tmp->line, (str)? str: "", n+1); 00625 00626 tmp->len= strlen(tmp->line); 00627 tmp->next= tmp->prev= NULL; 00628 00629 return tmp; 00630 } 00631 00632 void txt_clean_text (Text *text) 00633 { 00634 TextLine **top, **bot; 00635 00636 if (!text) return; 00637 00638 if (!text->lines.first) { 00639 if (text->lines.last) text->lines.first= text->lines.last; 00640 else text->lines.first= text->lines.last= txt_new_line(NULL); 00641 } 00642 00643 if (!text->lines.last) text->lines.last= text->lines.first; 00644 00645 top= (TextLine **) &text->lines.first; 00646 bot= (TextLine **) &text->lines.last; 00647 00648 while ((*top)->prev) *top= (*top)->prev; 00649 while ((*bot)->next) *bot= (*bot)->next; 00650 00651 if(!text->curl) { 00652 if(text->sell) text->curl= text->sell; 00653 else text->curl= text->lines.first; 00654 text->curc= 0; 00655 } 00656 00657 if(!text->sell) { 00658 text->sell= text->curl; 00659 text->selc= 0; 00660 } 00661 } 00662 00663 int txt_get_span (TextLine *from, TextLine *to) 00664 { 00665 int ret=0; 00666 TextLine *tmp= from; 00667 00668 if (!to || !from) return 0; 00669 if (from==to) return 0; 00670 00671 /* Look forwards */ 00672 while (tmp) { 00673 if (tmp == to) return ret; 00674 ret++; 00675 tmp= tmp->next; 00676 } 00677 00678 /* Look backwards */ 00679 if (!tmp) { 00680 tmp= from; 00681 ret=0; 00682 while(tmp) { 00683 if (tmp == to) break; 00684 ret--; 00685 tmp= tmp->prev; 00686 } 00687 if(!tmp) ret=0; 00688 } 00689 00690 return ret; 00691 } 00692 00693 static void txt_make_dirty (Text *text) 00694 { 00695 text->flags |= TXT_ISDIRTY; 00696 #ifdef WITH_PYTHON 00697 if (text->compiled) BPY_text_free_code(text); 00698 #endif 00699 } 00700 00701 /* 0:whitespace, 1:punct, 2:alphanumeric */ 00702 static short txt_char_type (char ch) 00703 { 00704 if (ch <= ' ') return 0; /* 32 */ 00705 if (ch <= '/') return 1; /* 47 */ 00706 if (ch <= '9') return 2; /* 57 */ 00707 if (ch <= '@') return 1; /* 64 */ 00708 if (ch <= 'Z') return 2; /* 90 */ 00709 if (ch == '_') return 2; /* 95, dont delimit '_' */ 00710 if (ch <= '`') return 1; /* 96 */ 00711 if (ch <= 'z') return 2; /* 122 */ 00712 return 1; 00713 } 00714 00715 /****************************/ 00716 /* Cursor utility functions */ 00717 /****************************/ 00718 00719 static void txt_curs_cur (Text *text, TextLine ***linep, int **charp) 00720 { 00721 *linep= &text->curl; *charp= &text->curc; 00722 } 00723 00724 static void txt_curs_sel (Text *text, TextLine ***linep, int **charp) 00725 { 00726 *linep= &text->sell; *charp= &text->selc; 00727 } 00728 00729 static void txt_curs_first (Text *text, TextLine **linep, int *charp) 00730 { 00731 if (text->curl==text->sell) { 00732 *linep= text->curl; 00733 if (text->curc<text->selc) *charp= text->curc; 00734 else *charp= text->selc; 00735 } else if (txt_get_span(text->lines.first, text->curl)<txt_get_span(text->lines.first, text->sell)) { 00736 *linep= text->curl; 00737 *charp= text->curc; 00738 } else { 00739 *linep= text->sell; 00740 *charp= text->selc; 00741 } 00742 } 00743 00744 /****************************/ 00745 /* Cursor movement functions */ 00746 /****************************/ 00747 00748 void txt_move_up(Text *text, short sel) 00749 { 00750 TextLine **linep; 00751 int *charp, old; 00752 00753 if (!text) return; 00754 if(sel) txt_curs_sel(text, &linep, &charp); 00755 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); } 00756 if (!*linep) return; 00757 old= *charp; 00758 00759 if((*linep)->prev) { 00760 *linep= (*linep)->prev; 00761 if (*charp > (*linep)->len) { 00762 *charp= (*linep)->len; 00763 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); 00764 } else { 00765 if(!undoing) txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP); 00766 } 00767 } else { 00768 txt_move_bol(text, sel); 00769 } 00770 00771 if(!sel) txt_pop_sel(text); 00772 } 00773 00774 void txt_move_down(Text *text, short sel) 00775 { 00776 TextLine **linep; 00777 int *charp, old; 00778 00779 if (!text) return; 00780 if(sel) txt_curs_sel(text, &linep, &charp); 00781 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); } 00782 if (!*linep) return; 00783 old= *charp; 00784 00785 if((*linep)->next) { 00786 *linep= (*linep)->next; 00787 if (*charp > (*linep)->len) { 00788 *charp= (*linep)->len; 00789 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); 00790 } else 00791 if(!undoing) txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN); 00792 } else { 00793 txt_move_eol(text, sel); 00794 } 00795 00796 if(!sel) txt_pop_sel(text); 00797 } 00798 00799 void txt_move_left(Text *text, short sel) 00800 { 00801 TextLine **linep; 00802 int *charp, oundoing= undoing; 00803 00804 if (!text) return; 00805 if(sel) txt_curs_sel(text, &linep, &charp); 00806 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); } 00807 if (!*linep) return; 00808 00809 undoing= 1; 00810 if (*charp== 0) { 00811 if ((*linep)->prev) { 00812 txt_move_up(text, sel); 00813 *charp= (*linep)->len; 00814 } 00815 } else { 00816 (*charp)--; 00817 } 00818 undoing= oundoing; 00819 if(!undoing) txt_undo_add_op(text, sel?UNDO_SLEFT:UNDO_CLEFT); 00820 00821 if(!sel) txt_pop_sel(text); 00822 } 00823 00824 void txt_move_right(Text *text, short sel) 00825 { 00826 TextLine **linep; 00827 int *charp, oundoing= undoing; 00828 00829 if (!text) return; 00830 if(sel) txt_curs_sel(text, &linep, &charp); 00831 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); } 00832 if (!*linep) return; 00833 00834 undoing= 1; 00835 if (*charp== (*linep)->len) { 00836 if ((*linep)->next) { 00837 txt_move_down(text, sel); 00838 *charp= 0; 00839 } 00840 } else { 00841 (*charp)++; 00842 } 00843 undoing= oundoing; 00844 if(!undoing) txt_undo_add_op(text, sel?UNDO_SRIGHT:UNDO_CRIGHT); 00845 00846 if(!sel) txt_pop_sel(text); 00847 } 00848 00849 void txt_jump_left(Text *text, short sel) 00850 { 00851 TextLine **linep, *oldl; 00852 int *charp, oldc, count, i; 00853 unsigned char oldu; 00854 00855 if (!text) return; 00856 if(sel) txt_curs_sel(text, &linep, &charp); 00857 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); } 00858 if (!*linep) return; 00859 00860 oldl= *linep; 00861 oldc= *charp; 00862 oldu= undoing; 00863 undoing= 1; /* Don't push individual moves to undo stack */ 00864 00865 count= 0; 00866 for (i=0; i<3; i++) { 00867 if (count < 2) { 00868 while (*charp>0 && txt_char_type((*linep)->line[*charp-1])==i) { 00869 txt_move_left(text, sel); 00870 count++; 00871 } 00872 } 00873 } 00874 if (count==0) txt_move_left(text, sel); 00875 00876 undoing= oldu; 00877 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); 00878 } 00879 00880 void txt_jump_right(Text *text, short sel) 00881 { 00882 TextLine **linep, *oldl; 00883 int *charp, oldc, count, i; 00884 unsigned char oldu; 00885 00886 if (!text) return; 00887 if(sel) txt_curs_sel(text, &linep, &charp); 00888 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); } 00889 if (!*linep) return; 00890 00891 oldl= *linep; 00892 oldc= *charp; 00893 oldu= undoing; 00894 undoing= 1; /* Don't push individual moves to undo stack */ 00895 00896 count= 0; 00897 for (i=0; i<3; i++) { 00898 if (count < 2) { 00899 while (*charp<(*linep)->len && txt_char_type((*linep)->line[*charp])==i) { 00900 txt_move_right(text, sel); 00901 count++; 00902 } 00903 } 00904 } 00905 if (count==0) txt_move_right(text, sel); 00906 00907 undoing= oldu; 00908 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); 00909 } 00910 00911 void txt_move_bol (Text *text, short sel) 00912 { 00913 TextLine **linep; 00914 int *charp, old; 00915 00916 if (!text) return; 00917 if(sel) txt_curs_sel(text, &linep, &charp); 00918 else txt_curs_cur(text, &linep, &charp); 00919 if (!*linep) return; 00920 old= *charp; 00921 00922 *charp= 0; 00923 00924 if(!sel) txt_pop_sel(text); 00925 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); 00926 } 00927 00928 void txt_move_eol (Text *text, short sel) 00929 { 00930 TextLine **linep; 00931 int *charp, old; 00932 00933 if (!text) return; 00934 if(sel) txt_curs_sel(text, &linep, &charp); 00935 else txt_curs_cur(text, &linep, &charp); 00936 if (!*linep) return; 00937 old= *charp; 00938 00939 *charp= (*linep)->len; 00940 00941 if(!sel) txt_pop_sel(text); 00942 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); 00943 } 00944 00945 void txt_move_bof (Text *text, short sel) 00946 { 00947 TextLine **linep; 00948 int *charp, old; 00949 00950 if (!text) return; 00951 if(sel) txt_curs_sel(text, &linep, &charp); 00952 else txt_curs_cur(text, &linep, &charp); 00953 if (!*linep) return; 00954 old= *charp; 00955 00956 *linep= text->lines.first; 00957 *charp= 0; 00958 00959 if(!sel) txt_pop_sel(text); 00960 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); 00961 } 00962 00963 void txt_move_eof (Text *text, short sel) 00964 { 00965 TextLine **linep; 00966 int *charp, old; 00967 00968 if (!text) return; 00969 if(sel) txt_curs_sel(text, &linep, &charp); 00970 else txt_curs_cur(text, &linep, &charp); 00971 if (!*linep) return; 00972 old= *charp; 00973 00974 *linep= text->lines.last; 00975 *charp= (*linep)->len; 00976 00977 if(!sel) txt_pop_sel(text); 00978 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); 00979 } 00980 00981 void txt_move_toline (Text *text, unsigned int line, short sel) 00982 { 00983 txt_move_to(text, line, 0, sel); 00984 } 00985 00986 void txt_move_to (Text *text, unsigned int line, unsigned int ch, short sel) 00987 { 00988 TextLine **linep, *oldl; 00989 int *charp, oldc; 00990 unsigned int i; 00991 00992 if (!text) return; 00993 if(sel) txt_curs_sel(text, &linep, &charp); 00994 else txt_curs_cur(text, &linep, &charp); 00995 if (!*linep) return; 00996 oldc= *charp; 00997 oldl= *linep; 00998 00999 *linep= text->lines.first; 01000 for (i=0; i<line; i++) { 01001 if ((*linep)->next) *linep= (*linep)->next; 01002 else break; 01003 } 01004 if (ch>(unsigned int)((*linep)->len)) 01005 ch= (unsigned int)((*linep)->len); 01006 *charp= ch; 01007 01008 if(!sel) txt_pop_sel(text); 01009 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); 01010 } 01011 01012 /****************************/ 01013 /* Text selection functions */ 01014 /****************************/ 01015 01016 static void txt_curs_swap (Text *text) 01017 { 01018 TextLine *tmpl; 01019 int tmpc; 01020 01021 tmpl= text->curl; 01022 text->curl= text->sell; 01023 text->sell= tmpl; 01024 01025 tmpc= text->curc; 01026 text->curc= text->selc; 01027 text->selc= tmpc; 01028 01029 if(!undoing) txt_undo_add_op(text, UNDO_SWAP); 01030 } 01031 01032 static void txt_pop_first (Text *text) 01033 { 01034 01035 if (txt_get_span(text->curl, text->sell)<0 || 01036 (text->curl==text->sell && text->curc>text->selc)) { 01037 txt_curs_swap(text); 01038 } 01039 01040 if(!undoing) txt_undo_add_toop(text, UNDO_STO, 01041 txt_get_span(text->lines.first, text->sell), 01042 text->selc, 01043 txt_get_span(text->lines.first, text->curl), 01044 text->curc); 01045 01046 txt_pop_sel(text); 01047 } 01048 01049 static void txt_pop_last (Text *text) 01050 { 01051 if (txt_get_span(text->curl, text->sell)>0 || 01052 (text->curl==text->sell && text->curc<text->selc)) { 01053 txt_curs_swap(text); 01054 } 01055 01056 if(!undoing) txt_undo_add_toop(text, UNDO_STO, 01057 txt_get_span(text->lines.first, text->sell), 01058 text->selc, 01059 txt_get_span(text->lines.first, text->curl), 01060 text->curc); 01061 01062 txt_pop_sel(text); 01063 } 01064 01065 /* never used: CVS 1.19 */ 01066 /* static void txt_pop_selr (Text *text) */ 01067 01068 void txt_pop_sel (Text *text) 01069 { 01070 text->sell= text->curl; 01071 text->selc= text->curc; 01072 } 01073 01074 void txt_order_cursors(Text *text) 01075 { 01076 if (!text) return; 01077 if (!text->curl) return; 01078 if (!text->sell) return; 01079 01080 /* Flip so text->curl is before text->sell */ 01081 if (txt_get_span(text->curl, text->sell)<0 || 01082 (text->curl==text->sell && text->curc>text->selc)) 01083 txt_curs_swap(text); 01084 } 01085 01086 int txt_has_sel(Text *text) 01087 { 01088 return ((text->curl!=text->sell) || (text->curc!=text->selc)); 01089 } 01090 01091 static void txt_delete_sel (Text *text) 01092 { 01093 TextLine *tmpl; 01094 TextMarker *mrk; 01095 char *buf; 01096 int move, lineno; 01097 01098 if (!text) return; 01099 if (!text->curl) return; 01100 if (!text->sell) return; 01101 01102 if (!txt_has_sel(text)) return; 01103 01104 txt_order_cursors(text); 01105 01106 if(!undoing) { 01107 buf= txt_sel_to_buf(text); 01108 txt_undo_add_block(text, UNDO_DBLOCK, buf); 01109 MEM_freeN(buf); 01110 } 01111 01112 buf= MEM_mallocN(text->curc+(text->sell->len - text->selc)+1, "textline_string"); 01113 01114 if (text->curl != text->sell) { 01115 txt_clear_marker_region(text, text->curl, text->curc, text->curl->len, 0, 0); 01116 move= txt_get_span(text->curl, text->sell); 01117 } else { 01118 mrk= txt_find_marker_region(text, text->curl, text->curc, text->selc, 0, 0); 01119 if (mrk && (mrk->start > text->curc || mrk->end < text->selc)) 01120 txt_clear_marker_region(text, text->curl, text->curc, text->selc, 0, 0); 01121 move= 0; 01122 } 01123 01124 mrk= txt_find_marker_region(text, text->sell, text->selc-1, text->sell->len, 0, 0); 01125 if (mrk) { 01126 lineno= mrk->lineno; 01127 do { 01128 mrk->lineno -= move; 01129 if (mrk->start > text->curc) mrk->start -= text->selc - text->curc; 01130 mrk->end -= text->selc - text->curc; 01131 mrk= mrk->next; 01132 } while (mrk && mrk->lineno==lineno); 01133 } 01134 01135 strncpy(buf, text->curl->line, text->curc); 01136 strcpy(buf+text->curc, text->sell->line + text->selc); 01137 buf[text->curc+(text->sell->len - text->selc)]=0; 01138 01139 make_new_line(text->curl, buf); 01140 01141 tmpl= text->sell; 01142 while (tmpl != text->curl) { 01143 tmpl= tmpl->prev; 01144 if (!tmpl) break; 01145 01146 txt_delete_line(text, tmpl->next); 01147 } 01148 01149 text->sell= text->curl; 01150 text->selc= text->curc; 01151 } 01152 01153 void txt_sel_all (Text *text) 01154 { 01155 if (!text) return; 01156 01157 text->curl= text->lines.first; 01158 text->curc= 0; 01159 01160 text->sell= text->lines.last; 01161 text->selc= text->sell->len; 01162 } 01163 01164 void txt_sel_line (Text *text) 01165 { 01166 if (!text) return; 01167 if (!text->curl) return; 01168 01169 text->curc= 0; 01170 text->sell= text->curl; 01171 text->selc= text->sell->len; 01172 } 01173 01174 /***************************/ 01175 /* Cut and paste functions */ 01176 /***************************/ 01177 01178 char *txt_to_buf (Text *text) 01179 { 01180 int length; 01181 TextLine *tmp, *linef, *linel; 01182 int charf, charl; 01183 char *buf; 01184 01185 if (!text) return NULL; 01186 if (!text->curl) return NULL; 01187 if (!text->sell) return NULL; 01188 if (!text->lines.first) return NULL; 01189 01190 linef= text->lines.first; 01191 charf= 0; 01192 01193 linel= text->lines.last; 01194 charl= linel->len; 01195 01196 if (linef == text->lines.last) { 01197 length= charl-charf; 01198 01199 buf= MEM_mallocN(length+2, "text buffer"); 01200 01201 BLI_strncpy(buf, linef->line + charf, length+1); 01202 buf[length]=0; 01203 } else { 01204 length= linef->len - charf; 01205 length+= charl; 01206 length+= 2; /* For the 2 '\n' */ 01207 01208 tmp= linef->next; 01209 while (tmp && tmp!= linel) { 01210 length+= tmp->len+1; 01211 tmp= tmp->next; 01212 } 01213 01214 buf= MEM_mallocN(length+1, "cut buffer"); 01215 01216 strncpy(buf, linef->line + charf, linef->len-charf); 01217 length= linef->len - charf; 01218 01219 buf[length++]='\n'; 01220 01221 tmp= linef->next; 01222 while (tmp && tmp!=linel) { 01223 strncpy(buf+length, tmp->line, tmp->len); 01224 length+= tmp->len; 01225 01226 buf[length++]='\n'; 01227 01228 tmp= tmp->next; 01229 } 01230 strncpy(buf+length, linel->line, charl); 01231 length+= charl; 01232 01233 /* python compiler wants an empty end line */ 01234 buf[length++]='\n'; 01235 buf[length]=0; 01236 } 01237 01238 return buf; 01239 } 01240 01241 int txt_find_string(Text *text, char *findstr, int wrap, int match_case) 01242 { 01243 TextLine *tl, *startl; 01244 char *s= NULL; 01245 01246 if (!text || !text->curl || !text->sell) return 0; 01247 01248 txt_order_cursors(text); 01249 01250 tl= startl= text->sell; 01251 01252 if(match_case) s= strstr(&tl->line[text->selc], findstr); 01253 else s= BLI_strcasestr(&tl->line[text->selc], findstr); 01254 while (!s) { 01255 tl= tl->next; 01256 if (!tl) { 01257 if (wrap) 01258 tl= text->lines.first; 01259 else 01260 break; 01261 } 01262 01263 if(match_case) s= strstr(tl->line, findstr); 01264 else s= BLI_strcasestr(tl->line, findstr); 01265 if (tl==startl) 01266 break; 01267 } 01268 01269 if (s) { 01270 int newl= txt_get_span(text->lines.first, tl); 01271 int newc= (int)(s-tl->line); 01272 txt_move_to(text, newl, newc, 0); 01273 txt_move_to(text, newl, newc + strlen(findstr), 1); 01274 return 1; 01275 } else 01276 return 0; 01277 } 01278 01279 char *txt_sel_to_buf (Text *text) 01280 { 01281 char *buf; 01282 int length=0; 01283 TextLine *tmp, *linef, *linel; 01284 int charf, charl; 01285 01286 if (!text) return NULL; 01287 if (!text->curl) return NULL; 01288 if (!text->sell) return NULL; 01289 01290 if (text->curl==text->sell) { 01291 linef= linel= text->curl; 01292 01293 if (text->curc < text->selc) { 01294 charf= text->curc; 01295 charl= text->selc; 01296 } else{ 01297 charf= text->selc; 01298 charl= text->curc; 01299 } 01300 } else if (txt_get_span(text->curl, text->sell)<0) { 01301 linef= text->sell; 01302 linel= text->curl; 01303 01304 charf= text->selc; 01305 charl= text->curc; 01306 } else { 01307 linef= text->curl; 01308 linel= text->sell; 01309 01310 charf= text->curc; 01311 charl= text->selc; 01312 } 01313 01314 if (linef == linel) { 01315 length= charl-charf; 01316 01317 buf= MEM_mallocN(length+1, "sel buffer"); 01318 01319 BLI_strncpy(buf, linef->line + charf, length+1); 01320 } else { 01321 length+= linef->len - charf; 01322 length+= charl; 01323 length++; /* For the '\n' */ 01324 01325 tmp= linef->next; 01326 while (tmp && tmp!= linel) { 01327 length+= tmp->len+1; 01328 tmp= tmp->next; 01329 } 01330 01331 buf= MEM_mallocN(length+1, "sel buffer"); 01332 01333 strncpy(buf, linef->line+ charf, linef->len-charf); 01334 length= linef->len-charf; 01335 01336 buf[length++]='\n'; 01337 01338 tmp= linef->next; 01339 while (tmp && tmp!=linel) { 01340 strncpy(buf+length, tmp->line, tmp->len); 01341 length+= tmp->len; 01342 01343 buf[length++]='\n'; 01344 01345 tmp= tmp->next; 01346 } 01347 strncpy(buf+length, linel->line, charl); 01348 length+= charl; 01349 01350 buf[length]=0; 01351 } 01352 01353 return buf; 01354 } 01355 01356 static void txt_shift_markers(Text *text, int lineno, int count) 01357 { 01358 TextMarker *marker; 01359 01360 for (marker=text->markers.first; marker; marker= marker->next) 01361 if (marker->lineno>=lineno) { 01362 marker->lineno+= count; 01363 } 01364 } 01365 01366 void txt_insert_buf(Text *text, const char *in_buffer) 01367 { 01368 int i=0, l=0, j, u, len, lineno= -1, count= 0; 01369 TextLine *add; 01370 01371 if (!text) return; 01372 if (!in_buffer) return; 01373 01374 txt_delete_sel(text); 01375 01376 if(!undoing) txt_undo_add_block (text, UNDO_IBLOCK, in_buffer); 01377 01378 u= undoing; 01379 undoing= 1; 01380 01381 /* Read the first line (or as close as possible */ 01382 while (in_buffer[i] && in_buffer[i]!='\n') { 01383 txt_add_raw_char(text, in_buffer[i]); 01384 i++; 01385 } 01386 01387 if (in_buffer[i]=='\n') txt_split_curline(text); 01388 else { undoing = u; return; } 01389 i++; 01390 01391 /* Read as many full lines as we can */ 01392 len= strlen(in_buffer); 01393 lineno= txt_get_span(text->lines.first, text->curl); 01394 01395 while (i<len) { 01396 l=0; 01397 01398 while (in_buffer[i] && in_buffer[i]!='\n') { 01399 i++; l++; 01400 } 01401 01402 if(in_buffer[i]=='\n') { 01403 add= txt_new_linen(in_buffer +(i-l), l); 01404 BLI_insertlinkbefore(&text->lines, text->curl, add); 01405 i++; 01406 count++; 01407 } else { 01408 if(count) { 01409 txt_shift_markers(text, lineno, count); 01410 count= 0; 01411 } 01412 01413 for (j= i-l; j<i && j<(int)strlen(in_buffer); j++) { 01414 txt_add_raw_char(text, in_buffer[j]); 01415 } 01416 break; 01417 } 01418 } 01419 01420 if(count) { 01421 txt_shift_markers(text, lineno, count); 01422 count= 0; 01423 } 01424 01425 undoing= u; 01426 01427 (void)count; 01428 } 01429 01430 /******************/ 01431 /* Undo functions */ 01432 /******************/ 01433 01434 static int max_undo_test(Text *text, int x) 01435 { 01436 while (text->undo_pos+x >= text->undo_len) { 01437 if(text->undo_len*2 > TXT_MAX_UNDO) { 01438 /* XXX error("Undo limit reached, buffer cleared\n"); */ 01439 MEM_freeN(text->undo_buf); 01440 init_undo_text(text); 01441 return 0; 01442 } else { 01443 void *tmp= text->undo_buf; 01444 text->undo_buf= MEM_callocN(text->undo_len*2, "undo buf"); 01445 memcpy(text->undo_buf, tmp, text->undo_len); 01446 text->undo_len*=2; 01447 MEM_freeN(tmp); 01448 } 01449 } 01450 01451 return 1; 01452 } 01453 01454 static void dump_buffer(Text *text) 01455 { 01456 int i= 0; 01457 01458 while (i++<text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]); 01459 } 01460 01461 void txt_print_undo(Text *text) 01462 { 01463 int i= 0; 01464 int op; 01465 const char *ops; 01466 int linep, charp; 01467 01468 dump_buffer(text); 01469 01470 printf ("---< Undo Buffer >---\n"); 01471 01472 printf ("UndoPosition is %d\n", text->undo_pos); 01473 01474 while (i<=text->undo_pos) { 01475 op= text->undo_buf[i]; 01476 01477 if (op==UNDO_CLEFT) { 01478 ops= "Cursor left"; 01479 } else if (op==UNDO_CRIGHT) { 01480 ops= "Cursor right"; 01481 } else if (op==UNDO_CUP) { 01482 ops= "Cursor up"; 01483 } else if (op==UNDO_CDOWN) { 01484 ops= "Cursor down"; 01485 } else if (op==UNDO_SLEFT) { 01486 ops= "Selection left"; 01487 } else if (op==UNDO_SRIGHT) { 01488 ops= "Selection right"; 01489 } else if (op==UNDO_SUP) { 01490 ops= "Selection up"; 01491 } else if (op==UNDO_SDOWN) { 01492 ops= "Selection down"; 01493 } else if (op==UNDO_STO) { 01494 ops= "Selection "; 01495 } else if (op==UNDO_CTO) { 01496 ops= "Cursor "; 01497 } else if (op==UNDO_INSERT) { 01498 ops= "Insert"; 01499 } else if (op==UNDO_BS) { 01500 ops= "Backspace"; 01501 } else if (op==UNDO_DEL) { 01502 ops= "Delete"; 01503 } else if (op==UNDO_SWAP) { 01504 ops= "Cursor swap"; 01505 } else if (op==UNDO_DBLOCK) { 01506 ops= "Delete text block"; 01507 } else if (op==UNDO_IBLOCK) { 01508 ops= "Insert text block"; 01509 } else if (op==UNDO_INDENT) { 01510 ops= "Indent "; 01511 } else if (op==UNDO_UNINDENT) { 01512 ops= "Unindent "; 01513 } else if (op==UNDO_COMMENT) { 01514 ops= "Comment "; 01515 } else if (op==UNDO_UNCOMMENT) { 01516 ops= "Uncomment "; 01517 } else { 01518 ops= "Unknown"; 01519 } 01520 01521 printf ("Op (%o) at %d = %s", op, i, ops); 01522 if (op==UNDO_INSERT || op==UNDO_BS || op==UNDO_DEL) { 01523 i++; 01524 printf (" - Char is %c", text->undo_buf[i]); 01525 i++; 01526 } else if (op==UNDO_STO || op==UNDO_CTO) { 01527 i++; 01528 01529 charp= text->undo_buf[i]; i++; 01530 charp= charp+(text->undo_buf[i]<<8); i++; 01531 01532 linep= text->undo_buf[i]; i++; 01533 linep= linep+(text->undo_buf[i]<<8); i++; 01534 linep= linep+(text->undo_buf[i]<<16); i++; 01535 linep= linep+(text->undo_buf[i]<<24); i++; 01536 01537 printf ("to <%d, %d> ", linep, charp); 01538 01539 charp= text->undo_buf[i]; i++; 01540 charp= charp+(text->undo_buf[i]<<8); i++; 01541 01542 linep= text->undo_buf[i]; i++; 01543 linep= linep+(text->undo_buf[i]<<8); i++; 01544 linep= linep+(text->undo_buf[i]<<16); i++; 01545 linep= linep+(text->undo_buf[i]<<24); i++; 01546 01547 printf ("from <%d, %d>", linep, charp); 01548 } else if (op==UNDO_DBLOCK || op==UNDO_IBLOCK) { 01549 i++; 01550 01551 linep= text->undo_buf[i]; i++; 01552 linep= linep+(text->undo_buf[i]<<8); i++; 01553 linep= linep+(text->undo_buf[i]<<16); i++; 01554 linep= linep+(text->undo_buf[i]<<24); i++; 01555 01556 printf (" (length %d) <", linep); 01557 01558 while (linep>0) { 01559 putchar(text->undo_buf[i]); 01560 linep--; i++; 01561 } 01562 01563 linep= text->undo_buf[i]; i++; 01564 linep= linep+(text->undo_buf[i]<<8); i++; 01565 linep= linep+(text->undo_buf[i]<<16); i++; 01566 linep= linep+(text->undo_buf[i]<<24); i++; 01567 printf ("> (%d)", linep); 01568 } else if (op==UNDO_INDENT || op==UNDO_UNINDENT) { 01569 i++; 01570 01571 charp= text->undo_buf[i]; i++; 01572 charp= charp+(text->undo_buf[i]<<8); i++; 01573 01574 linep= text->undo_buf[i]; i++; 01575 linep= linep+(text->undo_buf[i]<<8); i++; 01576 linep= linep+(text->undo_buf[i]<<16); i++; 01577 linep= linep+(text->undo_buf[i]<<24); i++; 01578 01579 printf ("to <%d, %d> ", linep, charp); 01580 01581 charp= text->undo_buf[i]; i++; 01582 charp= charp+(text->undo_buf[i]<<8); i++; 01583 01584 linep= text->undo_buf[i]; i++; 01585 linep= linep+(text->undo_buf[i]<<8); i++; 01586 linep= linep+(text->undo_buf[i]<<16); i++; 01587 linep= linep+(text->undo_buf[i]<<24); i++; 01588 01589 printf ("from <%d, %d>", linep, charp); 01590 } 01591 01592 printf (" %d\n", i); 01593 i++; 01594 } 01595 } 01596 01597 static void txt_undo_add_op(Text *text, int op) 01598 { 01599 if(!max_undo_test(text, 2)) 01600 return; 01601 01602 text->undo_pos++; 01603 text->undo_buf[text->undo_pos]= op; 01604 text->undo_buf[text->undo_pos+1]= 0; 01605 } 01606 01607 static void txt_undo_add_block(Text *text, int op, const char *buf) 01608 { 01609 int length; 01610 01611 length= strlen(buf); 01612 01613 if(!max_undo_test(text, length+11)) 01614 return; 01615 01616 text->undo_pos++; 01617 text->undo_buf[text->undo_pos]= op; 01618 01619 text->undo_pos++; 01620 text->undo_buf[text->undo_pos]= (length)&0xff; 01621 text->undo_pos++; 01622 text->undo_buf[text->undo_pos]= (length>>8)&0xff; 01623 text->undo_pos++; 01624 text->undo_buf[text->undo_pos]= (length>>16)&0xff; 01625 text->undo_pos++; 01626 text->undo_buf[text->undo_pos]= (length>>24)&0xff; 01627 01628 text->undo_pos++; 01629 strncpy(text->undo_buf+text->undo_pos, buf, length); 01630 text->undo_pos+=length; 01631 01632 text->undo_buf[text->undo_pos]= (length)&0xff; 01633 text->undo_pos++; 01634 text->undo_buf[text->undo_pos]= (length>>8)&0xff; 01635 text->undo_pos++; 01636 text->undo_buf[text->undo_pos]= (length>>16)&0xff; 01637 text->undo_pos++; 01638 text->undo_buf[text->undo_pos]= (length>>24)&0xff; 01639 01640 text->undo_pos++; 01641 text->undo_buf[text->undo_pos]= op; 01642 01643 text->undo_buf[text->undo_pos+1]= 0; 01644 } 01645 01646 void txt_undo_add_toop(Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc) 01647 { 01648 if(!max_undo_test(text, 15)) 01649 return; 01650 01651 if (froml==tol && fromc==toc) return; 01652 01653 text->undo_pos++; 01654 text->undo_buf[text->undo_pos]= op; 01655 01656 text->undo_pos++; 01657 text->undo_buf[text->undo_pos]= (fromc)&0xff; 01658 text->undo_pos++; 01659 text->undo_buf[text->undo_pos]= (fromc>>8)&0xff; 01660 01661 text->undo_pos++; 01662 text->undo_buf[text->undo_pos]= (froml)&0xff; 01663 text->undo_pos++; 01664 text->undo_buf[text->undo_pos]= (froml>>8)&0xff; 01665 text->undo_pos++; 01666 text->undo_buf[text->undo_pos]= (froml>>16)&0xff; 01667 text->undo_pos++; 01668 text->undo_buf[text->undo_pos]= (froml>>24)&0xff; 01669 01670 text->undo_pos++; 01671 text->undo_buf[text->undo_pos]= (toc)&0xff; 01672 text->undo_pos++; 01673 text->undo_buf[text->undo_pos]= (toc>>8)&0xff; 01674 01675 text->undo_pos++; 01676 text->undo_buf[text->undo_pos]= (tol)&0xff; 01677 text->undo_pos++; 01678 text->undo_buf[text->undo_pos]= (tol>>8)&0xff; 01679 text->undo_pos++; 01680 text->undo_buf[text->undo_pos]= (tol>>16)&0xff; 01681 text->undo_pos++; 01682 text->undo_buf[text->undo_pos]= (tol>>24)&0xff; 01683 01684 text->undo_pos++; 01685 text->undo_buf[text->undo_pos]= op; 01686 01687 text->undo_buf[text->undo_pos+1]= 0; 01688 } 01689 01690 static void txt_undo_add_charop(Text *text, int op, char c) 01691 { 01692 if(!max_undo_test(text, 4)) 01693 return; 01694 01695 text->undo_pos++; 01696 text->undo_buf[text->undo_pos]= op; 01697 text->undo_pos++; 01698 text->undo_buf[text->undo_pos]= c; 01699 text->undo_pos++; 01700 text->undo_buf[text->undo_pos]= op; 01701 text->undo_buf[text->undo_pos+1]= 0; 01702 } 01703 01704 void txt_do_undo(Text *text) 01705 { 01706 int op= text->undo_buf[text->undo_pos]; 01707 unsigned int linep, i; 01708 unsigned short charp; 01709 TextLine *holdl; 01710 int holdc, holdln; 01711 char *buf; 01712 01713 if (text->undo_pos<0) { 01714 return; 01715 } 01716 01717 text->undo_pos--; 01718 01719 undoing= 1; 01720 01721 switch(op) { 01722 case UNDO_CLEFT: 01723 txt_move_right(text, 0); 01724 break; 01725 01726 case UNDO_CRIGHT: 01727 txt_move_left(text, 0); 01728 break; 01729 01730 case UNDO_CUP: 01731 txt_move_down(text, 0); 01732 break; 01733 01734 case UNDO_CDOWN: 01735 txt_move_up(text, 0); 01736 break; 01737 01738 case UNDO_SLEFT: 01739 txt_move_right(text, 1); 01740 break; 01741 01742 case UNDO_SRIGHT: 01743 txt_move_left(text, 1); 01744 break; 01745 01746 case UNDO_SUP: 01747 txt_move_down(text, 1); 01748 break; 01749 01750 case UNDO_SDOWN: 01751 txt_move_up(text, 1); 01752 break; 01753 01754 case UNDO_CTO: 01755 case UNDO_STO: 01756 text->undo_pos--; 01757 text->undo_pos--; 01758 text->undo_pos--; 01759 text->undo_pos--; 01760 01761 text->undo_pos--; 01762 text->undo_pos--; 01763 01764 linep= text->undo_buf[text->undo_pos]; text->undo_pos--; 01765 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01766 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01767 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01768 01769 charp= text->undo_buf[text->undo_pos]; text->undo_pos--; 01770 charp= (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01771 01772 if (op==UNDO_CTO) { 01773 txt_move_toline(text, linep, 0); 01774 text->curc= charp; 01775 txt_pop_sel(text); 01776 } else { 01777 txt_move_toline(text, linep, 1); 01778 text->selc= charp; 01779 } 01780 01781 text->undo_pos--; 01782 break; 01783 01784 case UNDO_INSERT: 01785 txt_backspace_char(text); 01786 text->undo_pos--; 01787 text->undo_pos--; 01788 break; 01789 01790 case UNDO_BS: 01791 txt_add_char(text, text->undo_buf[text->undo_pos]); 01792 text->undo_pos--; 01793 text->undo_pos--; 01794 break; 01795 01796 case UNDO_DEL: 01797 txt_add_char(text, text->undo_buf[text->undo_pos]); 01798 txt_move_left(text, 0); 01799 text->undo_pos--; 01800 text->undo_pos--; 01801 break; 01802 01803 case UNDO_SWAP: 01804 txt_curs_swap(text); 01805 break; 01806 01807 case UNDO_DBLOCK: 01808 linep= text->undo_buf[text->undo_pos]; text->undo_pos--; 01809 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01810 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01811 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01812 01813 buf= MEM_mallocN(linep+1, "dblock buffer"); 01814 for (i=0; i < linep; i++){ 01815 buf[(linep-1)-i]= text->undo_buf[text->undo_pos]; 01816 text->undo_pos--; 01817 } 01818 buf[i]= 0; 01819 01820 txt_curs_first(text, &holdl, &holdc); 01821 holdln= txt_get_span(text->lines.first, holdl); 01822 01823 txt_insert_buf(text, buf); 01824 MEM_freeN(buf); 01825 01826 text->curl= text->lines.first; 01827 while (holdln>0) { 01828 if(text->curl->next) 01829 text->curl= text->curl->next; 01830 01831 holdln--; 01832 } 01833 text->curc= holdc; 01834 01835 linep= text->undo_buf[text->undo_pos]; text->undo_pos--; 01836 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01837 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01838 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01839 01840 text->undo_pos--; 01841 01842 break; 01843 01844 case UNDO_IBLOCK: 01845 linep= text->undo_buf[text->undo_pos]; text->undo_pos--; 01846 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01847 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01848 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01849 01850 txt_delete_sel(text); 01851 while (linep>0) { 01852 txt_backspace_char(text); 01853 text->undo_pos--; 01854 linep--; 01855 } 01856 01857 text->undo_pos--; 01858 text->undo_pos--; 01859 text->undo_pos--; 01860 text->undo_pos--; 01861 01862 text->undo_pos--; 01863 01864 break; 01865 case UNDO_INDENT: 01866 case UNDO_UNINDENT: 01867 case UNDO_COMMENT: 01868 case UNDO_UNCOMMENT: 01869 linep= text->undo_buf[text->undo_pos]; text->undo_pos--; 01870 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01871 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01872 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01873 //linep is now the end line of the selection 01874 01875 charp = text->undo_buf[text->undo_pos]; text->undo_pos--; 01876 charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01877 //charp is the last char selected or text->line->len 01878 //set the selcetion for this now 01879 text->selc = charp; 01880 text->sell = text->lines.first; 01881 for (i= 0; i < linep; i++) { 01882 text->sell = text->sell->next; 01883 } 01884 01885 linep= text->undo_buf[text->undo_pos]; text->undo_pos--; 01886 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01887 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01888 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01889 //first line to be selected 01890 01891 charp = text->undo_buf[text->undo_pos]; text->undo_pos--; 01892 charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--; 01893 //first postion to be selected 01894 text->curc = charp; 01895 text->curl = text->lines.first; 01896 for (i = 0; i < linep; i++) { 01897 text->curl = text->curl->next; 01898 } 01899 01900 01901 if (op==UNDO_INDENT) { 01902 txt_unindent(text); 01903 } else if (op== UNDO_UNINDENT) { 01904 txt_indent(text); 01905 } else if (op == UNDO_COMMENT) { 01906 txt_uncomment(text); 01907 } else if (op == UNDO_UNCOMMENT) { 01908 txt_comment(text); 01909 } 01910 01911 text->undo_pos--; 01912 break; 01913 default: 01914 //XXX error("Undo buffer error - resetting"); 01915 text->undo_pos= -1; 01916 01917 break; 01918 } 01919 01920 /* next undo step may need evaluating */ 01921 if (text->undo_pos>=0) { 01922 switch (text->undo_buf[text->undo_pos]) { 01923 case UNDO_STO: 01924 txt_do_undo(text); 01925 txt_do_redo(text); /* selections need restoring */ 01926 break; 01927 case UNDO_SWAP: 01928 txt_do_undo(text); /* swaps should appear transparent */ 01929 break; 01930 } 01931 } 01932 01933 undoing= 0; 01934 } 01935 01936 void txt_do_redo(Text *text) 01937 { 01938 char op; 01939 unsigned int linep, i; 01940 unsigned short charp; 01941 char *buf; 01942 01943 text->undo_pos++; 01944 op= text->undo_buf[text->undo_pos]; 01945 01946 if (!op) { 01947 text->undo_pos--; 01948 return; 01949 } 01950 01951 undoing= 1; 01952 01953 switch(op) { 01954 case UNDO_CLEFT: 01955 txt_move_left(text, 0); 01956 break; 01957 01958 case UNDO_CRIGHT: 01959 txt_move_right(text, 0); 01960 break; 01961 01962 case UNDO_CUP: 01963 txt_move_up(text, 0); 01964 break; 01965 01966 case UNDO_CDOWN: 01967 txt_move_down(text, 0); 01968 break; 01969 01970 case UNDO_SLEFT: 01971 txt_move_left(text, 1); 01972 break; 01973 01974 case UNDO_SRIGHT: 01975 txt_move_right(text, 1); 01976 break; 01977 01978 case UNDO_SUP: 01979 txt_move_up(text, 1); 01980 break; 01981 01982 case UNDO_SDOWN: 01983 txt_move_down(text, 1); 01984 break; 01985 01986 case UNDO_INSERT: 01987 text->undo_pos++; 01988 txt_add_char(text, text->undo_buf[text->undo_pos]); 01989 text->undo_pos++; 01990 break; 01991 01992 case UNDO_BS: 01993 text->undo_pos++; 01994 txt_backspace_char(text); 01995 text->undo_pos++; 01996 break; 01997 01998 case UNDO_DEL: 01999 text->undo_pos++; 02000 txt_delete_char(text); 02001 text->undo_pos++; 02002 break; 02003 02004 case UNDO_SWAP: 02005 txt_curs_swap(text); 02006 txt_do_redo(text); /* swaps should appear transparent a*/ 02007 break; 02008 02009 case UNDO_CTO: 02010 case UNDO_STO: 02011 text->undo_pos++; 02012 text->undo_pos++; 02013 02014 text->undo_pos++; 02015 text->undo_pos++; 02016 text->undo_pos++; 02017 text->undo_pos++; 02018 02019 text->undo_pos++; 02020 02021 charp= text->undo_buf[text->undo_pos]; 02022 text->undo_pos++; 02023 charp= charp+(text->undo_buf[text->undo_pos]<<8); 02024 02025 text->undo_pos++; 02026 linep= text->undo_buf[text->undo_pos]; text->undo_pos++; 02027 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++; 02028 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++; 02029 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++; 02030 02031 if (op==UNDO_CTO) { 02032 txt_move_toline(text, linep, 0); 02033 text->curc= charp; 02034 txt_pop_sel(text); 02035 } else { 02036 txt_move_toline(text, linep, 1); 02037 text->selc= charp; 02038 } 02039 02040 break; 02041 02042 case UNDO_DBLOCK: 02043 text->undo_pos++; 02044 linep= text->undo_buf[text->undo_pos]; text->undo_pos++; 02045 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++; 02046 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++; 02047 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++; 02048 02049 txt_delete_sel(text); 02050 text->undo_pos+=linep; 02051 02052 text->undo_pos++; 02053 text->undo_pos++; 02054 text->undo_pos++; 02055 text->undo_pos++; 02056 02057 break; 02058 02059 case UNDO_IBLOCK: 02060 text->undo_pos++; 02061 linep= text->undo_buf[text->undo_pos]; text->undo_pos++; 02062 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++; 02063 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++; 02064 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++; 02065 02066 buf= MEM_mallocN(linep+1, "iblock buffer"); 02067 memcpy (buf, &text->undo_buf[text->undo_pos], linep); 02068 text->undo_pos+= linep; 02069 buf[linep]= 0; 02070 02071 txt_insert_buf(text, buf); 02072 MEM_freeN(buf); 02073 02074 linep= text->undo_buf[text->undo_pos]; text->undo_pos++; 02075 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++; 02076 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++; 02077 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++; 02078 (void)linep; 02079 02080 break; 02081 case UNDO_INDENT: 02082 case UNDO_UNINDENT: 02083 case UNDO_COMMENT: 02084 case UNDO_UNCOMMENT: 02085 text->undo_pos++; 02086 charp = text->undo_buf[text->undo_pos]; text->undo_pos++; 02087 charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++; 02088 //charp is the first char selected or 0 02089 02090 linep= text->undo_buf[text->undo_pos]; text->undo_pos++; 02091 linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++; 02092 linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++; 02093 linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++; 02094 //linep is now the first line of the selection 02095 //set the selcetion for this now 02096 text->curc = charp; 02097 text->curl = text->lines.first; 02098 for (i= 0; i < linep; i++) { 02099 text->curl = text->curl->next; 02100 } 02101 02102 charp = text->undo_buf[text->undo_pos]; text->undo_pos++; 02103 charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++; 02104 //last postion to be selected 02105 linep= text->undo_buf[text->undo_pos]; text->undo_pos++; 02106 linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++; 02107 linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++; 02108 linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++; 02109 //Last line to be selected 02110 02111 text->selc = charp; 02112 text->sell = text->lines.first; 02113 for (i = 0; i < linep; i++) { 02114 text->sell = text->sell->next; 02115 } 02116 02117 if (op==UNDO_INDENT) { 02118 txt_indent(text); 02119 } else if (op== UNDO_UNINDENT) { 02120 txt_unindent(text); 02121 } else if (op == UNDO_COMMENT) { 02122 txt_comment(text); 02123 } else if (op == UNDO_UNCOMMENT) { 02124 txt_uncomment(text); 02125 } 02126 break; 02127 default: 02128 //XXX error("Undo buffer error - resetting"); 02129 text->undo_pos= -1; 02130 02131 break; 02132 } 02133 02134 undoing= 0; 02135 } 02136 02137 /**************************/ 02138 /* Line editing functions */ 02139 /**************************/ 02140 02141 void txt_split_curline (Text *text) 02142 { 02143 TextLine *ins; 02144 TextMarker *mrk; 02145 char *left, *right; 02146 int lineno= -1; 02147 02148 if (!text) return; 02149 if (!text->curl) return; 02150 02151 txt_delete_sel(text); 02152 02153 /* Move markers */ 02154 02155 lineno= txt_get_span(text->lines.first, text->curl); 02156 mrk= text->markers.first; 02157 while (mrk) { 02158 if (mrk->lineno==lineno && mrk->start>text->curc) { 02159 mrk->lineno++; 02160 mrk->start -= text->curc; 02161 mrk->end -= text->curc; 02162 } else if (mrk->lineno > lineno) { 02163 mrk->lineno++; 02164 } 02165 mrk= mrk->next; 02166 } 02167 02168 /* Make the two half strings */ 02169 02170 left= MEM_mallocN(text->curc+1, "textline_string"); 02171 if (text->curc) memcpy(left, text->curl->line, text->curc); 02172 left[text->curc]=0; 02173 02174 right= MEM_mallocN(text->curl->len - text->curc+1, "textline_string"); 02175 if (text->curl->len - text->curc) memcpy(right, text->curl->line+text->curc, text->curl->len-text->curc); 02176 right[text->curl->len - text->curc]=0; 02177 02178 MEM_freeN(text->curl->line); 02179 if (text->curl->format) MEM_freeN(text->curl->format); 02180 02181 /* Make the new TextLine */ 02182 02183 ins= MEM_mallocN(sizeof(TextLine), "textline"); 02184 ins->line= left; 02185 ins->format= NULL; 02186 ins->len= text->curc; 02187 02188 text->curl->line= right; 02189 text->curl->format= NULL; 02190 text->curl->len= text->curl->len - text->curc; 02191 02192 BLI_insertlinkbefore(&text->lines, text->curl, ins); 02193 02194 text->curc=0; 02195 02196 txt_make_dirty(text); 02197 txt_clean_text(text); 02198 02199 txt_pop_sel(text); 02200 if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, '\n'); 02201 } 02202 02203 static void txt_delete_line (Text *text, TextLine *line) 02204 { 02205 TextMarker *mrk=NULL, *nxt; 02206 int lineno= -1; 02207 02208 if (!text) return; 02209 if (!text->curl) return; 02210 02211 lineno= txt_get_span(text->lines.first, line); 02212 mrk= text->markers.first; 02213 while (mrk) { 02214 nxt= mrk->next; 02215 if (mrk->lineno==lineno) 02216 BLI_freelinkN(&text->markers, mrk); 02217 else if (mrk->lineno > lineno) 02218 mrk->lineno--; 02219 mrk= nxt; 02220 } 02221 02222 BLI_remlink (&text->lines, line); 02223 02224 if (line->line) MEM_freeN(line->line); 02225 if (line->format) MEM_freeN(line->format); 02226 02227 MEM_freeN(line); 02228 02229 txt_make_dirty(text); 02230 txt_clean_text(text); 02231 } 02232 02233 static void txt_combine_lines (Text *text, TextLine *linea, TextLine *lineb) 02234 { 02235 char *tmp; 02236 TextMarker *mrk= NULL; 02237 int lineno=-1; 02238 02239 if (!text) return; 02240 02241 if(!linea || !lineb) return; 02242 02243 mrk= txt_find_marker_region(text, lineb, 0, lineb->len, 0, 0); 02244 if (mrk) { 02245 lineno= mrk->lineno; 02246 do { 02247 mrk->lineno--; 02248 mrk->start += linea->len; 02249 mrk->end += linea->len; 02250 mrk= mrk->next; 02251 } while (mrk && mrk->lineno==lineno); 02252 } 02253 if (lineno==-1) lineno= txt_get_span(text->lines.first, lineb); 02254 02255 tmp= MEM_mallocN(linea->len+lineb->len+1, "textline_string"); 02256 02257 strcpy(tmp, linea->line); 02258 strcat(tmp, lineb->line); 02259 02260 make_new_line(linea, tmp); 02261 02262 txt_delete_line(text, lineb); 02263 02264 txt_make_dirty(text); 02265 txt_clean_text(text); 02266 } 02267 02268 void txt_delete_char (Text *text) 02269 { 02270 char c='\n'; 02271 02272 if (!text) return; 02273 if (!text->curl) return; 02274 02275 if (txt_has_sel(text)) { /* deleting a selection */ 02276 txt_delete_sel(text); 02277 txt_make_dirty(text); 02278 return; 02279 } 02280 else if (text->curc== text->curl->len) { /* Appending two lines */ 02281 if (text->curl->next) { 02282 txt_combine_lines(text, text->curl, text->curl->next); 02283 txt_pop_sel(text); 02284 } 02285 } else { /* Just deleting a char */ 02286 int i= text->curc; 02287 02288 TextMarker *mrk= txt_find_marker_region(text, text->curl, i-1, text->curl->len, 0, 0); 02289 if (mrk) { 02290 int lineno= mrk->lineno; 02291 if (mrk->end==i) { 02292 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) { 02293 txt_clear_markers(text, mrk->group, TMARK_TEMP); 02294 } else { 02295 BLI_freelinkN(&text->markers, mrk); 02296 } 02297 return; 02298 } 02299 do { 02300 if (mrk->start>i) mrk->start--; 02301 mrk->end--; 02302 mrk= mrk->next; 02303 } while (mrk && mrk->lineno==lineno); 02304 } 02305 02306 c= text->curl->line[i]; 02307 while(i< text->curl->len) { 02308 text->curl->line[i]= text->curl->line[i+1]; 02309 i++; 02310 } 02311 text->curl->len--; 02312 02313 txt_pop_sel(text); 02314 } 02315 02316 txt_make_dirty(text); 02317 txt_clean_text(text); 02318 02319 if(!undoing) txt_undo_add_charop(text, UNDO_DEL, c); 02320 } 02321 02322 void txt_delete_word (Text *text) 02323 { 02324 txt_jump_right(text, 1); 02325 txt_delete_sel(text); 02326 } 02327 02328 void txt_backspace_char (Text *text) 02329 { 02330 char c='\n'; 02331 02332 if (!text) return; 02333 if (!text->curl) return; 02334 02335 if (txt_has_sel(text)) { /* deleting a selection */ 02336 txt_delete_sel(text); 02337 txt_make_dirty(text); 02338 return; 02339 } 02340 else if (text->curc==0) { /* Appending two lines */ 02341 if (!text->curl->prev) return; 02342 02343 text->curl= text->curl->prev; 02344 text->curc= text->curl->len; 02345 02346 txt_combine_lines(text, text->curl, text->curl->next); 02347 txt_pop_sel(text); 02348 } 02349 else { /* Just backspacing a char */ 02350 int i= text->curc-1; 02351 02352 TextMarker *mrk= txt_find_marker_region(text, text->curl, i, text->curl->len, 0, 0); 02353 if (mrk) { 02354 int lineno= mrk->lineno; 02355 if (mrk->start==i+1) { 02356 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) { 02357 txt_clear_markers(text, mrk->group, TMARK_TEMP); 02358 } else { 02359 BLI_freelinkN(&text->markers, mrk); 02360 } 02361 return; 02362 } 02363 do { 02364 if (mrk->start>i) mrk->start--; 02365 mrk->end--; 02366 mrk= mrk->next; 02367 } while (mrk && mrk->lineno==lineno); 02368 } 02369 02370 c= text->curl->line[i]; 02371 while(i< text->curl->len) { 02372 text->curl->line[i]= text->curl->line[i+1]; 02373 i++; 02374 } 02375 text->curl->len--; 02376 text->curc--; 02377 02378 txt_pop_sel(text); 02379 } 02380 02381 txt_make_dirty(text); 02382 txt_clean_text(text); 02383 02384 if(!undoing) txt_undo_add_charop(text, UNDO_BS, c); 02385 } 02386 02387 void txt_backspace_word (Text *text) 02388 { 02389 txt_jump_left(text, 1); 02390 txt_delete_sel(text); 02391 } 02392 02393 /* Max spaces to replace a tab with, currently hardcoded to TXT_TABSIZE = 4. 02394 * Used by txt_convert_tab_to_spaces, indent and unintent. 02395 * Remember to change this string according to max tab size */ 02396 static char tab_to_spaces[] = " "; 02397 02398 static void txt_convert_tab_to_spaces (Text *text) 02399 { 02400 /* sb aims to pad adjust the tab-width needed so that the right number of spaces 02401 * is added so that the indention of the line is the right width (i.e. aligned 02402 * to multiples of TXT_TABSIZE) 02403 */ 02404 char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE]; 02405 txt_insert_buf(text, sb); 02406 } 02407 02408 static int txt_add_char_intern (Text *text, char add, int replace_tabs) 02409 { 02410 int len, lineno; 02411 char *tmp; 02412 TextMarker *mrk; 02413 02414 if (!text) return 0; 02415 if (!text->curl) return 0; 02416 02417 if (add=='\n') { 02418 txt_split_curline(text); 02419 return 1; 02420 } 02421 02422 /* insert spaces rather than tabs */ 02423 if (add == '\t' && replace_tabs) { 02424 txt_convert_tab_to_spaces(text); 02425 return 1; 02426 } 02427 02428 txt_delete_sel(text); 02429 02430 mrk= txt_find_marker_region(text, text->curl, text->curc-1, text->curl->len, 0, 0); 02431 if (mrk) { 02432 lineno= mrk->lineno; 02433 do { 02434 if (mrk->start>text->curc) mrk->start++; 02435 mrk->end++; 02436 mrk= mrk->next; 02437 } while (mrk && mrk->lineno==lineno); 02438 } 02439 02440 tmp= MEM_mallocN(text->curl->len+2, "textline_string"); 02441 02442 if(text->curc) memcpy(tmp, text->curl->line, text->curc); 02443 tmp[text->curc]= add; 02444 02445 len= text->curl->len - text->curc; 02446 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len); 02447 tmp[text->curl->len+1]=0; 02448 make_new_line(text->curl, tmp); 02449 02450 text->curc++; 02451 02452 txt_pop_sel(text); 02453 02454 txt_make_dirty(text); 02455 txt_clean_text(text); 02456 02457 if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, add); 02458 return 1; 02459 } 02460 02461 int txt_add_char (Text *text, char add) 02462 { 02463 return txt_add_char_intern(text, add, text->flags & TXT_TABSTOSPACES); 02464 } 02465 02466 int txt_add_raw_char (Text *text, char add) 02467 { 02468 return txt_add_char_intern(text, add, 0); 02469 } 02470 02471 void txt_delete_selected(Text *text) 02472 { 02473 txt_delete_sel(text); 02474 txt_make_dirty(text); 02475 } 02476 02477 int txt_replace_char (Text *text, char add) 02478 { 02479 char del; 02480 02481 if (!text) return 0; 02482 if (!text->curl) return 0; 02483 02484 /* If text is selected or we're at the end of the line just use txt_add_char */ 02485 if (text->curc==text->curl->len || txt_has_sel(text) || add=='\n') { 02486 TextMarker *mrk; 02487 int i= txt_add_char(text, add); 02488 mrk= txt_find_marker(text, text->curl, text->curc, 0, 0); 02489 if (mrk && mrk->end==text->curc) mrk->end--; 02490 return i; 02491 } 02492 02493 del= text->curl->line[text->curc]; 02494 text->curl->line[text->curc]= (unsigned char) add; 02495 text->curc++; 02496 txt_pop_sel(text); 02497 02498 txt_make_dirty(text); 02499 txt_clean_text(text); 02500 02501 /* Should probably create a new op for this */ 02502 if(!undoing) { 02503 txt_undo_add_charop(text, UNDO_DEL, del); 02504 txt_undo_add_charop(text, UNDO_INSERT, add); 02505 } 02506 return 1; 02507 } 02508 02509 void txt_indent(Text *text) 02510 { 02511 int len, num; 02512 char *tmp; 02513 02514 const char *add = "\t"; 02515 int indentlen = 1; 02516 02517 /* hardcoded: TXT_TABSIZE = 4 spaces: */ 02518 int spaceslen = TXT_TABSIZE; 02519 02520 /* insert spaces rather than tabs */ 02521 if (text->flags & TXT_TABSTOSPACES){ 02522 add = tab_to_spaces; 02523 indentlen = spaceslen; 02524 } 02525 02526 if (!text) return; 02527 if (!text->curl) return; 02528 if (!text->sell) return; 02529 02530 num = 0; 02531 while (TRUE) 02532 { 02533 tmp= MEM_mallocN(text->curl->len+indentlen+1, "textline_string"); 02534 02535 text->curc = 0; 02536 if(text->curc) memcpy(tmp, text->curl->line, text->curc); /* XXX never true, check prev line */ 02537 memcpy(tmp+text->curc, add, indentlen); 02538 02539 len= text->curl->len - text->curc; 02540 if(len>0) memcpy(tmp+text->curc+indentlen, text->curl->line+text->curc, len); 02541 tmp[text->curl->len+indentlen]= 0; 02542 02543 make_new_line(text->curl, tmp); 02544 02545 text->curc+= indentlen; 02546 02547 txt_make_dirty(text); 02548 txt_clean_text(text); 02549 02550 if(text->curl == text->sell) 02551 { 02552 text->selc = text->sell->len; 02553 break; 02554 } else { 02555 text->curl = text->curl->next; 02556 num++; 02557 } 02558 } 02559 text->curc = 0; 02560 while( num > 0 ) 02561 { 02562 text->curl = text->curl->prev; 02563 num--; 02564 } 02565 02566 if(!undoing) 02567 { 02568 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); 02569 } 02570 } 02571 02572 void txt_unindent(Text *text) 02573 { 02574 int num = 0; 02575 const char *remove = "\t"; 02576 int indent = 1; 02577 02578 /* hardcoded: TXT_TABSIZE = 4 spaces: */ 02579 int spaceslen = TXT_TABSIZE; 02580 02581 /* insert spaces rather than tabs */ 02582 if (text->flags & TXT_TABSTOSPACES){ 02583 remove = tab_to_spaces; 02584 indent = spaceslen; 02585 } 02586 02587 if (!text) return; 02588 if (!text->curl) return; 02589 if (!text->sell) return; 02590 02591 while(TRUE) 02592 { 02593 int i = 0; 02594 02595 if (BLI_strncasecmp(text->curl->line, remove, indent) == 0) 02596 { 02597 while(i< text->curl->len) { 02598 text->curl->line[i]= text->curl->line[i+indent]; 02599 i++; 02600 } 02601 text->curl->len-= indent; 02602 } 02603 02604 txt_make_dirty(text); 02605 txt_clean_text(text); 02606 02607 if(text->curl == text->sell) 02608 { 02609 text->selc = text->sell->len; 02610 break; 02611 } else { 02612 text->curl = text->curl->next; 02613 num++; 02614 } 02615 02616 } 02617 text->curc = 0; 02618 while( num > 0 ) 02619 { 02620 text->curl = text->curl->prev; 02621 num--; 02622 } 02623 02624 if(!undoing) 02625 { 02626 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); 02627 } 02628 } 02629 02630 void txt_comment(Text *text) 02631 { 02632 int len, num; 02633 char *tmp; 02634 char add = '#'; 02635 02636 if (!text) return; 02637 if (!text->curl) return; 02638 if (!text->sell) return;// Need to change this need to check if only one line is selected to more then one 02639 02640 num = 0; 02641 while (TRUE) 02642 { 02643 tmp= MEM_mallocN(text->curl->len+2, "textline_string"); 02644 02645 text->curc = 0; 02646 if(text->curc) memcpy(tmp, text->curl->line, text->curc); 02647 tmp[text->curc]= add; 02648 02649 len= text->curl->len - text->curc; 02650 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len); 02651 tmp[text->curl->len+1]=0; 02652 02653 make_new_line(text->curl, tmp); 02654 02655 text->curc++; 02656 02657 txt_make_dirty(text); 02658 txt_clean_text(text); 02659 02660 if(text->curl == text->sell) 02661 { 02662 text->selc = text->sell->len; 02663 break; 02664 } else { 02665 text->curl = text->curl->next; 02666 num++; 02667 } 02668 } 02669 text->curc = 0; 02670 while( num > 0 ) 02671 { 02672 text->curl = text->curl->prev; 02673 num--; 02674 } 02675 02676 if(!undoing) 02677 { 02678 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); 02679 } 02680 } 02681 02682 void txt_uncomment(Text *text) 02683 { 02684 int num = 0; 02685 char remove = '#'; 02686 02687 if (!text) return; 02688 if (!text->curl) return; 02689 if (!text->sell) return; 02690 02691 while(TRUE) 02692 { 02693 int i = 0; 02694 02695 if (text->curl->line[i] == remove) 02696 { 02697 while(i< text->curl->len) { 02698 text->curl->line[i]= text->curl->line[i+1]; 02699 i++; 02700 } 02701 text->curl->len--; 02702 } 02703 02704 02705 txt_make_dirty(text); 02706 txt_clean_text(text); 02707 02708 if(text->curl == text->sell) 02709 { 02710 text->selc = text->sell->len; 02711 break; 02712 } else { 02713 text->curl = text->curl->next; 02714 num++; 02715 } 02716 02717 } 02718 text->curc = 0; 02719 while( num > 0 ) 02720 { 02721 text->curl = text->curl->prev; 02722 num--; 02723 } 02724 02725 if(!undoing) 02726 { 02727 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); 02728 } 02729 } 02730 02731 int setcurr_tab_spaces (Text *text, int space) 02732 { 02733 int i = 0; 02734 int test = 0; 02735 const char *word = ":"; 02736 const char *comm = "#"; 02737 const char indent= (text->flags & TXT_TABSTOSPACES) ? ' ' : '\t'; 02738 static const char *back_words[]= {"return", "break", "continue", "pass", "yield", NULL}; 02739 if (!text) return 0; 02740 if (!text->curl) return 0; 02741 02742 while (text->curl->line[i] == indent) 02743 { 02744 //we only count those tabs/spaces that are before any text or before the curs; 02745 if (i == text->curc) 02746 { 02747 return i; 02748 } else { 02749 i++; 02750 } 02751 } 02752 if(strstr(text->curl->line, word)) 02753 { 02754 /* if we find a ':' on this line, then add a tab but not if it is: 02755 * 1) in a comment 02756 * 2) within an identifier 02757 * 3) after the cursor (text->curc), i.e. when creating space before a function def [#25414] 02758 */ 02759 int a, is_indent = 0; 02760 for(a=0; (a < text->curc) && (text->curl->line[a] != '\0'); a++) 02761 { 02762 char ch= text->curl->line[a]; 02763 if (ch=='#') { 02764 break; 02765 } else if (ch==':') { 02766 is_indent = 1; 02767 } else if (ch!=' ' && ch!='\t') { 02768 is_indent = 0; 02769 } 02770 } 02771 if (is_indent) { 02772 i += space; 02773 } 02774 } 02775 02776 for(test=0; back_words[test]; test++) 02777 { 02778 /* if there are these key words then remove a tab because we are done with the block */ 02779 if(strstr(text->curl->line, back_words[test]) && i > 0) 02780 { 02781 if(strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm)) 02782 { 02783 i -= space; 02784 } 02785 } 02786 } 02787 return i; 02788 } 02789 02790 /*********************************/ 02791 /* Text marker utility functions */ 02792 /*********************************/ 02793 02794 /* Creates and adds a marker to the list maintaining sorted order */ 02795 void txt_add_marker(Text *text, TextLine *line, int start, int end, const unsigned char color[4], int group, int flags) { 02796 TextMarker *tmp, *marker; 02797 02798 marker= MEM_mallocN(sizeof(TextMarker), "text_marker"); 02799 02800 marker->lineno= txt_get_span(text->lines.first, line); 02801 marker->start= MIN2(start, end); 02802 marker->end= MAX2(start, end); 02803 marker->group= group; 02804 marker->flags= flags; 02805 02806 marker->color[0]= color[0]; 02807 marker->color[1]= color[1]; 02808 marker->color[2]= color[2]; 02809 marker->color[3]= color[3]; 02810 02811 for (tmp=text->markers.last; tmp; tmp=tmp->prev) 02812 if (tmp->lineno < marker->lineno || (tmp->lineno==marker->lineno && tmp->start < marker->start)) 02813 break; 02814 02815 if (tmp) BLI_insertlinkafter(&text->markers, tmp, marker); 02816 else BLI_addhead(&text->markers, marker); 02817 } 02818 02819 /* Returns the first matching marker on the specified line between two points. 02820 If the group or flags fields are non-zero the returned flag must be in the 02821 specified group and have at least the specified flags set. */ 02822 TextMarker *txt_find_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) { 02823 TextMarker *marker, *next; 02824 int lineno= txt_get_span(text->lines.first, line); 02825 02826 for (marker=text->markers.first; marker; marker=next) { 02827 next= marker->next; 02828 02829 if (group && marker->group != group) continue; 02830 else if ((marker->flags & flags) != flags) continue; 02831 else if (marker->lineno < lineno) continue; 02832 else if (marker->lineno > lineno) break; 02833 02834 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) || 02835 (marker->start<end && marker->end>start)) 02836 return marker; 02837 } 02838 return NULL; 02839 } 02840 02841 /* Clears all markers on the specified line between two points. If the group or 02842 flags fields are non-zero the returned flag must be in the specified group 02843 and have at least the specified flags set. */ 02844 short txt_clear_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) { 02845 TextMarker *marker, *next; 02846 int lineno= txt_get_span(text->lines.first, line); 02847 short cleared= 0; 02848 02849 for (marker=text->markers.first; marker; marker=next) { 02850 next= marker->next; 02851 02852 if (group && marker->group != group) continue; 02853 else if ((marker->flags & flags) != flags) continue; 02854 else if (marker->lineno < lineno) continue; 02855 else if (marker->lineno > lineno) break; 02856 02857 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) || 02858 (marker->start<end && marker->end>start)) { 02859 BLI_freelinkN(&text->markers, marker); 02860 cleared= 1; 02861 } 02862 } 02863 return cleared; 02864 } 02865 02866 /* Clears all markers in the specified group (if given) with at least the 02867 specified flags set. Useful for clearing temporary markers (group=0, 02868 flags=TMARK_TEMP) */ 02869 short txt_clear_markers(Text *text, int group, int flags) { 02870 TextMarker *marker, *next; 02871 short cleared= 0; 02872 02873 for (marker=text->markers.first; marker; marker=next) { 02874 next= marker->next; 02875 02876 if ((!group || marker->group==group) && 02877 (marker->flags & flags) == flags) { 02878 BLI_freelinkN(&text->markers, marker); 02879 cleared= 1; 02880 } 02881 } 02882 return cleared; 02883 } 02884 02885 /* Finds the marker at the specified line and cursor position with at least the 02886 specified flags set in the given group (if non-zero). */ 02887 TextMarker *txt_find_marker(Text *text, TextLine *line, int curs, int group, int flags) { 02888 TextMarker *marker; 02889 int lineno= txt_get_span(text->lines.first, line); 02890 02891 for (marker=text->markers.first; marker; marker=marker->next) { 02892 if (group && marker->group != group) continue; 02893 else if ((marker->flags & flags) != flags) continue; 02894 else if (marker->lineno < lineno) continue; 02895 else if (marker->lineno > lineno) break; 02896 02897 if (marker->start <= curs && curs <= marker->end) 02898 return marker; 02899 } 02900 return NULL; 02901 } 02902 02903 /* Finds the previous marker in the same group. If no other is found, the same 02904 marker will be returned */ 02905 TextMarker *txt_prev_marker(Text *text, TextMarker *marker) { 02906 TextMarker *tmp= marker; 02907 while (tmp) { 02908 if (tmp->prev) tmp= tmp->prev; 02909 else tmp= text->markers.last; 02910 if (tmp->group == marker->group) 02911 return tmp; 02912 } 02913 return NULL; /* Only if marker==NULL */ 02914 } 02915 02916 /* Finds the next marker in the same group. If no other is found, the same 02917 marker will be returned */ 02918 TextMarker *txt_next_marker(Text *text, TextMarker *marker) { 02919 TextMarker *tmp= marker; 02920 while (tmp) { 02921 if (tmp->next) tmp= tmp->next; 02922 else tmp= text->markers.first; 02923 if (tmp->group == marker->group) 02924 return tmp; 02925 } 02926 return NULL; /* Only if marker==NULL */ 02927 } 02928 02929 02930 /*******************************/ 02931 /* Character utility functions */ 02932 /*******************************/ 02933 02934 int text_check_bracket(char ch) 02935 { 02936 int a; 02937 char opens[] = "([{"; 02938 char close[] = ")]}"; 02939 02940 for(a=0; a<(sizeof(opens)-1); a++) { 02941 if(ch==opens[a]) 02942 return a+1; 02943 else if(ch==close[a]) 02944 return -(a+1); 02945 } 02946 return 0; 02947 } 02948 02949 int text_check_delim(char ch) 02950 { 02951 int a; 02952 char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,"; 02953 02954 for(a=0; a<(sizeof(delims)-1); a++) { 02955 if(ch==delims[a]) 02956 return 1; 02957 } 02958 return 0; 02959 } 02960 02961 int text_check_digit(char ch) 02962 { 02963 if(ch < '0') return 0; 02964 if(ch <= '9') return 1; 02965 return 0; 02966 } 02967 02968 int text_check_identifier(char ch) 02969 { 02970 if(ch < '0') return 0; 02971 if(ch <= '9') return 1; 02972 if(ch < 'A') return 0; 02973 if(ch <= 'Z' || ch == '_') return 1; 02974 if(ch < 'a') return 0; 02975 if(ch <= 'z') return 1; 02976 return 0; 02977 } 02978 02979 int text_check_whitespace(char ch) 02980 { 02981 if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') 02982 return 1; 02983 return 0; 02984 }