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