Leviathan  0.8.0.0
Leviathan game engine
StringIterator.h
Go to the documentation of this file.
1 #pragma once
2 // ------------------------------------ //
3 #include "Define.h"
4 // ------------------------------------ //
5 #include "../Common/StringOperations.h"
6 #include "IteratorData.h"
7 #include "StringDataIterator.h"
8 
9 #include <functional>
10 #include <memory>
11 
12 
13 // Defining debug macro //
14 #if defined(_DEBUG) && (defined(LEVIATHAN_BUILD) || !defined(LEVIATHAN_UE_PLUGIN))
15 #define ALLOW_DEBUG
16 #define ITERATOR_ALLOW_DEBUG
17 #include "../Utility/Convert.h"
18 #include "Logger.h"
19 #include "utf8/checked.h"
20 #endif
21 
22 #ifdef ALLOW_DEBUG
23 #define ITR_FUNCDEBUG(x) \
24  { \
25  if(DebugMode) { \
26  Logger::Get()->Write("Iterator: procfunc: " + std::string(x)); \
27  } \
28  }
29 
30 #define ITR_COREDEBUG(x) \
31  { \
32  if(DebugMode) { \
33  Logger::Get()->Write("Iterator: " + std::string(x)); \
34  } \
35  }
36 #else
37 #define ITR_FUNCDEBUG(x) \
38  {}
39 #define ITR_COREDEBUG(x) \
40  {}
41 #endif // _DEBUG
42 
43 
44 namespace Leviathan {
45 
47 
53 };
54 
62 };
63 
68 };
69 
73 };
74 
77 
79  // SPECIAL_ITERATOR_ONNEWLINE_WHITESPACE = 0x8,
82 };
83 
85 #define SPECIAL_ITERATOR_FILEHANDLING \
86  SPECIAL_ITERATOR_ONNEWLINE_STOP | SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING
87 
88 
91 
94 
106 
110 
114 
129 };
130 
131 
132 
133 
136 public:
138  DLLEXPORT StringIterator(std::unique_ptr<StringDataIterator>&& iterator);
139 
141  DLLEXPORT StringIterator(const std::wstring& text);
143  DLLEXPORT StringIterator(const std::string& text);
146  DLLEXPORT StringIterator(const std::wstring* text);
149  DLLEXPORT StringIterator(const std::string* text);
150 
155 
156 
157  DLLEXPORT virtual ~StringIterator();
158 
160  DLLEXPORT void ReInit(std::unique_ptr<StringDataIterator>&& iterator);
162  DLLEXPORT void ReInit(const std::wstring& text);
164  DLLEXPORT void ReInit(const std::string& text);
167  DLLEXPORT void ReInit(const std::wstring* text);
170  DLLEXPORT void ReInit(const std::string* text);
171 
172  // Iterating functions //
173 
179  template<class RStrType>
180  std::unique_ptr<RStrType> GetStringInQuotes(QUOTETYPE quotes, int specialflags = 0)
181  {
182  // Setup the result object //
184 
185  // Iterate with our getting function //
186  StartIterating(
187  specialflags, &StringIterator::FindFirstQuotedString, &data, quotes, specialflags);
188 
189  // Create the substring from the result //
190  std::unique_ptr<RStrType> resultstr;
191 
192  // NULL if nothing found //
193  if(!data.Positions.Start || !data.Positions.End)
194  return nullptr;
195 
196  // Return the wanted part //
197  return GetSubstringFromIndexes<RStrType>(data.Positions.Start, data.Positions.End);
198  }
199 
206  template<class RStrType>
207  std::unique_ptr<RStrType> GetNextNumber(DECIMALSEPARATORTYPE decimal, int specialflags = 0)
208  {
209  // Setup the result object //
211 
212  // iterate over the string getting the proper part //
213  // Iterate with our getting function //
214  StartIterating(
215  specialflags, &StringIterator::FindNextNumber, &data, decimal, specialflags);
216 
217  // Check for nothing found //
218  if(!data.Positions.Start) {
219  return nullptr;
220  }
221 
222  // create substring of the wanted part //
223 
224 
225  // Make sure end is fine //
226  if(!data.Positions.End)
228 
229  // Return the wanted part //
230  return GetSubstringFromIndexes<RStrType>(data.Positions.Start, data.Positions.End);
231  }
232 
237  template<class RStrType>
238  std::unique_ptr<RStrType> GetNextCharacterSequence(int stopcaseflags, int specialflags = 0)
239  {
240  // Setup the result object //
242 
243  // Iterate with our getting function //
244  StartIterating(specialflags, &StringIterator::FindNextNormalCharacterString, &data,
245  stopcaseflags, specialflags);
246 
247  // check for nothing found //
248  if(!data.Positions.Start && !data.Positions.Start) {
249 
250  return NULL;
251  }
252 
253  // Make sure end is fine //
254  if(!data.Positions.End)
256 
257 
258  // Return the wanted part //
259  return GetSubstringFromIndexes<RStrType>(data.Positions.Start, data.Positions.End);
260  }
261 
266  template<class RStrType>
267  std::unique_ptr<RStrType> GetUntilEqualityAssignment(
268  EQUALITYCHARACTER stopcase, int specialflags = 0)
269  {
270  // Setup the result object //
272 
273  // Iterate with our getting function //
274  StartIterating(
275  specialflags, &StringIterator::FindUntilEquality, &data, stopcase, specialflags);
276 
277  // Check for validity //
278  if(!data.Positions.Start || data.SeparatorFound == false) {
279  // nothing found //
280  return nullptr;
281  }
282 
283  if(!data.Positions.End) {
284  // Set to start, this only happens if there is just one character //
285  data.Positions.End = data.Positions.Start;
286  }
287 
288  // Return the wanted part //
289  return GetSubstringFromIndexes<RStrType>(data.Positions.Start, data.Positions.End);
290  }
291 
292 
296  template<class RStrType>
297  std::unique_ptr<RStrType> GetUntilEnd()
298  {
299 
300  // Just return from here to the last character //
301  return GetSubstringFromIndexes<RStrType>(GetPosition(), GetLastValidCharIndex());
302  }
303 
308  template<class RStrType>
309  std::unique_ptr<RStrType> GetUntilLineEnd()
310  {
311 
312  // Setup the result object //
314 
315  // Iterate with our getting function //
316  StartIterating(0, &StringIterator::FindUntilNewLine, &data);
317 
318  // Check for validity //
319  if(!data.Positions.Start) {
320  // Nothing found //
321  return nullptr;
322  }
323 
324  if(!data.Positions.End) {
325  // Set to end of string //
327  }
328 
329  // Return the wanted part //
330  return GetSubstringFromIndexes<RStrType>(data.Positions.Start, data.Positions.End);
331  }
332 
333 
334 
343  template<class RStrType>
344  std::unique_ptr<RStrType> GetUntilNextCharacterOrNothing(
345  int charactertolookfor, int specialflags = 0)
346  {
347 
348  auto data = GetPositionsUntilACharacter(charactertolookfor, specialflags);
349 
350  // Check was the end found //
351  if(!data.FoundEnd || !data.Positions.Start) {
352  // not found the ending character //
353  return nullptr;
354  }
355 
356  // Return the wanted part //
357  return GetSubstringFromIndexes<RStrType>(data.Positions.Start, data.Positions.End);
358  }
359 
367  template<class RStrType>
368  std::unique_ptr<RStrType> GetUntilNextCharacterOrAll(
369  int charactertolookfor, int specialflags = 0)
370  {
371  auto data = GetPositionsUntilACharacter(charactertolookfor, specialflags);
372 
373  if(!data.Positions.Start || !data.Positions.End) {
374  // return empty string //
375  return nullptr;
376  }
377 
378  // Return all if not found //
379  if(!data.FoundEnd &&
380  (!data.NewLineBreak || !(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP))) {
381  return GetSubstringFromIndexes<RStrType>(
382  data.Positions.Start, GetLastValidCharIndex());
383  }
384 
385  // Return the wanted part //
386  return GetSubstringFromIndexes<RStrType>(data.Positions.Start, data.Positions.End);
387  }
388 
393  template<class RStrType>
394  std::unique_ptr<RStrType> GetUntilCharacterSequence(
395  const RStrType& findstr, int specialflags = 0)
396  {
397  // Setup the result object //
399 
400  // Iterate with our getting function //
401  StartIterating(
402  specialflags, &StringIterator::FindUntilSequence<RStrType>, &data, specialflags);
403 
404  // Check for validity //
405  if(!data.Positions.Start) {
406  // Nothing found //
407  return nullptr;
408  }
409 
410  // This only happens when the string ends with a partial match //
411  // Example: look for "this", string is like this: my super nice th
412  if(!data.Positions.End) {
413  // Set to end of string //
414  data.Positions.End = GetLastValidCharIndex();
415  }
416 
417  // Return the wanted part //
418  return GetSubstringFromIndexes<RStrType>(data.Positions.Start, data.Positions.End);
419  }
420 
428  template<class RStrType>
429  std::unique_ptr<RStrType> GetStringInBracketsRecursive(int specialflags = 0)
430  {
431 
432  // Setup the result object //
434 
435  // Iterate with our getting function //
436  StartIterating(specialflags, &StringIterator::FindInMatchingParentheses, &data, '[',
437  ']', specialflags);
438 
439  // Create the substring from the result //
440  std::unique_ptr<RStrType> resultstr;
441 
442  // NULL if nothing found //
443  if(!data.Positions.Start || !data.Positions.End)
444  return nullptr;
445 
446  // Return the wanted part //
447  return GetSubstringFromIndexes<RStrType>(data.Positions.Start, data.Positions.End);
448  }
449 
452  void inline SkipWhiteSpace(int specialflags = 0)
453  {
454 
456  }
457 
463  void SkipCharacters(int chartoskip, int additionalflag = 0, int specialflags = 0)
464  {
465  IteratorCharacterData stufftoskip(chartoskip);
466 
467  // Iterate over the string skipping until hit something that doesn't need to be
468  // skipped
469  StartIterating(specialflags, &StringIterator::SkipSomething, stufftoskip,
470  additionalflag, specialflags);
471  }
472 
473  // Utility functions //
474 
475 #ifdef ITERATOR_ALLOW_DEBUG
476  void SetDebugMode(bool mode)
478  {
479  DebugMode = mode;
480  }
481 #endif
482 
487  inline size_t GetPosition()
488  {
489 
490  return DataIterator->CurrentIteratorPosition();
491  }
492 
494  inline size_t GetCurrentLine()
495  {
496 
497  return DataIterator->GetCurrentLineNumber();
498  }
499 
501  inline int GetCharacter(size_t forward = 0)
502  {
503 
504  // Special case for current character //
505  if(!forward) {
506 
507  if(!CurrentStored) {
508 
509  if(!DataIterator->GetNextCharCode(CurrentCharacter, 0)) {
510 
511  // Invalid position //
512  return -1;
513  }
514 
515  CurrentStored = true;
516 
518  "Current char: (" + Convert::CodePointToUtf8(CurrentCharacter) + ")");
519  }
520 
521  return CurrentCharacter;
522  }
523 
524  // Get the character from our iterator and store it to a temporary value
525  // and then return it
526  int tmpval = -1;
527  DataIterator->GetNextCharCode(tmpval, forward);
528 
529  ITR_COREDEBUG("Peek forward char: (" + Convert::CodePointToUtf8(tmpval) + ")");
530 
531  return tmpval;
532  }
533 
535  inline bool IsAtNewLine()
536  {
537 
538  // Ignore new lines if '\' is put before them
539  if(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)
540  return false;
541 
543  }
544 
547 
549  inline size_t GetLastValidCharIndex() const
550  {
551 
552  return DataIterator->GetLastValidIteratorPosition();
553  }
554 
558  inline bool MoveToNext()
559  {
560 
561  DataIterator->MoveToNextCharacter();
562  bool valid = DataIterator->IsPositionValid();
563  // It's important to reset this //
564  CurrentStored = false;
565 
566  // We need to handle the flags on this position if we aren't on the first character //
567  if(valid && DataIterator->CurrentIteratorPosition() != 0) {
568 
569  ITR_COREDEBUG("Move to next");
570 
571  CheckActiveFlags();
572 
573  // check current character //
574  HandleSpecialCharacters();
575  }
576 
577  return valid;
578  }
579 
581  DLLEXPORT void SkipLineEnd();
582 
584  inline bool IsOutOfBounds()
585  {
586 
587  return !DataIterator->IsPositionValid();
588  }
589 
590  // Flag checking methods for outside callers //
591  inline bool IsInsideString()
592  {
593 
594  return CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING;
595  }
596 
597  inline bool IsInsideComment()
598  {
599 
600  return CurrentFlags & ITERATORFLAG_SET_INSIDE_CCOMMENT;
601  }
602 
604  template<class STRSType>
605  std::unique_ptr<STRSType> GetSubstringFromIndexes(
606  size_t firstcharacter, size_t lastcharacter) const
607  {
608  // Don't want to do anything if no string //
609  if(!DataIterator)
610  return nullptr;
611 
612  // Return a substring from our data source //
613  std::unique_ptr<STRSType> returnval(new STRSType());
614 
615  if(DataIterator->ReturnSubString(firstcharacter, lastcharacter, *returnval)) {
616 
617  return returnval;
618  }
619 
620  // It failed for some reason //
621  return nullptr;
622  }
623 
624 
626  IteratorFindUntilData GetPositionsUntilACharacter(int character, int specialflags = 0)
627  {
628  // Setup the result object //
630 
631  // Iterate with our getting function //
632  StartIterating(specialflags, &StringIterator::FindUntilSpecificCharacter, &data,
633  character, specialflags);
634 
635 #ifdef ITERATOR_ALLOW_DEBUG
636  if(DebugMode) {
637  Logger::Get()->Write("Iterator: find GetPositionsUntilACharacter, positions: " +
639  ", found: " + Convert::ToString(data.FoundEnd));
640  }
641 #endif // _DEBUG
642 
643  return data;
644  }
645 
646 private:
647  StringIterator(const StringIterator& other) = delete;
648 
650  inline ITERATORCALLBACK_RETURNTYPE HandleSpecialCharacters()
651  {
652 
653  // check should this special character be ignored //
654  if(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)
656 
657  // check for special characters //
658  int character = GetCharacter();
659 
660  switch(character) {
661  case '\\': {
662  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT)) {
663  // ignore next special character //
664  CurrentFlags |= ITERATORFLAG_SET_IGNORE_SPECIAL;
665 
666 #ifdef ALLOW_DEBUG
667  if(DebugMode) {
668  Logger::Get()->Write("Iterator: setting: ITERATORFLAG_SET_IGNORE_SPECIAL");
669  }
670 #endif // _DEBUG
671  }
672  } break;
673  case '"': {
674  // Strings cannot be inside comments //
675  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT)) {
676  // a string //
677  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING_DOUBLE)) {
678 #ifdef ALLOW_DEBUG
679  if(DebugMode) {
680  Logger::Get()->Write(
681  "Iterator: setting: ITERATORFLAG_SET_INSIDE_STRING_DOUBLE");
682  }
683 
684  if(DebugMode && !(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING)) {
685  Logger::Get()->Write(
686  "Iterator: setting: ITERATORFLAG_SET_INSIDE_STRING");
687  }
688 #endif // _DEBUG
689  // set //
691 
692  // set as inside string //
693  CurrentFlags |= ITERATORFLAG_SET_INSIDE_STRING;
694 
695  } else {
696 #ifdef ALLOW_DEBUG
697  if(DebugMode) {
698  Logger::Get()->Write("Iterator: set flag end: "
699  "ITERATORFLAG_SET_INSIDE_STRING_DOUBLE");
700  }
701 #endif // _DEBUG
702  // set ending flag //
704  }
705  }
706  } break;
707  case '\'': {
708  // Strings cannot be inside comments //
709  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT)) {
710  // a string //
711  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING_SINGLE)) {
712 #ifdef ALLOW_DEBUG
713  if(DebugMode) {
714  Logger::Get()->Write(
715  "Iterator: setting: ITERATORFLAG_SET_INSIDE_STRING_SINGLE");
716  }
717 
718  if(DebugMode && !(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING)) {
719  Logger::Get()->Write(
720  "Iterator: setting: ITERATORFLAG_SET_INSIDE_STRING");
721  }
722 #endif // _DEBUG
723  // set //
725 
726  // set as inside string //
727  CurrentFlags |= ITERATORFLAG_SET_INSIDE_STRING;
728 
729  } else {
730 #ifdef ALLOW_DEBUG
731  if(DebugMode) {
732  Logger::Get()->Write("Iterator: set flag end: "
733  "ITERATORFLAG_SET_INSIDE_STRING_SINGLE");
734  }
735 #endif // _DEBUG
736 
738  }
739  }
740  } break;
741  case '/': {
742  // Comments cannot be inside strings //
743  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING)) {
744  // There might be a comment beginning //
745  int nextchar = GetCharacter(1);
746 
747  if(nextchar == '/') {
748  // C++-style comment starts //
749  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_CPPCOMMENT)) {
750 #ifdef ALLOW_DEBUG
751  if(DebugMode) {
752  Logger::Get()->Write(
753  "Iterator: setting: ITERATORFLAG_SET_INSIDE_CPPCOMMENT");
754  }
755 
756  if(DebugMode && !(CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT)) {
757  Logger::Get()->Write(
758  "Iterator: setting: ITERATORFLAG_SET_INSIDE_COMMENT");
759  }
760 #endif // _DEBUG
761  CurrentFlags |= ITERATORFLAG_SET_INSIDE_CPPCOMMENT;
762  CurrentFlags |= ITERATORFLAG_SET_INSIDE_COMMENT;
763  }
764 
765 
766  } else if(nextchar == '*') {
767  // C-style comment starts //
768  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_CCOMMENT)) {
769 #ifdef ALLOW_DEBUG
770  if(DebugMode) {
771  Logger::Get()->Write(
772  "Iterator: setting: ITERATORFLAG_SET_INSIDE_CCOMMENT");
773  }
774 
775  if(DebugMode && !(CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT)) {
776  Logger::Get()->Write(
777  "Iterator: setting: ITERATORFLAG_SET_INSIDE_COMMENT");
778  }
779 #endif // _DEBUG
780  CurrentFlags |= ITERATORFLAG_SET_INSIDE_CCOMMENT;
781  CurrentFlags |= ITERATORFLAG_SET_INSIDE_COMMENT;
782  }
783 
784  } else if(CurrentFlags & ITERATORFLAG_SET_INSIDE_CCOMMENT) {
785  // C-style comment might end //
786 
787  int previouschar = GetPreviousCharacter();
788 
789  if(previouschar == '*') {
790 
791  // Set as ending //
792  CurrentFlags |= ITERATORFLAG_SET_CCOMMENT_END;
793 #ifdef ALLOW_DEBUG
794  if(DebugMode) {
795  Logger::Get()->Write(
796  "Iterator: set flag end: ITERATORFLAG_SET_CCOMMENT_END");
797  }
798 #endif // _DEBUG
799  }
800  }
801  }
802 
803  } break;
804  }
805 
806  if(IsAtNewLine()) {
807  // A C++-style comment might end //
808  if(CurrentFlags & ITERATORFLAG_SET_INSIDE_CPPCOMMENT) {
809  // Set as ending //
810  CurrentFlags |= ITERATORFLAG_SET_CPPCOMMENT_END;
811 #ifdef ALLOW_DEBUG
812  if(DebugMode) {
813  Logger::Get()->Write(
814  "Iterator: set flag end: ITERATORFLAG_SET_CPPCOMMENT_END");
815  }
816 #endif // _DEBUG
817  }
818  }
819 
821  }
822 
824  inline ITERATORCALLBACK_RETURNTYPE CheckActiveFlags()
825  {
826  if(CurrentFlags & ITERATORFLAG_SET_STOP)
828 
829  // Reset 1 character long flags //
830  if(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL) {
831 #ifdef ALLOW_DEBUG
832  if(DebugMode) {
833  Logger::Get()->Write("Iterator: flag: STRINGITERATOR_IGNORE_SPECIAL");
834  }
835 #endif // _DEBUG
836 
837  // check should end now //
838  if(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL_END) {
839 #ifdef ALLOW_DEBUG
840  if(DebugMode) {
841  Logger::Get()->Write(
842  "Iterator: flag ended: STRINGITERATOR_IGNORE_SPECIAL");
843  }
844 #endif // _DEBUG
845  // unset both //
846  CurrentFlags &= ~ITERATORFLAG_SET_IGNORE_SPECIAL_END;
847  CurrentFlags &= ~ITERATORFLAG_SET_IGNORE_SPECIAL;
848 
849  } else {
850 #ifdef ALLOW_DEBUG
851  if(DebugMode) {
852  Logger::Get()->Write("Iterator: flag ends next character: "
853  "ITERATORFLAG_SET_IGNORE_SPECIAL");
854  }
855 #endif // _DEBUG
856  // set to end next character //
857  CurrentFlags |= ITERATORFLAG_SET_IGNORE_SPECIAL_END;
858  }
859  }
860 
861  // reset end flags before we process this cycle further //
862  if(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING_DOUBLE_END) {
863 #ifdef ALLOW_DEBUG
864  if(DebugMode) {
865  Logger::Get()->Write(
866  "Iterator: flag ends: ITERATORFLAG_SET_INSIDE_STRING_DOUBLE");
867  }
868 #endif // _DEBUG
869  // unset flag //
870  CurrentFlags &= ~ITERATORFLAG_SET_INSIDE_STRING_DOUBLE;
872  }
873 
874  if(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING_SINGLE_END) {
875 #ifdef ALLOW_DEBUG
876  if(DebugMode) {
877  Logger::Get()->Write(
878  "Iterator: flag ends: ITERATORFLAG_SET_INSIDE_STRING_SINGLE");
879  }
880 #endif // _DEBUG
881  // unset flag //
882  CurrentFlags &= ~ITERATORFLAG_SET_INSIDE_STRING_SINGLE;
884  }
885 
886  // Check can we unset the whole string flag //
887  if(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING) {
888  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING_DOUBLE) &&
889  !(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING_SINGLE)) {
890 #ifdef ALLOW_DEBUG
891  if(DebugMode) {
892  Logger::Get()->Write(
893  "Iterator: flag ends: ITERATORFLAG_SET_INSIDE_STRING");
894  }
895 #endif // _DEBUG
896  // can unset this //
897  CurrentFlags &= ~ITERATORFLAG_SET_INSIDE_STRING;
898  }
899  }
900 
901  // Unsetting comment flags //
902  if(CurrentFlags & ITERATORFLAG_SET_CPPCOMMENT_END) {
903 #ifdef ALLOW_DEBUG
904  if(DebugMode) {
905  Logger::Get()->Write("Iterator: flag ends: ITERATORFLAG_SET_CPPCOMMENT_END");
906  }
907 #endif // _DEBUG
908  // unset flag //
909  CurrentFlags &= ~ITERATORFLAG_SET_CPPCOMMENT_END;
910  CurrentFlags &= ~ITERATORFLAG_SET_INSIDE_CPPCOMMENT;
911  }
912 
913  // C-style flag //
914  if(CurrentFlags & ITERATORFLAG_SET_CCOMMENT_END) {
915 #ifdef ALLOW_DEBUG
916  if(DebugMode) {
917  Logger::Get()->Write("Iterator: flag ends: ITERATORFLAG_SET_CCOMMENT_END");
918  }
919 #endif // _DEBUG
920  // unset flag //
921  CurrentFlags &= ~ITERATORFLAG_SET_CCOMMENT_END;
922  CurrentFlags &= ~ITERATORFLAG_SET_INSIDE_CCOMMENT;
923  }
924 
925  // Check can we unset the whole comment flag //
926  if(CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT) {
927  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_CPPCOMMENT) &&
928  !(CurrentFlags & ITERATORFLAG_SET_INSIDE_CCOMMENT)) {
929 #ifdef ALLOW_DEBUG
930  if(DebugMode) {
931  Logger::Get()->Write(
932  "Iterator: flag ends: ITERATORFLAG_SET_INSIDE_COMMENT");
933  }
934 #endif // _DEBUG
935  // can unset this //
936  CurrentFlags &= ~ITERATORFLAG_SET_INSIDE_COMMENT;
937  }
938  }
939 
940 
942  }
943 
944  template<typename T, typename R, typename... Args>
945  R proxycall(T& obj, R (T::*mf)(Args...), Args&&... args)
946  {
947  return (obj.*mf)(std::forward<Args>(args)...);
948  }
949 
953  template<typename... Params, typename... Args>
954  inline void StartIterating(int specialflagcopy,
955  ITERATORCALLBACK_RETURNTYPE (StringIterator::*mf)(Params...), Args&&... args)
956  {
957 #ifdef ITERATOR_ALLOW_DEBUG
958  if(DebugMode) {
959  Logger::Get()->Write("Iterator: begin ----------------------");
960  }
961 #endif // ITERATOR_ALLOW_DEBUG
962  // We want to skip multiple checks on same character
963  // so we skip checks on first character when starting except
964  // the beginning of the string
965  bool IsStartUpLoop = GetPosition() == 0 ? true : false;
966 
967  bool firstiter = true;
968  if(IsStartUpLoop)
969  firstiter = false;
970 
971  for(; DataIterator->IsPositionValid(); DataIterator->MoveToNextCharacter()) {
972 
973  // The GetCharacter call will cache the result
974  // but there might be iterators that don't want to get the current character
975 #ifdef ITERATOR_ALLOW_DEBUG
976 
977  if(DebugMode) {
978  int chara = GetCharacter();
979 
980  std::string datathing =
981  "Iterator: iterating: " + Convert::ToString(GetPosition()) + " (";
982 
983  // Encode the character //
984  datathing += Convert::CodePointToUtf8(chara) + ")";
985 
986  Logger::Get()->Write(datathing);
987  }
988 
989 #endif // ITERATOR_ALLOW_DEBUG
990 
991  // First iteration call is the same as the last so skip it //
992  if(!firstiter) {
993 
994  if(CheckActiveFlags() == ITERATORCALLBACK_RETURNTYPE_STOP)
995  break;
996 
997  // check current character //
998  if(HandleSpecialCharacters() == ITERATORCALLBACK_RETURNTYPE_STOP)
999  break;
1000  }
1001 
1002  firstiter = false;
1003 
1004  // Check for special cases //
1005 
1006  // valid character/valid iteration call callback //
1007  ITERATORCALLBACK_RETURNTYPE retval = (this->*mf)(std::forward<Args>(args)...);
1008  if(retval == ITERATORCALLBACK_RETURNTYPE_STOP) {
1009 
1010 #ifdef ITERATOR_ALLOW_DEBUG
1011  if(DebugMode) {
1012  Logger::Get()->Write("Iterator: stop ----------------------");
1013  }
1014 #endif // ITERATOR_ALLOW_DEBUG
1015  break;
1016  }
1017 
1018  // Character changes after this //
1019  CurrentStored = false;
1020  }
1021  }
1022 
1023 
1024  // ------------------------------------ //
1026  bool HandlesDelete = false;
1027 
1028 #ifdef ITERATOR_ALLOW_DEBUG
1029  bool DebugMode = false;
1031 #endif
1032 
1034  StringDataIterator* DataIterator = nullptr;
1035 
1038  int CurrentFlags = 0;
1039 
1041  int CurrentCharacter = -1;
1042 
1044  bool CurrentStored = false;
1045 
1046 protected:
1047  // Iteration functions //
1048 
1050  IteratorPositionData* data, QUOTETYPE quotes, int specialflags)
1051  {
1052  bool TakeChar = true;
1053  bool End = false;
1054 
1055  if(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP && IsAtNewLine()) {
1056  ITR_FUNCDEBUG("Stopping to new line");
1057 
1058  if(data->Positions.Start) {
1059  // Set the last character to two before this
1060  // (skip the current and " and end there)
1061  int previouscheck = GetPreviousCharacter();
1062 
1063  // Check do we need to go back 2 characters or just one //
1064  if((quotes == QUOTETYPE_BOTH &&
1065  (previouscheck == '"' || previouscheck == '\'')) ||
1066  (quotes == QUOTETYPE_DOUBLEQUOTES && previouscheck == '"') ||
1067  (quotes == QUOTETYPE_SINGLEQUOTES && previouscheck == '\'')) {
1068  ITR_FUNCDEBUG("Going back over an extra quote character");
1069  data->Positions.End = GetPosition() - 2;
1070  } else {
1071  data->Positions.End = GetPosition() - 1;
1072  }
1073 
1074  ITR_FUNCDEBUG("Ending to new line, end is now: " +
1076  }
1077 
1078  SkipLineEnd();
1080  }
1081 
1082  int currentcharacter = GetCharacter();
1083 
1084  switch(quotes) {
1085  case QUOTETYPE_BOTH: {
1086  if(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING) {
1087  // check if we are on the quotes, because we don't want those //
1088  if(currentcharacter == '"' || currentcharacter == '\'') {
1089  // if we aren't ignoring special disallow //
1090  if(!(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)) {
1091  TakeChar = false;
1092  ITR_FUNCDEBUG("Found quote character");
1093  }
1094  }
1095 
1096  } else {
1097  End = true;
1098  ITR_FUNCDEBUG("Outside quotes");
1099  }
1100  } break;
1101  case QUOTETYPE_SINGLEQUOTES: {
1102  if(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING_SINGLE) {
1103  // check if we are on the quotes, because we don't want those //
1104  if(currentcharacter == '\'') {
1105  // if we aren't ignoring special disallow //
1106  if(!(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)) {
1107  TakeChar = false;
1108  ITR_FUNCDEBUG("Found quote character");
1109  }
1110  }
1111 
1112  } else {
1113  End = true;
1114  ITR_FUNCDEBUG("Outside quotes");
1115  }
1116  } break;
1117  case QUOTETYPE_DOUBLEQUOTES: {
1118  if(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING_DOUBLE) {
1119  // check if we are on the quotes, because we don't want those //
1120  if(currentcharacter == '"') {
1121  // if we aren't ignoring special disallow //
1122  if(!(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)) {
1123  TakeChar = false;
1124  ITR_FUNCDEBUG("Found quote character");
1125  }
1126  }
1127 
1128  } else {
1129  End = true;
1130  ITR_FUNCDEBUG("Outside quotes");
1131  }
1132  } break;
1133  }
1134 
1135  // If we have found a character this is on the ending quote //
1136  if(!TakeChar && data->Positions.Start) {
1137 
1138  // Set the last character to the one before this (skip the " and end there) //
1139  data->Positions.End = GetPosition() - 1;
1140  ITR_FUNCDEBUG(
1141  "On ending quote, end is now: " + Convert::ToString(data->Positions.End));
1142  }
1143 
1144  if(End) {
1145  // if we have found at least a character we can end this here //
1146  if(data->Positions.Start) {
1147  // Set the last character to two before this
1148  // (skip the current and " and end there)
1149  data->Positions.End = GetPosition() - 2;
1150  ITR_FUNCDEBUG("Ending outside quotes, end is now: " +
1151  Convert::ToString(data->Positions));
1153  }
1154  } else if(TakeChar) {
1155  // check is this first quoted character //
1156  if(!data->Positions.Start) {
1157  // first position! //
1158  data->Positions.Start = GetPosition();
1159  ITR_FUNCDEBUG(
1160  "First character found: " + Convert::ToString(data->Positions.Start));
1161  }
1162  }
1163 
1165  }
1166 
1168  IteratorPositionData* data, int stopflags, int specialflags)
1169  {
1170  bool IsValid = true;
1171 
1172  if(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP && IsAtNewLine()) {
1173  ITR_FUNCDEBUG("Stopping to new line");
1174 
1175  if(data->Positions.Start) {
1176  // ended //
1177  data->Positions.End = GetPosition() - 1;
1178  ITR_FUNCDEBUG("Ending to new line, end is now: " +
1180  }
1181 
1182  SkipLineEnd();
1184  }
1185 
1186  int currentcharacter = GetCharacter();
1187 
1188  // If set this is invalid inside comments //
1189  if((specialflags & SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING) &&
1190  (CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT)) {
1191  IsValid = false;
1192  goto invalidcodelabelunnormalcharacter;
1193  }
1194 
1195  if((stopflags & UNNORMALCHARACTER_TYPE_LOWCODES ||
1196  stopflags & UNNORMALCHARACTER_TYPE_WHITESPACE) &&
1197  !(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING)) {
1198  if(currentcharacter <= ' ') {
1199  IsValid = false;
1200  goto invalidcodelabelunnormalcharacter;
1201  }
1202  }
1203 
1204  if(stopflags & UNNORMALCHARACTER_TYPE_NON_ASCII) {
1205 
1206  if(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING ||
1207  !((currentcharacter >= '0' && currentcharacter <= '9') ||
1208  (currentcharacter >= 'A' && currentcharacter <= 'Z') ||
1209  (currentcharacter >= 'a' && currentcharacter <= 'z'))) {
1210  IsValid = false;
1211  goto invalidcodelabelunnormalcharacter;
1212  }
1213  }
1214 
1216  !(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING) &&
1217  !(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)) {
1218  if(((currentcharacter <= '/' && currentcharacter >= '!') ||
1219  (currentcharacter <= '@' && currentcharacter >= ':') ||
1220  (currentcharacter <= '`' && currentcharacter >= '[') ||
1221  (currentcharacter <= '~' && currentcharacter >= '{')) &&
1222  !(currentcharacter == '_' || currentcharacter == '-')) {
1223  IsValid = false;
1224  goto invalidcodelabelunnormalcharacter;
1225  }
1226  }
1227 
1228  if(IsValid) {
1229  // check is this first character //
1230  if(!data->Positions.Start) {
1231  // first position! //
1232  data->Positions.Start = GetPosition();
1233  ITR_FUNCDEBUG("Started: " + Convert::ToString(data->Positions.Start));
1234  }
1235 
1236  } else {
1237 
1238  invalidcodelabelunnormalcharacter:
1239 
1240 
1241  // check for end //
1242  if(data->Positions.Start) {
1243  // ended //
1244  data->Positions.End = GetPosition() - 1;
1245  ITR_FUNCDEBUG("End now: " + Convert::ToString(data->Positions.End));
1247  }
1248  }
1249 
1251  }
1252 
1254  IteratorNumberFindData* data, DECIMALSEPARATORTYPE decimal, int specialflags)
1255  {
1256  // Check is the current element a part of a number //
1257 
1258  bool IsValid = false;
1259 
1260  if(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP && IsAtNewLine()) {
1261  ITR_FUNCDEBUG("Stopping to new line");
1262 
1263  if(data->Positions.Start) {
1264  // ended //
1265  data->Positions.End = GetPosition() - 1;
1266  ITR_FUNCDEBUG("Ending to new line, end is now: " +
1268  }
1269 
1270  SkipLineEnd();
1272  }
1273 
1274  // Comments might be skipped //
1275  if(!(specialflags & SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING) ||
1276  !(CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT)) {
1277  int currentcharacter = GetCharacter();
1278 
1279  if((currentcharacter >= 48) && (currentcharacter <= 57)) {
1280  // Is a plain old digit //
1281  IsValid = true;
1282 
1283  } else {
1284  // Check is it a decimal separator (1 allowed)
1285  // or a negativity sign in front
1286  if(currentcharacter == '+' || currentcharacter == '-') {
1287 
1288  if((data->DigitsFound < 1) && (!data->NegativeFound)) {
1289  IsValid = true;
1290  }
1291  data->NegativeFound = true;
1292  } else if(((currentcharacter == '.') &&
1293  ((decimal == DECIMALSEPARATORTYPE_DOT) ||
1294  (decimal == DECIMALSEPARATORTYPE_BOTH))) ||
1295  ((currentcharacter == ',') &&
1296  ((decimal == DECIMALSEPARATORTYPE_COMMA) ||
1297  (decimal == DECIMALSEPARATORTYPE_BOTH)))) {
1298  if((!data->DecimalFound) && (data->DigitsFound > 0)) {
1299  IsValid = true;
1300  data->DecimalFound = true;
1301  }
1302  }
1303  }
1304  } else {
1305  ITR_FUNCDEBUG("Ignoring inside a comment");
1306  }
1307 
1308  if(IsValid) {
1309  // check is this first digit //
1310  data->DigitsFound++;
1311  if(!data->Positions.Start) {
1312  // first position! //
1313 
1314  data->Positions.Start = GetPosition();
1315  ITR_FUNCDEBUG("Data started: " + Convert::ToString(data->Positions.Start));
1316  }
1317 
1318  } else {
1319  // check for end //
1320  if(data->Positions.Start) {
1321  // ended //
1322  data->Positions.End = GetPosition() - 1;
1323  ITR_FUNCDEBUG("End now: " + Convert::ToString(data->Positions.End));
1325  }
1326  }
1328  }
1329 
1331  IteratorAssignmentData* data, EQUALITYCHARACTER equality, int specialflags)
1332  {
1333  // check is current element a valid element //
1334  bool IsValid = true;
1335  bool IsStop = false;
1336 
1337  if(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP && IsAtNewLine()) {
1338  ITR_FUNCDEBUG("Stopping to new line");
1339 
1340  SkipLineEnd();
1342  }
1343 
1344  // Comments cannot be part of this //
1345  if((specialflags & SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING) &&
1346  (CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT)) {
1347  // Not valid inside a comment //
1348  ITR_FUNCDEBUG("Comment skipped");
1349  IsValid = false;
1350 
1351  } else {
1352 
1353  int charvalue = GetCharacter();
1354 
1355  // Skip if this is a space //
1356  if(charvalue < 33) {
1357  // Not allowed in a name //
1358  ITR_FUNCDEBUG("Whitespace skipped");
1359  IsValid = false;
1360  }
1361 
1362  if(equality == EQUALITYCHARACTER_TYPE_ALL) {
1363  // check for all possible value separators //
1364  if(charvalue == '=' || charvalue == ':') {
1365 
1366  if(!(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)) {
1367  // If ignored don't stop //
1368  ITR_FUNCDEBUG("Found = or :");
1369  IsStop = true;
1370  }
1371  }
1372  } else if(equality == EQUALITYCHARACTER_TYPE_EQUALITY) {
1373  // Check for an equality sign //
1374  if(charvalue == '=') {
1375  if(!(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)) {
1376  ITR_FUNCDEBUG("Found =");
1377  IsStop = true;
1378  }
1379  }
1380  } else if(equality == EQUALITYCHARACTER_TYPE_DOUBLEDOTSTYLE) {
1381  // Check does it match the characters //
1382  if(charvalue == ':') {
1383  if(!(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)) {
1384  ITR_FUNCDEBUG("Found :");
1385  IsStop = true;
1386  }
1387  }
1388  }
1389  }
1390 
1391  if(!IsStop) {
1392  // end if end already found //
1393  if(data->SeparatorFound) {
1394  ITR_FUNCDEBUG("Found stop");
1396  }
1397  } else {
1398  data->SeparatorFound = true;
1399  IsValid = false;
1400  }
1401 
1402  if(IsValid) {
1403  // Check is this the first character //
1404  if(!data->Positions.Start) {
1405  // first position! //
1406  data->Positions.Start = GetPosition();
1407  ITR_FUNCDEBUG("Data started: " + Convert::ToString(data->Positions.Start));
1408 
1409  } else {
1410  // Set end to this valid character //
1411  data->Positions.End = GetPosition();
1412  ITR_FUNCDEBUG("End now: " + Convert::ToString(data->Positions.End));
1413  }
1414  }
1415 
1416 
1418  }
1419 
1421  IteratorCharacterData& data, const int additionalskip, const int specialflags)
1422  {
1423  if(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP && IsAtNewLine()) {
1424  ITR_FUNCDEBUG("Stopping to new line");
1425 
1426  SkipLineEnd();
1428  }
1429 
1430  // We can probably always skip inside a comment //
1431  if((specialflags & SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING) &&
1432  (CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT)) {
1434  }
1435 
1436  // We can just return if we are inside a string //
1437  if(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING) {
1439  }
1440 
1441  // Check does the character match what is being skipped //
1442  int curchara = GetCharacter();
1443 
1444  if(additionalskip & UNNORMALCHARACTER_TYPE_LOWCODES) {
1445  if(curchara <= 32)
1447  }
1448 
1449  if(curchara == data.CharacterToUse) {
1450  // We want to skip it //
1452  }
1453 
1454  // didn't match to be skipped characters //
1456  }
1457 
1459  IteratorFindUntilData* data, int character, int specialflags)
1460  {
1461  // Can this character be added //
1462  bool ValidChar = true;
1463 
1464  if(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP && IsAtNewLine()) {
1465  ITR_FUNCDEBUG("Stopping to new line");
1466 
1467  if(data->Positions.Start) {
1468  // This should be fine to get here //
1469  data->Positions.End = GetPosition() - 1;
1470  ITR_FUNCDEBUG("Ending to new line, end is now: " +
1472  }
1473 
1474  // Make sure to not return until end of the whole string //
1475  data->NewLineBreak = true;
1476 
1477  SkipLineEnd();
1479  }
1480 
1481  int tmpchara = GetCharacter();
1482 
1483  // We can just continue if we are inside a string //
1484  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING) &&
1485  !((specialflags & SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING) &&
1486  (CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT))) {
1487  // Check did we encounter stop character //
1488 #ifdef ALLOW_DEBUG
1489  if(DebugMode) {
1490 
1491  std::string value = "Trying to match: ";
1492  utf8::append(tmpchara, std::back_inserter(value));
1493  value += "==" + Convert::ToString(tmpchara);
1494 
1495  Logger::Get()->Write("Iterator: procfunc: " + value);
1496  }
1497 #endif // ALLOW_DEBUG
1498 
1499  if(tmpchara == character) {
1500  // Skip if ignoring special characters //
1501  if(!(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)) {
1502  // Not valid character //
1503  ValidChar = false;
1504  ITR_FUNCDEBUG("Found match");
1505  // We must have started to encounter the stop character //
1506  if(data->Positions.Start) {
1507  // We encountered the stop character //
1508  data->FoundEnd = true;
1509  ITR_FUNCDEBUG("Encountered end");
1510  }
1511  }
1512  }
1513  } else {
1514 #ifdef ALLOW_DEBUG
1515  if((CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING)) {
1516  ITR_FUNCDEBUG("Ignoring inside string");
1517  }
1518  if((specialflags & SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING) &&
1519  (CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT)) {
1520  ITR_FUNCDEBUG("Ignoring inside comment");
1521  }
1522 #endif // _DEBUG
1523  }
1524 
1525  if(ValidChar) {
1526  // valid character set start if not already set //
1527  if(!data->Positions.Start) {
1528  data->Positions.Start = GetPosition();
1529  data->Positions.End = data->Positions.Start;
1530  ITR_FUNCDEBUG("Data started: " + Convert::ToString(data->Positions.Start));
1531  }
1533  }
1534  // let's stop if we have found something //
1535  if(data->Positions.Start) {
1536  // This should be fine to get here //
1537  data->Positions.End = GetPosition() - 1;
1538  ITR_FUNCDEBUG("Ending here: " + Convert::ToString(data->Positions.End));
1540  }
1541 
1542  // haven't found anything, we'll need to find something //
1544  }
1545 
1547  {
1548  // Continue if the current character is a new line character //
1549 
1550  // All line separator characters should be here //
1551  if(IsAtNewLine()) {
1552 
1553  if(!data->FoundEnd) {
1554  // Ignore the first new line //
1555  data->FoundEnd = true;
1556  ITR_FUNCDEBUG("Ignoring first newline character");
1557  goto positionisvalidlabelstringiteratorfindnewline;
1558  }
1559 
1560  // This is a new line character //
1561  ITR_FUNCDEBUG("Found newline character");
1562 
1563  // End before this character //
1564  data->Positions.End = GetPosition() - 1;
1565  ITR_FUNCDEBUG("Ending here: " + Convert::ToString(data->Positions));
1566 
1567  SkipLineEnd();
1569  }
1570 
1571  positionisvalidlabelstringiteratorfindnewline:
1572 
1573  // Set position //
1574  if(!data->Positions.Start) {
1575 
1576  // End before this character //
1577  data->Positions.Start = GetPosition();
1578  data->FoundEnd = true;
1579  ITR_FUNCDEBUG("Data started: " + Convert::ToString(data->Positions));
1580  }
1581 
1583  }
1584 
1586  IteratorNestingLevelData* data, int left, int right, int specialflags)
1587  {
1588  // Ignore if ignoring special characters //
1589  if(!(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL) &&
1590  !(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING)) {
1591  if(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP && IsAtNewLine()) {
1592 
1593  // Invalid, always //
1595  }
1596 
1597  int currentcharacter = GetCharacter();
1598 
1599  // Nesting level starts //
1600  if(currentcharacter == left) {
1601 
1602  ++data->NestingLevel;
1603 
1604  if(data->NestingLevel > 1) {
1605 
1606  // There where multiple lefts in a row, like "[[[...]]]"
1607  goto isinsidevalidleftrightpair;
1608  }
1609 
1611  }
1612 
1613  // One nesting level is ending //
1614  if(currentcharacter == right) {
1615 
1616  --data->NestingLevel;
1617 
1618  if(data->NestingLevel == 0) {
1619 
1620  data->Positions.End = GetPosition() - 1;
1622  }
1623  }
1624  }
1625 
1626  isinsidevalidleftrightpair:
1627 
1628  if(!data->Positions.Start && data->NestingLevel > 0) {
1629 
1630  data->Positions.Start = GetPosition();
1631  }
1632 
1634  }
1635 
1636 
1637 
1638  template<class AcceptStr>
1640  IteratorUntilSequenceData<AcceptStr>* data, int specialflags)
1641  {
1642  // First check if this is a line end //
1643  int curcharacter = GetCharacter();
1644 
1645  if(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP && IsAtNewLine()) {
1646 
1647  // Set the end to one before this, if found any //
1648  if(data->Positions.Start) {
1649 
1650  data->Positions.End = GetPosition() - 1;
1651  }
1652 
1653  SkipLineEnd();
1655  }
1656 
1657  // We may not be inside strings nor comments for checking //
1658  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING) &&
1659  (!(CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT) ||
1660  !(specialflags & SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING))) {
1661  // Check do we match the current position //
1662  if(curcharacter == data->StringToMatch[data->CurMatchedIndex]) {
1663 
1664  // Found a matching character //
1665 
1666  // Move to next match position and don't yet verify if this is a valid
1667  // character
1668  ++data->CurMatchedIndex;
1669 
1670  if(data->CurMatchedIndex >= data->StringToMatch.size()) {
1671 
1672  // End found //
1674  }
1675 
1677  }
1678  }
1679 
1680  // Go back to beginning of matching //
1681  data->CurMatchedIndex = 0;
1682 
1683  // All is fine //
1684  if(!data->Positions.Start) {
1685 
1686  data->Positions.Start = GetPosition();
1687  data->Positions.End = data->Positions.Start;
1688  } else {
1689 
1690  // This might be poisonous to performance, but this gets the job done //
1691  data->Positions.End = GetPosition();
1692  }
1693 
1695  }
1696 };
1697 
1698 } // namespace Leviathan
1699 #undef ALLOW_DEBUG
1700 
1701 #ifdef LEAK_INTO_GLOBAL
1703 #endif
std::unique_ptr< RStrType > GetUntilCharacterSequence(const RStrType &findstr, int specialflags=0)
Gets all characters until a sequence is matched.
ITERATORCALLBACK_RETURNTYPE FindUntilEquality(IteratorAssignmentData *data, EQUALITYCHARACTER equality, int specialflags)
DLLEXPORT void Write(const std::string &data) override
Definition: Logger.cpp:113
std::unique_ptr< RStrType > GetStringInBracketsRecursive(int specialflags=0)
Gets characters inside brackets.
virtual bool GetNextCharCode(int &codepointreceiver, size_t forward)=0
Gets the next character unicode code point (usually an ascii value)
static bool IsLineTerminator(int32_t codepoint)
\ is found, next special character will be ignored
The iterator has finished the current operation and will stop for now.
void SkipWhiteSpace(int specialflags=0)
Skips until characters that are not whitespace are found.
bool IsOutOfBounds()
Returns true when the read position is valid.
size_t GetLastValidCharIndex() const
Returns the last valid index on the iterator.
virtual DLLEXPORT ~StringIterator()
DLLEXPORT void ReInit(std::unique_ptr< StringDataIterator > &&iterator)
Changes the current iterator to the new iterator and goes to the beginning.
std::unique_ptr< STRSType > GetSubstringFromIndexes(size_t firstcharacter, size_t lastcharacter) const
Returns substring from the wanted indexes.
bool MoveToNext()
Skips the current character and moves to the next.
std::unique_ptr< RStrType > GetStringInQuotes(QUOTETYPE quotes, int specialflags=0)
Gets the next string in quotes.
ITERATORCALLBACK_RETURNTYPE FindNextNormalCharacterString(IteratorPositionData *data, int stopflags, int specialflags)
virtual void MoveToNextCharacter()=0
Moves the iterator forward.
DLLEXPORT int GetPreviousCharacter()
Gets the previous character.
ITERATORCALLBACK_RETURNTYPE FindInMatchingParentheses(IteratorNestingLevelData *data, int left, int right, int specialflags)
virtual size_t CurrentIteratorPosition() const =0
Gets the position of the iterator, for use with ReturnSubString and others.
virtual DLLEXPORT bool ReturnSubString(size_t startpos, size_t endpos, std::string &receiver)
size_t GetCurrentLine()
Returns the current line the processing is happening.
#define ITR_COREDEBUG(x)
int GetCharacter(size_t forward=0)
Gets the character in the position current + forward.
virtual bool IsPositionValid() const =0
Returns true when the iterator is still valid.
#define ITR_FUNCDEBUG(x)
std::unique_ptr< RStrType > GetUntilEqualityAssignment(EQUALITYCHARACTER stopcase, int specialflags=0)
Gets the string that is before the equality assignment.
std::unique_ptr< RStrType > GetUntilNextCharacterOrAll(int charactertolookfor, int specialflags=0)
Gets characters until a character or all remaining characters.
DLLEXPORT void SkipLineEnd()
Skips characters until the line number changes.
ITERATORCALLBACK_RETURNTYPE FindUntilSequence(IteratorUntilSequenceData< AcceptStr > *data, int specialflags)
Iterator class for getting parts of a string.
SPECIAL_ITERATOR
Special case handling flags for iterator.
void SkipCharacters(int chartoskip, int additionalflag=0, int specialflags=0)
Skips until chartoskip doesn't match the current character.
virtual DLLEXPORT size_t GetCurrentLineNumber() const
Returns the 1 based line number.
static std::string ToString(const T &val)
Definition: Convert.h:72
Set when a c style comment will end on the next character.
Iterator is currently inside double quoted string, "like this".
ITERATORCALLBACK_RETURNTYPE FindFirstQuotedString(IteratorPositionData *data, QUOTETYPE quotes, int specialflags)
static DLLEXPORT std::string CodePointToUtf8(int32_t codepoint)
Encodes a Unicode code point as an UTF8 string.
Definition: Convert.cpp:137
static DLLEXPORT Logger * Get()
Definition: Logger.cpp:106
IteratorFindUntilData GetPositionsUntilACharacter(int character, int specialflags=0)
Gets the position of the current character and the specified character.
Set when a c++ style comment will end on the next character.
ITERATORCALLBACK_RETURNTYPE
std::unique_ptr< RStrType > GetNextNumber(DECIMALSEPARATORTYPE decimal, int specialflags=0)
Gets the next number.
virtual size_t GetLastValidIteratorPosition() const =0
Gets the last valid index of the underlying string (not the last character but the last byte)
std::unique_ptr< RStrType > GetUntilNextCharacterOrNothing(int charactertolookfor, int specialflags=0)
Gets characters until a character or nothing if the specified character is not found.
DLLEXPORT StringIterator()
Creates an empty iterator.
std::unique_ptr< RStrType > GetUntilLineEnd()
Gets all characters until a line end.
Causes comments to be handled as whitespace/delimiting.
size_t GetPosition()
Returns the current reading position.
#define DLLEXPORT
Definition: Include.h:84
Iterator is currently inside a string.
ITERATORCALLBACK_RETURNTYPE FindUntilSpecificCharacter(IteratorFindUntilData *data, int character, int specialflags)
std::unique_ptr< RStrType > GetUntilEnd()
Gets all characters until the end.
ITERATORFLAG_SET
Set flags for the iterator, this is changed to this for performance.
ITERATORCALLBACK_RETURNTYPE FindUntilNewLine(IteratorFindUntilData *data)
The access mask controls which registered functions and classes a script sees.
Definition: GameModule.h:12
Iterator is currently inside single quoted string, 'like this'.
ITERATORCALLBACK_RETURNTYPE SkipSomething(IteratorCharacterData &data, const int additionalskip, const int specialflags)
bool IsAtNewLine()
Returns true if current character is a new line.
std::unique_ptr< RStrType > GetNextCharacterSequence(int stopcaseflags, int specialflags=0)
Gets the next sequence of characters according to stopcaseflags.
ITERATORCALLBACK_RETURNTYPE FindNextNumber(IteratorNumberFindData *data, DECIMALSEPARATORTYPE decimal, int specialflags)
octet_iterator append(uint32_t cp, octet_iterator result)
The library API - functions intended to be called by the users.
Definition: checked.h:73