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