Logo ROOT  
Reference Guide
TGText.cxx
Go to the documentation of this file.
1// @(#)root/gui:$Id: ba5caabd5d69c640536a71daaa6968de966be4a8 $
2// Author: Fons Rademakers 26/04/98
3
4/*************************************************************************
5 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11/**************************************************************************
12
13 This source is based on Xclass95, a Win95-looking GUI toolkit.
14 Copyright (C) 1996, 1997 David Barth, Ricky Ralston, Hector Peraza.
15
16 Xclass95 is free software; you can redistribute it and/or
17 modify it under the terms of the GNU Library General Public
18 License as published by the Free Software Foundation; either
19 version 2 of the License, or (at your option) any later version.
20
21**************************************************************************/
22
23
24/** \class TGText
25 \ingroup guiwidgets
26
27A TGText is a multi line text buffer. It allows the text to be
28loaded from file, saved to file and edited. It is used in the
29TGTextEdit widget. Single line text is handled by TGTextBuffer
30and the TGTextEntry widget.
31
32*/
33
34
35#include "TGText.h"
36#include "strlcpy.h"
37#include <cctype>
38
39const Int_t kMaxLen = 8000;
40
41
43
44////////////////////////////////////////////////////////////////////////////////
45/// Create empty line of text (default ctor).
46
48{
49 fLength = 0;
50 fString = 0;
51 fPrev = fNext = 0;
52}
53
54////////////////////////////////////////////////////////////////////////////////
55/// Initialize line of text with other line of text (not copy ctor).
56
58{
59 fLength = line->GetLineLength();
60 fString = 0;
61 if (fLength > 0)
62 fString = line->GetText(0, line->GetLineLength());
63 fPrev = fNext = 0;
64}
65
66////////////////////////////////////////////////////////////////////////////////
67/// Initialize line of text with a const char*.
68
69TGTextLine::TGTextLine(const char *string)
70{
71 if (string) {
72 fLength = strlen(string);
73 fString = new char[fLength+1];
74 strlcpy(fString, string, fLength+1);
75 } else {
76 fLength = 0;
77 fString = 0;
78 }
79 fPrev = fNext = 0;
80}
81
82////////////////////////////////////////////////////////////////////////////////
83///copy constructor
84
85TGTextLine::TGTextLine(const TGTextLine& tl) : fLength(tl.fLength),
86 fPrev(tl.fPrev), fNext(tl.fNext)
87{
88 fString = 0;
89 if (tl.fString) {
90 fString = new char[fLength+1];
91 strncpy(fString, tl.fString, fLength);
92 fString[fLength] = 0;
93 }
94}
95
96////////////////////////////////////////////////////////////////////////////////
97///assignment operator
98
100{
101 if (this != &tl) {
102 fLength = tl.fLength;
103 if (fString) delete [] fString;
104 fString = new char[fLength+1];
105 strncpy(fString, tl.fString, fLength);
106 fString[fLength] = 0;
107 fPrev = tl.fPrev;
108 fNext = tl.fNext;
109 }
110 return *this;
111}
112
113////////////////////////////////////////////////////////////////////////////////
114/// Delete a line of text.
115
117{
118 if (fString)
119 delete [] fString;
120}
121
122////////////////////////////////////////////////////////////////////////////////
123/// Clear a line of text.
124
126{
127 if (fString)
128 delete [] fString;
129 fString = 0;
130 fLength = 0;
131}
132
133////////////////////////////////////////////////////////////////////////////////
134/// Delete length chars from line starting at position pos.
135
137{
138 if (fLength == 0 || pos >= fLength)
139 return;
140 if (pos+length > fLength)
141 length = fLength - pos;
142
143 if (fLength - length <= 0) {
144 delete [] fString;
145 fLength = 0;
146 fString = 0;
147 return;
148 }
149 char *newstring = new char[fLength - length+1];
150 strncpy(newstring, fString, (UInt_t)pos);
151 strncpy(newstring+pos, fString+pos+length, UInt_t(fLength-pos-length));
152 delete [] fString;
153 fString = newstring;
154 fLength = fLength - length;
155 fString[fLength] = '\0';
156}
157
158////////////////////////////////////////////////////////////////////////////////
159/// Insert text in line starting at position pos.
160
161void TGTextLine::InsText(ULong_t pos, const char *text)
162{
163 if (pos > fLength || !text)
164 return;
165
166 char *newstring = new char[strlen(text)+fLength+1];
167 if (fString != 0)
168 strncpy(newstring, fString, (UInt_t)pos);
169 // coverity[secure_coding]
170 strcpy(newstring+pos, text);
171 if (fString != 0 && fLength - pos > 0)
172 strncpy(newstring+pos+strlen(text), fString+pos, UInt_t(fLength-pos));
173 fLength = fLength + strlen(text);
174 delete [] fString;
175 fString = newstring;
176 fString[fLength] ='\0';
177}
178
179////////////////////////////////////////////////////////////////////////////////
180/// Get length characters from line starting at pos. Returns 0
181/// in case pos and length are out of range. The returned string
182/// must be freed by the user.
183
185{
186 if (pos >= fLength) {
187 return 0;
188 }
189
190 if (pos + length > fLength) {
191 length = fLength - pos;
192 }
193
194 char *retstring = new char[length+1];
195 retstring[length] = '\0';
196 strncpy(retstring, fString+pos, (UInt_t)length);
197
198 return retstring;
199}
200
201////////////////////////////////////////////////////////////////////////////////
202/// Get word at position. Returned string must be deleted.
203
205{
206 if (pos >= fLength) {
207 return 0;
208 }
209
210 Int_t start = (Int_t)pos;
211 UInt_t end = (UInt_t)pos;
212 UInt_t i = (UInt_t)pos;
213
214 if (fString[i] == ' ' || fString[i] == '\t') {
215 while (start >= 0) {
216 if (fString[start] == ' ' || fString[start] == '\t') --start;
217 else break;
218 }
219 ++start;
220 while (end < fLength) {
221 if (fString[end] == ' ' || fString[end] == '\t') ++end;
222 else break;
223 }
224 } else if (isalnum(fString[i])) {
225 while (start >= 0) {
226 if (isalnum(fString[start])) --start;
227 else break;
228 }
229 ++start;
230 while (end < fLength) {
231 if (isalnum(fString[end])) ++end;
232 else break;
233 }
234 } else {
235 while (start >= 0) {
236 if (isalnum(fString[start]) || fString[start] == ' ' || fString[start] == '\t') {
237 break;
238 } else {
239 --start;
240 }
241 }
242 ++start;
243 while (end < fLength) {
244 if (isalnum(fString[end]) || fString[end] == ' ' || fString[end] == '\t') {
245 break;
246 } else {
247 ++end;
248 }
249 }
250 }
251
252 UInt_t length = UInt_t(end - start);
253 char *retstring = new char[length+1];
254 retstring[length] = '\0';
255 strncpy(retstring, fString+start, length);
256
257 return retstring;
258}
259
260////////////////////////////////////////////////////////////////////////////////
261/// Delete a character from the line.
262
264{
265 char *newstring;
266 if ((fLength <= 0) || (pos > fLength))
267 return;
268 newstring = new char[fLength];
269 strncpy(newstring, fString, (UInt_t)pos-1);
270 if (pos < fLength)
271 strncpy(newstring+pos-1, fString+pos, UInt_t(fLength-pos+1));
272 else
273 newstring[pos-1] = 0;
274 delete [] fString;
275 fString = newstring;
276 fLength--;
277}
278
279////////////////////////////////////////////////////////////////////////////////
280/// Insert a character at the specified position.
281
282void TGTextLine::InsChar(ULong_t pos, char character)
283{
284 char *newstring;
285 if (pos > fLength)
286 return;
287 newstring = new char[fLength+2];
288 newstring[fLength+1] = '\0';
289 if (fLength > 0)
290 strncpy (newstring, fString, (UInt_t)pos);
291 newstring[pos] = character;
292 if (fLength - pos > 0)
293 strncpy(newstring+pos+1, fString+pos, UInt_t(fLength-pos));
294 delete [] fString;
295 fString = newstring;
296 fLength++;
297}
298
299////////////////////////////////////////////////////////////////////////////////
300/// Get a character at the specified position from the line.
301/// Returns -1 if pos is out of range.
302
304{
305 if ((fLength <= 0) || (pos >= fLength))
306 return -1;
307 return fString[pos];
308}
309
310
312
313////////////////////////////////////////////////////////////////////////////////
314///copy constructor
315
317 fFilename(gt.fFilename),
318 fIsSaved(gt.fIsSaved),
319 fFirst(gt.fFirst),
320 fCurrent(gt.fCurrent),
321 fCurrentRow(gt.fCurrentRow),
322 fRowCount(gt.fRowCount),
323 fColCount(gt.fColCount),
324 fLongestLine(gt.fLongestLine)
325{
326}
327
328////////////////////////////////////////////////////////////////////////////////
329///assignment operator
330
332{
333 if(this!=&gt) {
336 fFirst=gt.fFirst;
342 }
343 return *this;
344}
345
346////////////////////////////////////////////////////////////////////////////////
347/// Common initialization method.
348
350{
351 fFirst = new TGTextLine;
353 fCurrentRow = 0;
354 fColCount = 0;
355 fRowCount = 1;
356 fLongestLine = 0;
357 fIsSaved = kTRUE;
358}
359
360////////////////////////////////////////////////////////////////////////////////
361/// Create default (empty) text buffer.
362
364{
365 Init();
366}
367
368////////////////////////////////////////////////////////////////////////////////
369/// Create text buffer and initialize with other text buffer.
370
372{
373 TGLongPosition pos, end;
374
375 pos.fX = pos.fY = 0;
376 end.fY = text->RowCount() - 1;
377 end.fX = text->GetLineLength(end.fY) - 1;
378 Init();
379 InsText(pos, text, pos, end);
380}
381
382////////////////////////////////////////////////////////////////////////////////
383/// Create text buffer and initialize with single line string.
384
385TGText::TGText(const char *string)
386{
387 TGLongPosition pos;
388
389 pos.fX = pos.fY = 0;
390 Init();
391 InsText(pos, string);
392}
393
394////////////////////////////////////////////////////////////////////////////////
395/// Destroy text buffer.
396
398{
399 Clear();
400 delete fFirst;
401}
402
403////////////////////////////////////////////////////////////////////////////////
404/// Clear text buffer.
405
407{
408 TGTextLine *travel = fFirst->fNext;
409 TGTextLine *toDelete;
410 while (travel != 0) {
411 toDelete = travel;
412 travel = travel->fNext;
413 delete toDelete;
414 }
415 fFirst->Clear();
416 fFirst->fNext = 0;
418 fCurrentRow = 0;
419 fColCount = 0;
420 fRowCount = 1;
421 fLongestLine = 0;
422 fIsSaved = kTRUE;
423 fFilename = "";
424}
425
426////////////////////////////////////////////////////////////////////////////////
427/// Load text from file fn. Startpos is the begin from where to
428/// load the file and length is the number of characters to read
429/// from the file.
430
431Bool_t TGText::Load(const char *fn, Long_t startpos, Long_t length)
432{
433 Bool_t isFirst = kTRUE;
434 Bool_t finished = kFALSE;
435 Long_t count, charcount, i, cnt;
436 FILE *fp;
437 char *buf, c, *src, *dst, *buffer, *buf2;
438 TGTextLine *travel, *temp;
439
440 travel = fFirst;
441
442 if (!(fp = fopen(fn, "r"))) return kFALSE;
443 buf = new char[kMaxLen];
444 i = 0;
445 fseek(fp, startpos, SEEK_SET);
446 charcount = 0;
447 while (fgets(buf, kMaxLen, fp)) {
448 if ((length != -1) && (charcount+(Int_t)strlen(buf) > length)) {
449 count = length - charcount;
450 finished = kTRUE;
451 } else
452 count = kMaxLen;
453 charcount += strlen(buf);
454 buf2 = new char[count+1];
455 buf2[count] = '\0';
456 src = buf;
457 dst = buf2;
458 cnt = 0;
459 while ((c = *src++)) {
460 // Don't put CR or NL in buffer
461 if (c == 0x0D || c == 0x0A)
462 break;
463 // Expand tabs
464 else if (c == 0x09) {
465 *dst++ = '\t';
466 while (((dst-buf2) & 0x7) && (cnt++ < count-1))
467 *dst++ = 16; //*dst++ = ' ';
468 } else
469 *dst++ = c;
470 if (cnt++ >= count-1) break;
471 }
472 *dst = '\0';
473 temp = new TGTextLine;
474 const size_t bufferSize = strlen(buf2)+1;
475 buffer = new char[bufferSize];
476 strlcpy(buffer, buf2, bufferSize);
477 temp->fLength = strlen(buf2);
478 temp->fString = buffer;
479 temp->fNext = temp->fPrev = 0;
480 if (isFirst) {
481 delete fFirst;
482 fFirst = temp;
483 fCurrent = temp;
484 travel = fFirst;
485 isFirst = kFALSE;
486 } else {
487 travel->fNext = temp;
488 temp->fPrev = travel;
489 travel = travel->fNext;
490 }
491 ++i;
492 delete [] buf2;
493 if (finished)
494 break;
495 }
496 fclose(fp);
497 delete [] buf;
498
499 // Remember the number of lines
500 fRowCount = i;
501 if (fRowCount == 0)
502 fRowCount++;
503 fIsSaved = kTRUE;
504 fFilename = fn;
505 LongestLine();
506
507 return kTRUE;
508}
509
510////////////////////////////////////////////////////////////////////////////////
511/// Load a 0 terminated buffer. Lines will be split at '\n'.
512
513Bool_t TGText::LoadBuffer(const char *txtbuf)
514{
515 Bool_t isFirst = kTRUE;
516 Bool_t finished = kFALSE, lastnl = kFALSE;
517 Long_t i, cnt;
518 TGTextLine *travel, *temp;
519 char *buf, c, *src, *dst, *buffer, *buf2, *s;
520 const char *tbuf = txtbuf;
521
522 travel = fFirst;
523
524 if (!tbuf || !tbuf[0])
525 return kFALSE;
526
527 buf = new char[kMaxLen];
528 i = 0;
529next:
530 if ((s = (char*)strchr(tbuf, '\n'))) {
531 if (s-tbuf+1 >= kMaxLen-1) {
532 strncpy(buf, tbuf, kMaxLen-2);
533 buf[kMaxLen-2] = '\n';
534 buf[kMaxLen-1] = 0;
535 } else {
536 strncpy(buf, tbuf, s-tbuf+1);
537 buf[s-tbuf+1] = 0;
538 }
539 tbuf = s+1;
540 } else {
541 strncpy(buf, tbuf, kMaxLen-1);
542 buf[kMaxLen-1] = 0;
543 finished = kTRUE;
544 }
545
546 buf2 = new char[kMaxLen+1];
547 buf2[kMaxLen] = '\0';
548 src = buf;
549 dst = buf2;
550 cnt = 0;
551 while ((c = *src++)) {
552 // Don't put CR or NL in buffer
553 if (c == 0x0D || c == 0x0A)
554 break;
555 // Expand tabs
556 else if (c == 0x09) {
557 *dst++ = '\t';
558 while (((dst-buf2) & 0x7) && (cnt++ < kMaxLen-1))
559 *dst++ = 16; //*dst++ = ' ';
560 } else
561 *dst++ = c;
562 if (cnt++ >= kMaxLen-1) break;
563 }
564 *dst = '\0';
565 temp = new TGTextLine;
566 const size_t bufferSize = strlen(buf2) + 1;
567 buffer = new char[bufferSize];
568 strlcpy(buffer, buf2, bufferSize);
569 temp->fLength = strlen(buf2);
570 temp->fString = buffer;
571 temp->fNext = temp->fPrev = 0;
572 if (isFirst) {
573 delete fFirst;
574 fFirst = temp;
575 fCurrent = temp;
576 travel = fFirst;
577 isFirst = kFALSE;
578 } else {
579 travel->fNext = temp;
580 temp->fPrev = travel;
581 travel = travel->fNext;
582 }
583 ++i;
584 delete [] buf2;
585
586 // make sure that \n generates a single empty line in the TGText
587 if (!lastnl && !*tbuf && *(tbuf-1) == '\n') {
588 tbuf--;
589 lastnl = kTRUE;
590 }
591
592 if (!finished && strlen(tbuf))
593 goto next;
594
595 delete [] buf;
596 // Remember the number of lines
597 fRowCount = i;
598 if (fRowCount == 0)
599 fRowCount++;
600 fIsSaved = kTRUE;
601 fFilename = "";
602 LongestLine();
603
604 return kTRUE;
605}
606
607////////////////////////////////////////////////////////////////////////////////
608/// Save text buffer to file fn.
609
610Bool_t TGText::Save(const char *fn)
611{
612 char *buffer;
613 TGTextLine *travel = fFirst;
614 FILE *fp;
615 if (!(fp = fopen(fn, "w"))) return kFALSE;
616
617 while (travel) {
618 ULong_t i = 0;
619 buffer = new char[travel->fLength+2];
620 strncpy(buffer, travel->fString, (UInt_t)travel->fLength);
621 buffer[travel->fLength] = '\n';
622 buffer[travel->fLength+1] = '\0';
623 while (buffer[i] != '\0') {
624 if (buffer[i] == '\t') {
625 ULong_t j = i+1;
626 while (buffer[j] == 16)
627 j++;
628 // coverity[secure_coding]
629 strcpy(buffer+i+1, buffer+j);
630 }
631 i++;
632 }
633 if (fputs(buffer, fp) == EOF) {
634 delete [] buffer;
635 fclose(fp);
636 return kFALSE;
637 }
638 delete [] buffer;
639 travel = travel->fNext;
640 }
641 fIsSaved = kTRUE;
642 fFilename = fn;
643 fclose(fp);
644
645 return kTRUE;
646}
647
648////////////////////////////////////////////////////////////////////////////////
649/// Append buffer to file fn.
650
651Bool_t TGText::Append(const char *fn)
652{
653 char *buffer;
654 TGTextLine *travel = fFirst;
655 FILE *fp;
656 if (!(fp = fopen(fn, "a"))) return kFALSE;
657
658 while (travel) {
659 ULong_t i = 0;
660 buffer = new char[travel->fLength+2];
661 strncpy(buffer, travel->fString, (UInt_t)travel->fLength);
662 buffer[travel->fLength] = '\n';
663 buffer[travel->fLength+1] = '\0';
664 while (buffer[i] != '\0') {
665 if (buffer[i] == '\t') {
666 ULong_t j = i+1;
667 while (buffer[j] == 16 && buffer[j] != '\0')
668 j++;
669 // coverity[secure_coding]
670 strcpy(buffer+i+1, buffer+j);
671 }
672 i++;
673 }
674 if (fputs(buffer, fp) == EOF) {
675 delete [] buffer;
676 fclose(fp);
677 return kFALSE;
678 }
679 delete [] buffer;
680 travel = travel->fNext;
681 }
682 fIsSaved = kTRUE;
683 fclose(fp);
684
685 return kTRUE;
686}
687
688////////////////////////////////////////////////////////////////////////////////
689/// Delete character at specified position pos.
690
692{
693 if ((pos.fY >= fRowCount) || (pos.fY < 0))
694 return kFALSE;
695
696 if (!SetCurrentRow(pos.fY)) return kFALSE;
697 fCurrent->DelChar(pos.fX);
698
700 LongestLine();
701 return kTRUE;
702}
703
704////////////////////////////////////////////////////////////////////////////////
705/// Insert character c at the specified position pos.
706
708{
709 if ((pos.fY >= fRowCount) || (pos.fY < 0) || (pos.fX < 0))
710 return kFALSE;
711
712 if (!SetCurrentRow(pos.fY)) return kFALSE;
713 fCurrent->InsChar(pos.fX, c);
714
716 LongestLine();
717 return kTRUE;
718}
719
720////////////////////////////////////////////////////////////////////////////////
721/// Get character a position pos. If character not valid return -1.
722
724{
725 if (pos.fY >= fRowCount)
726 return -1;
727
728 if (!SetCurrentRow(pos.fY)) return -1;
729 return fCurrent->GetChar(pos.fX);
730}
731
732////////////////////////////////////////////////////////////////////////////////
733/// Delete text between start and end positions. Returns false in
734/// case of failure (start and end not being within bounds).
735
737{
738 if ((start.fY < 0) || (start.fY >= fRowCount) ||
739 (end.fY < 0) || (end.fY >= fRowCount)) {
740 return kFALSE;
741 }
742
743 if ((end.fX < 0) || (end.fX > GetLineLength(end.fY))) {
744 return kFALSE;
745 }
746
747 char *tempbuffer;
748
749 if (!SetCurrentRow(start.fY)) return kFALSE;
750
751 if (start.fY == end.fY) {
752 fCurrent->DelText(start.fX, end.fX-start.fX+1);
753 return kTRUE;
754 }
755 fCurrent->DelText(start.fX, fCurrent->fLength-start.fX);
757 for (Long_t i = start.fY+1; i < end.fY; i++) {
759 }
760
761 tempbuffer = fCurrent->GetText(end.fX+1, fCurrent->fLength-end.fX-1);
763 SetCurrentRow(start.fY);
764 if (tempbuffer) {
765 fCurrent->InsText(fCurrent->GetLineLength(), tempbuffer);
766 delete [] tempbuffer;
767 } else {
768 if (fCurrent->fNext) {
771 SetCurrentRow(start.fY);
772 }
773 }
774
776 LongestLine();
777 return kTRUE;
778}
779
780////////////////////////////////////////////////////////////////////////////////
781/// Insert src text from start_src to end_src into text at position ins_pos.
782/// Returns false in case of failure (start_src, end_src out of range for
783/// src, and ins_pos out of range for this).
784
786 TGLongPosition start_src, TGLongPosition end_src)
787{
788 /*
789 if ((start_src.fY < 0) || (start_src.fY >= src->RowCount()) ||
790 (end_src.fY < 0) || (end_src.fY >= src->RowCount()))
791 return kFALSE;
792 if ((start_src.fX < 0) || (start_src.fX > src->GetLineLength(start_src.fY)) ||
793 (end_src.fX < 0) || (end_src.fX > src->GetLineLength(end_src.fY)))
794 return kFALSE;
795 if ((ins_pos.fY < 0) || (ins_pos.fY > fRowCount))
796 return kFALSE;
797 if ((ins_pos.fX < 0) || (ins_pos.fX > GetLineLength(ins_pos.fY)))
798 return kFALSE;
799 */
800 if (ins_pos.fY > fRowCount)
801 return kFALSE;
802
803 TGLongPosition pos;
804 ULong_t len;
805 char *lineString;
806 char *restString;
807 TGTextLine *following;
808
809 if (ins_pos.fY == fRowCount) { // for appending text
810 pos.fY = fRowCount - 1;
811 pos.fX = GetLineLength(pos.fY);
812 BreakLine(pos); // current row is set by this
813 } else {
814 // otherwise going to the desired row
815 if (!SetCurrentRow(ins_pos.fY)) return kFALSE;
816 }
817
818 // preparing first line to be inserted
819 restString = fCurrent->GetText(ins_pos.fX, fCurrent->fLength - ins_pos.fX);
820 fCurrent->DelText(ins_pos.fX, fCurrent->fLength - ins_pos.fX);
821 following = fCurrent->fNext;
822 // inserting first line
823 if (start_src.fY == end_src.fY) {
824 len = end_src.fX - start_src.fX+1;
825 } else {
826 len = src->GetLineLength(start_src.fY) - start_src.fX;
827 }
828
829 if (len > 0) {
830 lineString = src->GetLine(start_src, len);
831 fCurrent->InsText(ins_pos.fX, lineString);
832 delete [] lineString;
833 }
834 // [...] inserting possible lines
835 pos.fY = start_src.fY+1;
836 pos.fX = 0;
837 for ( ; pos.fY < end_src.fY; pos.fY++) {
838 Int_t llen = src->GetLineLength(pos.fY);
839 lineString = src->GetLine(pos, llen > 0 ? llen : 0);
840 fCurrent->fNext = new TGTextLine(lineString);
843 fRowCount++;
844 fCurrentRow++;
845 delete [] lineString;
846 }
847 // last line of inserted text is as special as first line
848 if (start_src.fY != end_src.fY) {
849 pos.fY = end_src.fY;
850 pos.fX = 0;
851 lineString = src->GetLine(pos, end_src.fX+1);
852 fCurrent->fNext = new TGTextLine(lineString);
855 fRowCount++;
856 fCurrentRow++;
857 delete [] lineString;
858 }
859 // ok, now we have to add the rest of the first destination line
860 if (restString) {
861#if 0
862 if (ins_pos.fX == 0) {
863 fCurrent->fNext = new TGTextLine(restString);
866 fRowCount++;
867 fCurrentRow++;
868 } else
869#endif
870 fCurrent->InsText(fCurrent->fLength, restString);
871 delete [] restString;
872 }
873 // now re-linking the rest of the origin text
874 fCurrent->fNext = following;
875 if (fCurrent->fNext) {
877 }
878
879 LongestLine();
881 return kTRUE;
882}
883
884////////////////////////////////////////////////////////////////////////////////
885/// Insert single line at specified position. Return false in case position
886/// is out of bounds.
887
888Bool_t TGText::InsText(TGLongPosition pos, const char *buffer)
889{
890 if (pos.fY < 0 || pos.fY > fRowCount) {
891 return kFALSE;
892 }
893
894 if (pos.fY == fRowCount) {
896 fCurrent->fNext = new TGTextLine(buffer);
898 fRowCount++;
899 } else {
900 SetCurrentRow(pos.fY);
901 fCurrent->InsText(pos.fX, buffer);
902 }
903 LongestLine();
905 return kTRUE;
906}
907
908////////////////////////////////////////////////////////////////////////////////
909/// Add another text buffer to this buffer.
910
912{
913 TGLongPosition end, start_src, end_src;
914
915 end.fY = fRowCount;
916 end.fX = 0;
917 start_src.fX = start_src.fY = 0;
918 end_src.fY = text->RowCount()-1;
919 end_src.fX = text->GetLineLength(end_src.fY)-1;
921 return InsText(end, text, start_src, end_src);
922}
923
924////////////////////////////////////////////////////////////////////////////////
925/// Insert string before specified position.
926/// Returns false if insertion failed.
927
928Bool_t TGText::InsLine(ULong_t pos, const char *string)
929{
930 TGTextLine *previous, *newline;
931 if ((Long_t)pos > fRowCount) {
932 return kFALSE;
933 }
934 if ((Long_t)pos < fRowCount) {
935 SetCurrentRow(pos);
936 } else {
938 }
939
940 if (!fCurrent) return kFALSE;
941
942 previous = fCurrent->fPrev;
943 newline = new TGTextLine(string);
944 newline->fPrev = previous;
945 if (previous) {
946 previous->fNext = newline;
947 } else {
948 fFirst = newline;
949 }
950
951 newline->fNext = fCurrent;
952 fCurrent->fPrev = newline;
953 fRowCount++;
954 fCurrentRow++;
955
956 LongestLine();
958 return kTRUE;
959}
960
961////////////////////////////////////////////////////////////////////////////////
962/// Delete specified row. Returns false if row does not exist.
963
965{
966 if (!SetCurrentRow(pos) || (fRowCount == 1)) {
967 return kFALSE;
968 }
969
970 TGTextLine *travel = fCurrent;
971 if (travel == fFirst) {
973 fFirst->fPrev = 0;
974 } else {
975 travel->fPrev->fNext = travel->fNext;
976 if (travel->fNext) {
977 travel->fNext->fPrev = travel->fPrev;
979 } else {
981 fCurrentRow--;
982 }
983 }
984 delete travel;
985
986 fRowCount--;
988 LongestLine();
989
990 return kTRUE;
991}
992
993////////////////////////////////////////////////////////////////////////////////
994/// Return string at position pos. Returns 0 in case pos is not valid.
995/// The returned string must be deleted by the user.
996
998{
999 if (SetCurrentRow(pos.fY)) {
1000 return fCurrent->GetText(pos.fX, length);
1001 }
1002 return 0;
1003}
1004
1005////////////////////////////////////////////////////////////////////////////////
1006/// Break line at position pos. Returns false if pos is not valid.
1007
1009{
1010 if (!SetCurrentRow(pos.fY))
1011 return kFALSE;
1012 if ((pos.fX < 0) || (pos.fX > (Long_t)fCurrent->fLength))
1013 return kFALSE;
1014
1015 TGTextLine *temp;
1016 char *tempbuffer;
1017 if (pos.fX < (Long_t)fCurrent->fLength) {
1018 tempbuffer = fCurrent->GetText(pos.fX, fCurrent->fLength-pos.fX);
1019 temp = new TGTextLine(tempbuffer);
1020 fCurrent->DelText(pos.fX, fCurrent->fLength - pos.fX);
1021 delete [] tempbuffer;
1022 } else {
1023 temp = new TGTextLine;
1024 }
1025 temp->fPrev = fCurrent;
1026 temp->fNext = fCurrent->fNext;
1027 fCurrent->fNext = temp;
1028 if (temp->fNext) {
1029 temp->fNext->fPrev = temp;
1030 }
1031
1032 fIsSaved = kFALSE;
1033 fRowCount++;
1034 fCurrentRow++;
1036 LongestLine();
1037 return kTRUE;
1038}
1039
1040////////////////////////////////////////////////////////////////////////////////
1041/// Get length of specified line. Returns -1 if row does not exist.
1042
1044{
1045 if (!SetCurrentRow(row)) {
1046 return -1;
1047 }
1048 return (Long_t)fCurrent->GetLineLength();
1049}
1050
1051////////////////////////////////////////////////////////////////////////////////
1052/// Make specified row the current row. Returns false if row does not exist.
1053/// In which case fCurrent is not changed or set to the last valid line.
1054
1056{
1057 Long_t count;
1058 if ((row < 0) || (row >= fRowCount)) {
1059 return kFALSE;
1060 }
1061 if (row > fCurrentRow) {
1062 for (count = fCurrentRow; count < row; count++) {
1063 if (!fCurrent->fNext) {
1064 fCurrentRow = count;
1065 return kFALSE;
1066 }
1068 }
1069 } else {
1070 if (fCurrentRow == row)
1071 return kTRUE;
1072 for (count = fCurrentRow; count > row; count--) {
1073 if (!fCurrent->fPrev) {
1074 fCurrentRow = count;
1075 return kFALSE;
1076 }
1078 }
1079 }
1080 fCurrentRow = row;
1081 return kTRUE;
1082}
1083
1084////////////////////////////////////////////////////////////////////////////////
1085/// Redo all tabs in a line. Needed after a new tab is inserted.
1086
1088{
1089 if (!SetCurrentRow(row)) {
1090 return;
1091 }
1092
1093 // first remove all special tab characters (16)
1094 char *buffer;
1095 ULong_t i = 0;
1096
1097 buffer = fCurrent->fString;
1098 while (buffer[i] != '\0') {
1099 if (buffer[i] == '\t') {
1100 ULong_t j = i+1;
1101 while (buffer[j] == 16 && buffer[j] != '\0') {
1102 j++;
1103 }
1104 // coverity[secure_coding]
1105 strcpy(buffer+i+1, buffer+j);
1106 }
1107 i++;
1108 }
1109
1110 char c, *src, *dst, *buf2;
1111 Long_t cnt;
1112
1113 buf2 = new char[kMaxLen+1];
1114 buf2[kMaxLen] = '\0';
1115 src = buffer;
1116 dst = buf2;
1117 cnt = 0;
1118 while ((c = *src++)) {
1119 // Expand tabs
1120 if (c == 0x09) {
1121 *dst++ = '\t';
1122 while (((dst-buf2) & 0x7) && (cnt++ < kMaxLen-1)) {
1123 *dst++ = 16;
1124 }
1125 } else {
1126 *dst++ = c;
1127 }
1128 if (cnt++ >= kMaxLen-1) break;
1129 }
1130 *dst = '\0';
1131
1132 fCurrent->fString = buf2;
1133 fCurrent->fLength = strlen(buf2);
1134
1135 delete [] buffer;
1136}
1137
1138////////////////////////////////////////////////////////////////////////////////
1139/// Search for string searchString starting at the specified position going
1140/// in forward (direction = true) or backward direction. Returns true if
1141/// found and foundPos is set accordingly.
1142
1144 const char *searchString,
1145 Bool_t direction, Bool_t caseSensitive)
1146{
1147 if (!SetCurrentRow(start.fY))
1148 return kFALSE;
1149
1150 Ssiz_t x = kNPOS;
1151
1152 if (direction) {
1153 while(1) {
1155 x = s.Index(searchString, (Ssiz_t)start.fX,
1156 caseSensitive ? TString::kExact : TString::kIgnoreCase);
1157 if (x != kNPOS) {
1158 foundPos->fX = x;
1159 foundPos->fY = fCurrentRow;
1160 return kTRUE;
1161 }
1162 if (!SetCurrentRow(fCurrentRow+1))
1163 break;
1164 start.fX = 0;
1165 }
1166 } else {
1167 while(1) {
1169 for (int i = (int)start.fX; i >= 0; i--) {
1170 x = s.Index(searchString, (Ssiz_t)i,
1171 caseSensitive ? TString::kExact : TString::kIgnoreCase);
1172 if (x >= start.fX) {
1173 x = kNPOS;
1174 continue;
1175 }
1176 if (x != kNPOS) {
1177 break;
1178 }
1179 }
1180 if (x != kNPOS) {
1181 foundPos->fX = x;
1182 foundPos->fY = fCurrentRow;
1183 return kTRUE;
1184 }
1185 if (!SetCurrentRow(fCurrentRow-1)) {
1186 break;
1187 }
1188 start.fX = fCurrent->fLength;
1189 }
1190 }
1191 return kFALSE;
1192}
1193
1194////////////////////////////////////////////////////////////////////////////////
1195/// Replace oldText by newText. Returns false if nothing replaced.
1196
1197Bool_t TGText::Replace(TGLongPosition start, const char *oldText, const char *newText,
1198 Bool_t direction, Bool_t caseSensitive)
1199{
1200 if (!SetCurrentRow(start.fY)) {
1201 return kFALSE;
1202 }
1203
1204 TGLongPosition foundPos;
1205 if (!Search(&foundPos, start, oldText, direction, caseSensitive)) {
1206 return kFALSE;
1207 }
1208
1209 TGLongPosition delEnd;
1210 delEnd.fY = foundPos.fY;
1211 delEnd.fX = foundPos.fX + strlen(oldText) - 1;
1212 DelText(foundPos, delEnd);
1213 InsText(foundPos, newText);
1214 return kTRUE;
1215}
1216
1217////////////////////////////////////////////////////////////////////////////////
1218/// Set fLongestLine.
1219
1221{
1222 Long_t line_count = 0;
1223 TGTextLine *travel = fFirst;
1224 fColCount = 0;
1225 while (travel) {
1226 if ((Long_t)travel->fLength > fColCount) {
1227 fColCount = travel->fLength;
1228 fLongestLine = line_count;
1229 }
1230 travel = travel->fNext;
1231 line_count++;
1232 }
1233}
1234
1235////////////////////////////////////////////////////////////////////////////////
1236/// Returns content as ROOT string
1237
1239{
1240 TString ret;
1241
1242 Long_t line_count = 0;
1243 TGTextLine *travel = fFirst;
1244 fColCount = 0;
1245
1246 while (travel) {
1247 if ((Long_t)travel->fLength > fColCount) {
1248 fColCount = travel->fLength;
1249 fLongestLine = line_count;
1250 }
1251 char *txt = travel->GetText();
1252 ret += txt;
1253 travel = travel->fNext;
1254 if (travel) ret += '\n';
1255 line_count++;
1256 }
1257
1258 return ret;
1259}
#define c(i)
Definition: RSha256.hxx:101
const Ssiz_t kNPOS
Definition: RtypesCore.h:124
int Int_t
Definition: RtypesCore.h:45
int Ssiz_t
Definition: RtypesCore.h:67
unsigned int UInt_t
Definition: RtypesCore.h:46
const Bool_t kFALSE
Definition: RtypesCore.h:101
unsigned long ULong_t
Definition: RtypesCore.h:55
long Long_t
Definition: RtypesCore.h:54
bool Bool_t
Definition: RtypesCore.h:63
const Bool_t kTRUE
Definition: RtypesCore.h:100
#define ClassImp(name)
Definition: Rtypes.h:364
const Int_t kMaxLen
Definition: TGText.cxx:39
T1 fFirst
Definition: X11Events.mm:86
Long_t fX
x position
Definition: TGDimension.h:56
Long_t fY
y position
Definition: TGDimension.h:57
virtual ~TGTextLine()
Delete a line of text.
Definition: TGText.cxx:116
TGTextLine * fPrev
previous line
Definition: TGText.h:28
char * fString
line of text
Definition: TGText.h:26
void DelChar(ULong_t pos)
Delete a character from the line.
Definition: TGText.cxx:263
void InsChar(ULong_t pos, char character)
Insert a character at the specified position.
Definition: TGText.cxx:282
char GetChar(ULong_t pos)
Get a character at the specified position from the line.
Definition: TGText.cxx:303
ULong_t GetLineLength()
Definition: TGText.h:41
char * GetText() const
Definition: TGText.h:46
char * GetWord(ULong_t pos)
Get word at position. Returned string must be deleted.
Definition: TGText.cxx:204
void InsText(ULong_t pos, const char *text)
Insert text in line starting at position pos.
Definition: TGText.cxx:161
TGTextLine * fNext
next line
Definition: TGText.h:29
void Clear()
Clear a line of text.
Definition: TGText.cxx:125
TGTextLine()
Create empty line of text (default ctor).
Definition: TGText.cxx:47
void DelText(ULong_t pos, ULong_t length)
Delete length chars from line starting at position pos.
Definition: TGText.cxx:136
ULong_t fLength
length of line
Definition: TGText.h:27
char * GetText(ULong_t pos, ULong_t length)
Get length characters from line starting at pos.
Definition: TGText.cxx:184
TGTextLine & operator=(const TGTextLine &)
assignment operator
Definition: TGText.cxx:99
A TGText is a multi line text buffer.
Definition: TGText.h:57
Bool_t InsChar(TGLongPosition pos, char c)
Insert character c at the specified position pos.
Definition: TGText.cxx:707
void ReTab(Long_t row)
Redo all tabs in a line. Needed after a new tab is inserted.
Definition: TGText.cxx:1087
virtual ~TGText()
Destroy text buffer.
Definition: TGText.cxx:397
Long_t fColCount
number of columns in current line
Definition: TGText.h:66
Bool_t AddText(TGText *text)
Add another text buffer to this buffer.
Definition: TGText.cxx:911
TGTextLine * fFirst
first line of text
Definition: TGText.h:62
Bool_t DelText(TGLongPosition start, TGLongPosition end)
Delete text between start and end positions.
Definition: TGText.cxx:736
TString fFilename
name of opened file ("" if open buffer)
Definition: TGText.h:60
TGText()
Create default (empty) text buffer.
Definition: TGText.cxx:363
Long_t fLongestLine
length of longest line
Definition: TGText.h:67
Long_t fRowCount
number of rows
Definition: TGText.h:65
Bool_t fIsSaved
false if text needs to be saved
Definition: TGText.h:61
void LongestLine()
Set fLongestLine.
Definition: TGText.cxx:1220
Bool_t Search(TGLongPosition *foundPos, TGLongPosition start, const char *searchString, Bool_t direction, Bool_t caseSensitive)
Search for string searchString starting at the specified position going in forward (direction = true)...
Definition: TGText.cxx:1143
Bool_t DelLine(ULong_t pos)
Delete specified row. Returns false if row does not exist.
Definition: TGText.cxx:964
Bool_t Save(const char *fn)
Save text buffer to file fn.
Definition: TGText.cxx:610
Bool_t Replace(TGLongPosition start, const char *oldText, const char *newText, Bool_t direction, Bool_t caseSensitive)
Replace oldText by newText. Returns false if nothing replaced.
Definition: TGText.cxx:1197
Bool_t InsLine(ULong_t row, const char *string)
Insert string before specified position.
Definition: TGText.cxx:928
Bool_t SetCurrentRow(Long_t row)
Make specified row the current row.
Definition: TGText.cxx:1055
Long_t fCurrentRow
current row number
Definition: TGText.h:64
Bool_t DelChar(TGLongPosition pos)
Delete character at specified position pos.
Definition: TGText.cxx:691
Bool_t BreakLine(TGLongPosition pos)
Break line at position pos. Returns false if pos is not valid.
Definition: TGText.cxx:1008
Bool_t InsText(TGLongPosition pos, const char *buf)
Insert single line at specified position.
Definition: TGText.cxx:888
char * GetLine(TGLongPosition pos, ULong_t length)
Return string at position pos.
Definition: TGText.cxx:997
TGTextLine * fCurrent
current line
Definition: TGText.h:63
char GetChar(TGLongPosition pos)
Get character a position pos. If character not valid return -1.
Definition: TGText.cxx:723
Bool_t Load(const char *fn, Long_t startpos=0, Long_t length=-1)
Load text from file fn.
Definition: TGText.cxx:431
Bool_t LoadBuffer(const char *txtbuf)
Load a 0 terminated buffer. Lines will be split at ' '.
Definition: TGText.cxx:513
void Clear()
Clear text buffer.
Definition: TGText.cxx:406
Bool_t Append(const char *fn)
Append buffer to file fn.
Definition: TGText.cxx:651
Long_t GetLineLength(Long_t row)
Get length of specified line. Returns -1 if row does not exist.
Definition: TGText.cxx:1043
void Init()
Common initialization method.
Definition: TGText.cxx:349
TString AsString()
Returns content as ROOT string.
Definition: TGText.cxx:1238
TGText & operator=(const TGText &)
assignment operator
Definition: TGText.cxx:331
Basic string class.
Definition: TString.h:136
@ kIgnoreCase
Definition: TString.h:268
@ kExact
Definition: TString.h:268
TText * text
TLine * line
Double_t x[n]
Definition: legend1.C:17
static constexpr double s
const char * cnt
Definition: TXMLSetup.cxx:75