Logo ROOT   6.12/07
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 
37 const 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 
67 TGTextLine::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 
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 
160 void 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 
281 void 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 
315 TGText::TGText(const TGText& gt) :
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) {
333  fFilename=gt.fFilename;
334  fIsSaved=gt.fIsSaved;
335  fFirst=gt.fFirst;
336  fCurrent=gt.fCurrent;
338  fRowCount=gt.fRowCount;
339  fColCount=gt.fColCount;
341  }
342  return *this;
343 }
344 
345 ////////////////////////////////////////////////////////////////////////////////
346 /// Common initialization method.
347 
349 {
350  fFirst = new TGTextLine;
351  fCurrent = fFirst;
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 
384 TGText::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;
416  fCurrent = fFirst;
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 
430 Bool_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 
512 Bool_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;
528 next:
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 && tbuf && 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 
609 Bool_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 
650 Bool_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 
698  fIsSaved = kFALSE;
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 
714  fIsSaved = kFALSE;
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) {
769  DelLine(fCurrentRow+1);
770  SetCurrentRow(start.fY);
771  }
772  }
773 
774  fIsSaved = kFALSE;
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();
879  fIsSaved = kFALSE;
880  return kTRUE;
881 }
882 
883 ////////////////////////////////////////////////////////////////////////////////
884 /// Insert single line at specified position. Return false in case position
885 /// is out of bounds.
886 
887 Bool_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();
903  fIsSaved = kFALSE;
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;
919  fIsSaved = kFALSE;
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 
927 Bool_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();
956  fIsSaved = kFALSE;
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) {
971  fFirst = fFirst->fNext;
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--;
986  fIsSaved = kFALSE;
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++;
1034  fCurrent = fCurrent->fNext;
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  }
1066  fCurrent = fCurrent->fNext;
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  }
1076  fCurrent = fCurrent->fPrev;
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 
1196 Bool_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 }
Long_t fCurrentRow
Definition: TGText.h:74
TGTextLine * fFirst
Definition: TGText.h:72
TGTextLine * fCurrent
Definition: TGText.h:73
TGText()
Create default (empty) text buffer.
Definition: TGText.cxx:362
Bool_t Append(const char *fn)
Append buffer to file fn.
Definition: TGText.cxx:650
TLine * line
Bool_t InsText(TGLongPosition pos, const char *buf)
Insert single line at specified position.
Definition: TGText.cxx:887
Definition: TGText.h:67
void Clear()
Clear text buffer.
Definition: TGText.cxx:405
char * GetText() const
Definition: TGText.h:56
const Ssiz_t kNPOS
Definition: RtypesCore.h:111
virtual ~TGTextLine()
Delete a line of text.
Definition: TGText.cxx:115
const Int_t kMaxLen
Definition: TGText.cxx:37
void DelText(ULong_t pos, ULong_t length)
Delete length chars from line starting at position pos.
Definition: TGText.cxx:135
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:585
Basic string class.
Definition: TString.h:125
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
Bool_t BreakLine(TGLongPosition pos)
Break line at position pos. Returns false if pos is not valid.
Definition: TGText.cxx:1007
Bool_t fIsSaved
Definition: TGText.h:71
TGTextLine * fNext
Definition: TGText.h:39
Bool_t LoadBuffer(const char *txtbuf)
Load a 0 terminated buffer. Lines will be split at &#39; &#39;.
Definition: TGText.cxx:512
Bool_t DelChar(TGLongPosition pos)
Delete character at specified position pos.
Definition: TGText.cxx:690
char * fString
Definition: TGText.h:36
Double_t x[n]
Definition: legend1.C:17
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
ULong_t fLength
Definition: TGText.h:37
TString fFilename
Definition: TGText.h:70
void DelChar(ULong_t pos)
Delete a character from the line.
Definition: TGText.cxx:262
ULong_t GetLineLength()
Definition: TGText.h:51
char * GetLine(TGLongPosition pos, ULong_t length)
Return string at position pos.
Definition: TGText.cxx:996
TGTextLine & operator=(const TGTextLine &)
assignment operator
Definition: TGText.cxx:98
Bool_t Load(const char *fn, Long_t startpos=0, Long_t length=-1)
Load text from file fn.
Definition: TGText.cxx:430
Long_t RowCount() const
Definition: TGText.h:116
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
unsigned int UInt_t
Definition: RtypesCore.h:42
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
Long_t fRowCount
Definition: TGText.h:75
TGText & operator=(const TGText &)
assignment operator
Definition: TGText.cxx:330
char GetChar(TGLongPosition pos)
Get character a position pos. If charcater not valid return -1.
Definition: TGText.cxx:722
void Init()
Common initialization method.
Definition: TGText.cxx:348
Bool_t DelText(TGLongPosition start, TGLongPosition end)
Delete text between start and end positions.
Definition: TGText.cxx:735
Bool_t Save(const char *fn)
Save text buffer to file fn.
Definition: TGText.cxx:609
Long_t GetLineLength(Long_t row)
Get length of specified line. Returns -1 if row does not exist.
Definition: TGText.cxx:1042
const Bool_t kFALSE
Definition: RtypesCore.h:88
TGTextLine * fPrev
Definition: TGText.h:38
long Long_t
Definition: RtypesCore.h:50
int Ssiz_t
Definition: RtypesCore.h:63
TGTextLine()
Create empty line of text (default ctor).
Definition: TGText.cxx:45
#define ClassImp(name)
Definition: Rtypes.h:359
TText * text
Long_t fLongestLine
Definition: TGText.h:77
unsigned long ULong_t
Definition: RtypesCore.h:51
Bool_t InsChar(TGLongPosition pos, char c)
Insert character c at the specified position pos.
Definition: TGText.cxx:706
static constexpr double s
TString AsString()
Returns content as ROOT string.
Definition: TGText.cxx:1237
Bool_t AddText(TGText *text)
Add another text buffer to this buffer.
Definition: TGText.cxx:910
void InsChar(ULong_t pos, char character)
Insert a character at the specified position.
Definition: TGText.cxx:281
Bool_t DelLine(ULong_t pos)
Delete specified row. Returns false if row does not exist.
Definition: TGText.cxx:963
Long_t fColCount
Definition: TGText.h:76
void ReTab(Long_t row)
Redo all tabs in a line. Needed after a new tab is inserted.
Definition: TGText.cxx:1086
char * GetText(ULong_t pos, ULong_t length)
Get length characters from line starting at pos.
Definition: TGText.cxx:183
const Bool_t kTRUE
Definition: RtypesCore.h:87
Bool_t InsLine(ULong_t row, const char *string)
Insert string before specified position.
Definition: TGText.cxx:927
void Clear()
Clear a line of text.
Definition: TGText.cxx:124
void LongestLine()
Set fLongestLine.
Definition: TGText.cxx:1219
char GetChar(ULong_t pos)
Get a character at the specified position from the line.
Definition: TGText.cxx:302
Bool_t SetCurrentRow(Long_t row)
Make specified row the current row.
Definition: TGText.cxx:1054
const char * cnt
Definition: TXMLSetup.cxx:74
virtual ~TGText()
Destroy text buffer.
Definition: TGText.cxx:396
T1 fFirst
Definition: X11Events.mm:86