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 "StringDataIterator.h"
6 #include "IteratorData.h"
7 #include "../Common/StringOperations.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 "Logger.h"
18 #include "../Utility/Convert.h"
19 #include "utf8/checked.h"
20 #endif
21 
22 #ifdef ALLOW_DEBUG
23 #define ITR_FUNCDEBUG(x) { \
24 if(DebugMode){ \
25  Logger::Get()->Write("Iterator: procfunc: " + std::string(x)); \
26 } \
27 }
28 
29 #define ITR_COREDEBUG(x) { \
30 if(DebugMode){ \
31  Logger::Get()->Write("Iterator: " + std::string(x)); \
32 } \
33 }
34 #else
35 #define ITR_FUNCDEBUG(x) {}
36 #define ITR_COREDEBUG(x) {}
37 #endif // _DEBUG
38 
39 
40 namespace Leviathan{
41 
43 
49 };
50 
58 };
59 
64 
68 };
69 
72 
74  //SPECIAL_ITERATOR_ONNEWLINE_WHITESPACE = 0x8,
77 };
78 
80 #define SPECIAL_ITERATOR_FILEHANDLING SPECIAL_ITERATOR_ONNEWLINE_STOP | SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING
81 
82 
85 
88 
100 
104 
108 
123 };
124 
125 
126 
127 
130 public:
132  DLLEXPORT StringIterator(std::unique_ptr<StringDataIterator>&& iterator);
133 
135  DLLEXPORT StringIterator(const std::wstring &text);
137  DLLEXPORT StringIterator(const std::string &text);
140  DLLEXPORT StringIterator(const std::wstring* text);
143  DLLEXPORT StringIterator(const std::string* text);
144 
149 
150 
151  DLLEXPORT virtual ~StringIterator();
152 
154  DLLEXPORT void ReInit(std::unique_ptr<StringDataIterator>&& iterator);
156  DLLEXPORT void ReInit(const std::wstring &text);
158  DLLEXPORT void ReInit(const std::string &text);
161  DLLEXPORT void ReInit(const std::wstring* text);
164  DLLEXPORT void ReInit(const std::string* text);
165 
166  // Iterating functions //
167 
173  template<class RStrType>
174  std::unique_ptr<RStrType> GetStringInQuotes(QUOTETYPE quotes,
175  int specialflags = 0)
176  {
177 
178  // Setup the result object //
180 
181  // Iterate with our getting function //
182  StartIterating(specialflags, &StringIterator::FindFirstQuotedString,
183  &data, quotes, specialflags);
184 
185  // Create the substring from the result //
186  std::unique_ptr<RStrType> resultstr;
187 
188  // NULL if nothing found //
189  if(!data.Positions.Start || !data.Positions.End)
190  return nullptr;
191 
192  // Return the wanted part //
193  return GetSubstringFromIndexes<RStrType>(data.Positions.Start, data.Positions.End);
194  }
195 
202  template<class RStrType>
203  std::unique_ptr<RStrType> GetNextNumber(DECIMALSEPARATORTYPE decimal,
204  int specialflags = 0)
205  {
206 
207  // Setup the result object //
209 
210  // iterate over the string getting the proper part //
211  // Iterate with our getting function //
212  StartIterating(specialflags, &StringIterator::FindNextNumber,
213  &data, decimal, specialflags);
214 
215  // Check for nothing found //
216  if(!data.Positions.Start){
217  return nullptr;
218  }
219 
220  // create substring of the wanted part //
221 
222 
223  // Make sure end is fine //
224  if(!data.Positions.End)
226 
227  // Return the wanted part //
228  return GetSubstringFromIndexes<RStrType>(data.Positions.Start, data.Positions.End);
229  }
230 
235  template<class RStrType>
236  std::unique_ptr<RStrType> GetNextCharacterSequence(int stopcaseflags,
237  int specialflags = 0)
238  {
239 
240  // Setup the result object //
242 
243  // Iterate with our getting function //
244  StartIterating(specialflags, &StringIterator::FindNextNormalCharacterString,
245  &data, 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(EQUALITYCHARACTER stopcase,
268  int specialflags = 0)
269  {
270 
271  // Setup the result object //
273 
274  // Iterate with our getting function //
275  StartIterating(specialflags, &StringIterator::FindUntilEquality,
276  &data, stopcase, specialflags);
277 
278  // Check for validity //
279  if(!data.Positions.Start || data.Positions.Start == data.Positions.End ||
280  data.SeparatorFound == false)
281  {
282  // nothing found //
283  return nullptr;
284  }
285 
286  if(!data.Positions.End){
287  // Set to start, this only happens if there is just one character //
288  data.Positions.End = data.Positions.Start;
289  }
290 
291  // Return the wanted part //
292  return GetSubstringFromIndexes<RStrType>(data.Positions.Start, data.Positions.End);
293  }
294 
295 
299  template<class RStrType>
300  std::unique_ptr<RStrType> GetUntilEnd(){
301 
302  // Just return from here to the last character //
303  return GetSubstringFromIndexes<RStrType>(GetPosition(), GetLastValidCharIndex());
304  }
305 
310  template<class RStrType>
311  std::unique_ptr<RStrType> GetUntilLineEnd(){
312 
313  // Setup the result object //
315 
316  // Iterate with our getting function //
317  StartIterating(0, &StringIterator::FindUntilNewLine, &data);
318 
319  // Check for validity //
320  if(!data.Positions.Start){
321  // Nothing found //
322  return nullptr;
323  }
324 
325  if(!data.Positions.End){
326  // Set to end of string //
328  }
329 
330  // Return the wanted part //
331  return GetSubstringFromIndexes<RStrType>(data.Positions.Start, data.Positions.End);
332  }
333 
334 
335 
344  template<class RStrType>
345  std::unique_ptr<RStrType> GetUntilNextCharacterOrNothing(int charactertolookfor,
346  int specialflags = 0)
347  {
348 
349  auto data = GetPositionsUntilACharacter(charactertolookfor, specialflags);
350 
351  // Check was the end found //
352  if(!data.FoundEnd || !data.Positions.Start){
353  // not found the ending character //
354  return nullptr;
355  }
356 
357  // Return the wanted part //
358  return GetSubstringFromIndexes<RStrType>(data.Positions.Start, data.Positions.End);
359  }
360 
368  template<class RStrType>
369  std::unique_ptr<RStrType> GetUntilNextCharacterOrAll(int charactertolookfor,
370  int specialflags = 0)
371  {
372 
373  auto data = GetPositionsUntilACharacter(charactertolookfor, specialflags);
374 
375  if(!data.Positions.Start || !data.Positions.End){
376  // return empty string //
377  return nullptr;
378  }
379 
380  // Return all if not found //
381  if(!data.FoundEnd && (!data.NewLineBreak ||
382  !(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP)))
383  {
384 
385  return GetSubstringFromIndexes<RStrType>(data.Positions.Start,
387  }
388 
389  // Return the wanted part //
390  return GetSubstringFromIndexes<RStrType>(data.Positions.Start, data.Positions.End);
391  }
392 
397  template<class RStrType>
398  std::unique_ptr<RStrType> GetUntilCharacterSequence(const RStrType &findstr,
399  int specialflags = 0)
400  {
401 
402  // Setup the result object //
404 
405  // Iterate with our getting function //
406  StartIterating(specialflags, &StringIterator::FindUntilSequence<RStrType>,
407  &data, specialflags);
408 
409  // Check for validity //
410  if(!data.Positions.Start){
411  // Nothing found //
412  return nullptr;
413  }
414 
415  // This only happens when the string ends with a partial match //
416  // Example: look for "this", string is like this: my super nice th
417  if(!data.Positions.End){
418  // Set to end of string //
419  data.Positions.End = GetLastValidCharIndex();
420  }
421 
422  // Return the wanted part //
423  return GetSubstringFromIndexes<RStrType>(data.Positions.Start, data.Positions.End);
424  }
425 
433  template<class RStrType>
434  std::unique_ptr<RStrType> GetStringInBracketsRecursive(int specialflags = 0){
435 
436  // Setup the result object //
438 
439  // Iterate with our getting function //
440  StartIterating(specialflags, &StringIterator::FindInMatchingParentheses,
441  &data, '[', ']', specialflags);
442 
443  // Create the substring from the result //
444  std::unique_ptr<RStrType> resultstr;
445 
446  // NULL if nothing found //
447  if(!data.Positions.Start || !data.Positions.End)
448  return nullptr;
449 
450  // Return the wanted part //
451  return GetSubstringFromIndexes<RStrType>(data.Positions.Start, data.Positions.End);
452  }
453 
456  void inline SkipWhiteSpace(int specialflags = 0){
457 
459  }
460 
466  void SkipCharacters(int chartoskip, int additionalflag = 0,
467  int specialflags = 0)
468  {
469 
470  IteratorCharacterData stufftoskip(chartoskip);
471 
472  // Iterate over the string skipping until hit something that doesn't need to be
473  // skipped
474  StartIterating(specialflags, &StringIterator::SkipSomething,
475  stufftoskip, additionalflag, specialflags);
476  }
477 
478  // Utility functions //
479 
480 #ifdef ITERATOR_ALLOW_DEBUG
481  void SetDebugMode(bool mode){
483 
484  DebugMode = mode;
485  }
486 #endif
487 
492  inline size_t GetPosition(){
493 
494  return DataIterator->CurrentIteratorPosition();
495  }
496 
498  inline size_t GetCurrentLine(){
499 
500  return DataIterator->GetCurrentLineNumber();
501  }
502 
504  inline int GetCharacter(size_t forward = 0){
505 
506  // Special case for current character //
507  if(!forward){
508 
509  if(!CurrentStored){
510 
511  if(!DataIterator->GetNextCharCode(CurrentCharacter, 0)){
512 
513  // Invalid position //
514  return -1;
515  }
516 
517  CurrentStored = true;
518 
519  ITR_COREDEBUG("Current char: (" +
520  Convert::CodePointToUtf8(CurrentCharacter) + ")");
521  }
522 
523  return CurrentCharacter;
524  }
525 
526  // Get the character from our iterator and store it to a temporary value
527  // and then return it
528  int tmpval = -1;
529  DataIterator->GetNextCharCode(tmpval, forward);
530 
531  ITR_COREDEBUG("Peek forward char: (" + Convert::CodePointToUtf8(tmpval) + ")");
532 
533  return tmpval;
534  }
535 
537  inline bool IsAtNewLine(){
538 
539  // Ignore new lines if '\' is put before them
540  if (CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)
541  return false;
542 
544  }
545 
548 
550  inline size_t GetLastValidCharIndex() const{
551 
552  return DataIterator->GetLastValidIteratorPosition();
553  }
554 
558  inline bool MoveToNext(){
559 
560  DataIterator->MoveToNextCharacter();
561  bool valid = DataIterator->IsPositionValid();
562  // It's important to reset this //
563  CurrentStored = false;
564 
565  // We need to handle the flags on this position if we aren't on the first character //
566  if(valid && DataIterator->CurrentIteratorPosition() != 0){
567 
568  ITR_COREDEBUG("Move to next");
569 
570  CheckActiveFlags();
571 
572  // check current character //
573  HandleSpecialCharacters();
574  }
575 
576  return valid;
577  }
578 
580  DLLEXPORT void SkipLineEnd();
581 
583  inline bool IsOutOfBounds(){
584 
585  return !DataIterator->IsPositionValid();
586  }
587 
588  // Flag checking methods for outside callers //
589  inline bool IsInsideString(){
590 
591  return CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING;
592  }
593 
594  inline bool IsInsideComment(){
595 
596  return CurrentFlags & ITERATORFLAG_SET_INSIDE_CCOMMENT;
597  }
598 
600  template<class STRSType>
601  std::unique_ptr<STRSType> GetSubstringFromIndexes(size_t firstcharacter,
602  size_t lastcharacter) const
603  {
604  // Don't want to do anything if no string //
605  if(!DataIterator)
606  return nullptr;
607 
608  // Return a substring from our data source //
609  std::unique_ptr<STRSType> returnval(new STRSType());
610 
611  if(DataIterator->ReturnSubString(firstcharacter, lastcharacter, *returnval)){
612 
613  return returnval;
614  }
615 
616  // It failed for some reason //
617  return nullptr;
618  }
619 
620 
623  int specialflags = 0)
624  {
625  // Setup the result object //
627 
628  // Iterate with our getting function //
629  StartIterating(specialflags, &StringIterator::FindUntilSpecificCharacter,
630  &data, character, specialflags);
631 
632  #ifdef ITERATOR_ALLOW_DEBUG
633  if(DebugMode){
634  Logger::Get()->Write("Iterator: find GetPositionsUntilACharacter, positions: " +
635  Convert::ToString(data.Positions) + ", found: "+
637  }
638  #endif // _DEBUG
639 
640  return data;
641  }
642 
643 private:
644 
645  StringIterator(const StringIterator &other) = delete;
646 
648  inline ITERATORCALLBACK_RETURNTYPE HandleSpecialCharacters(){
649 
650  // check should this special character be ignored //
651  if(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)
653 
654  // check for special characters //
655  int character = GetCharacter();
656 
657  switch(character){
658  case '\\':
659  {
660  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT)){
661  // ignore next special character //
662  CurrentFlags |= ITERATORFLAG_SET_IGNORE_SPECIAL;
663 
664  #ifdef ALLOW_DEBUG
665  if(DebugMode){
666  Logger::Get()->Write(
667  "Iterator: setting: ITERATORFLAG_SET_IGNORE_SPECIAL");
668  }
669  #endif // _DEBUG
670  }
671  }
672  break;
673  case '"':
674  {
675  // Strings cannot be inside comments //
676  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT)){
677  // a string //
678  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING_DOUBLE)){
679  #ifdef ALLOW_DEBUG
680  if(DebugMode){
681  Logger::Get()->Write(
682  "Iterator: setting: ITERATORFLAG_SET_INSIDE_STRING_DOUBLE");
683  }
684 
685  if(DebugMode && !(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING)){
686  Logger::Get()->Write(
687  "Iterator: setting: ITERATORFLAG_SET_INSIDE_STRING");
688  }
689  #endif // _DEBUG
690  // set //
692 
693  // set as inside string //
694  CurrentFlags |= ITERATORFLAG_SET_INSIDE_STRING;
695 
696  } else {
697  #ifdef ALLOW_DEBUG
698  if(DebugMode){
699  Logger::Get()->Write("Iterator: set flag end: "
700  "ITERATORFLAG_SET_INSIDE_STRING_DOUBLE");
701  }
702  #endif // _DEBUG
703  // set ending flag //
705  }
706  }
707  }
708  break;
709  case '\'':
710  {
711  // Strings cannot be inside comments //
712  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT)){
713  // a string //
714  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING_SINGLE)){
715  #ifdef ALLOW_DEBUG
716  if(DebugMode){
717  Logger::Get()->Write(
718  "Iterator: setting: ITERATORFLAG_SET_INSIDE_STRING_SINGLE");
719  }
720 
721  if(DebugMode && !(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING)){
722  Logger::Get()->Write(
723  "Iterator: setting: ITERATORFLAG_SET_INSIDE_STRING");
724  }
725  #endif // _DEBUG
726  // set //
728 
729  // set as inside string //
730  CurrentFlags |= ITERATORFLAG_SET_INSIDE_STRING;
731 
732  } else {
733  #ifdef ALLOW_DEBUG
734  if(DebugMode){
735  Logger::Get()->Write("Iterator: set flag end: "
736  "ITERATORFLAG_SET_INSIDE_STRING_SINGLE");
737  }
738  #endif // _DEBUG
739 
741  }
742  }
743  }
744  break;
745  case '/':
746  {
747  // Comments cannot be inside strings //
748  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING)){
749  // There might be a comment beginning //
750  int nextchar = GetCharacter(1);
751 
752  if(nextchar == '/'){
753  // C++-style comment starts //
754  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_CPPCOMMENT)){
755  #ifdef ALLOW_DEBUG
756  if(DebugMode){
757  Logger::Get()->Write(
758  "Iterator: setting: ITERATORFLAG_SET_INSIDE_CPPCOMMENT");
759  }
760 
761  if(DebugMode &&
762  !(CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT))
763  {
764  Logger::Get()->Write(
765  "Iterator: setting: ITERATORFLAG_SET_INSIDE_COMMENT");
766  }
767  #endif // _DEBUG
768  CurrentFlags |= ITERATORFLAG_SET_INSIDE_CPPCOMMENT;
769  CurrentFlags |= ITERATORFLAG_SET_INSIDE_COMMENT;
770  }
771 
772 
773  } else if(nextchar == '*'){
774  // C-style comment starts //
775  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_CCOMMENT)){
776  #ifdef ALLOW_DEBUG
777  if(DebugMode){
778  Logger::Get()->Write(
779  "Iterator: setting: ITERATORFLAG_SET_INSIDE_CCOMMENT");
780  }
781 
782  if(DebugMode &&
783  !(CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT))
784  {
785  Logger::Get()->Write(
786  "Iterator: setting: ITERATORFLAG_SET_INSIDE_COMMENT");
787  }
788  #endif // _DEBUG
789  CurrentFlags |= ITERATORFLAG_SET_INSIDE_CCOMMENT;
790  CurrentFlags |= ITERATORFLAG_SET_INSIDE_COMMENT;
791  }
792 
793  } else if(CurrentFlags & ITERATORFLAG_SET_INSIDE_CCOMMENT){
794  // C-style comment might end //
795 
796  int previouschar = GetPreviousCharacter();
797 
798  if(previouschar == '*'){
799 
800  // Set as ending //
801  CurrentFlags |= ITERATORFLAG_SET_CCOMMENT_END;
802  #ifdef ALLOW_DEBUG
803  if(DebugMode){
804  Logger::Get()->Write(
805  "Iterator: set flag end: ITERATORFLAG_SET_CCOMMENT_END");
806  }
807  #endif // _DEBUG
808  }
809  }
810  }
811 
812  }
813  break;
814  }
815 
816  if (IsAtNewLine()) {
817  // A C++-style comment might end //
818  if (CurrentFlags & ITERATORFLAG_SET_INSIDE_CPPCOMMENT) {
819  // Set as ending //
820  CurrentFlags |= ITERATORFLAG_SET_CPPCOMMENT_END;
821  #ifdef ALLOW_DEBUG
822  if (DebugMode) {
823  Logger::Get()->Write(
824  "Iterator: set flag end: ITERATORFLAG_SET_CPPCOMMENT_END");
825  }
826  #endif // _DEBUG
827  }
828  }
829 
831  }
832 
834  inline ITERATORCALLBACK_RETURNTYPE CheckActiveFlags(){
835  if(CurrentFlags & ITERATORFLAG_SET_STOP)
837 
838  // Reset 1 character long flags //
839  if(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL){
840  #ifdef ALLOW_DEBUG
841  if(DebugMode){
842  Logger::Get()->Write("Iterator: flag: STRINGITERATOR_IGNORE_SPECIAL");
843  }
844  #endif // _DEBUG
845 
846  // check should end now //
847  if(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL_END){
848  #ifdef ALLOW_DEBUG
849  if(DebugMode){
850  Logger::Get()->Write(
851  "Iterator: flag ended: STRINGITERATOR_IGNORE_SPECIAL");
852  }
853  #endif // _DEBUG
854  // unset both //
855  CurrentFlags &= ~ITERATORFLAG_SET_IGNORE_SPECIAL_END;
856  CurrentFlags &= ~ITERATORFLAG_SET_IGNORE_SPECIAL;
857 
858  } else {
859  #ifdef ALLOW_DEBUG
860  if(DebugMode){
861  Logger::Get()->Write("Iterator: flag ends next character: "
862  "ITERATORFLAG_SET_IGNORE_SPECIAL");
863  }
864  #endif // _DEBUG
865  // set to end next character //
866  CurrentFlags |= ITERATORFLAG_SET_IGNORE_SPECIAL_END;
867  }
868  }
869 
870  // reset end flags before we process this cycle further //
872  #ifdef ALLOW_DEBUG
873  if(DebugMode){
874  Logger::Get()->Write(
875  "Iterator: flag ends: ITERATORFLAG_SET_INSIDE_STRING_DOUBLE");
876  }
877  #endif // _DEBUG
878  // unset flag //
879  CurrentFlags &= ~ITERATORFLAG_SET_INSIDE_STRING_DOUBLE;
880  CurrentFlags &= ~ITERATORFLAG_SET_INSIDE_STRING_DOUBLE_END;
881  }
882 
884  #ifdef ALLOW_DEBUG
885  if(DebugMode){
886  Logger::Get()->Write(
887  "Iterator: flag ends: ITERATORFLAG_SET_INSIDE_STRING_SINGLE");
888  }
889  #endif // _DEBUG
890  // unset flag //
891  CurrentFlags &= ~ITERATORFLAG_SET_INSIDE_STRING_SINGLE;
892  CurrentFlags &= ~ITERATORFLAG_SET_INSIDE_STRING_SINGLE_END;
893  }
894 
895  // Check can we unset the whole string flag //
896  if(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING){
897  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING_DOUBLE) &&
898  !(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING_SINGLE))
899  {
900  #ifdef ALLOW_DEBUG
901  if(DebugMode){
902  Logger::Get()->Write(
903  "Iterator: flag ends: ITERATORFLAG_SET_INSIDE_STRING");
904  }
905  #endif // _DEBUG
906  // can unset this //
907  CurrentFlags &= ~ITERATORFLAG_SET_INSIDE_STRING;
908  }
909  }
910 
911  // Unsetting comment flags //
912  if(CurrentFlags & ITERATORFLAG_SET_CPPCOMMENT_END){
913  #ifdef ALLOW_DEBUG
914  if(DebugMode){
915  Logger::Get()->Write("Iterator: flag ends: ITERATORFLAG_SET_CPPCOMMENT_END");
916  }
917  #endif // _DEBUG
918  // unset flag //
919  CurrentFlags &= ~ITERATORFLAG_SET_CPPCOMMENT_END;
920  CurrentFlags &= ~ITERATORFLAG_SET_INSIDE_CPPCOMMENT;
921  }
922 
923  // C-style flag //
924  if(CurrentFlags & ITERATORFLAG_SET_CCOMMENT_END){
925  #ifdef ALLOW_DEBUG
926  if(DebugMode){
927  Logger::Get()->Write("Iterator: flag ends: ITERATORFLAG_SET_CCOMMENT_END");
928  }
929  #endif // _DEBUG
930  // unset flag //
931  CurrentFlags &= ~ITERATORFLAG_SET_CCOMMENT_END;
932  CurrentFlags &= ~ITERATORFLAG_SET_INSIDE_CCOMMENT;
933  }
934 
935  // Check can we unset the whole comment flag //
936  if(CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT){
937  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_CPPCOMMENT) &&
938  !(CurrentFlags & ITERATORFLAG_SET_INSIDE_CCOMMENT))
939  {
940  #ifdef ALLOW_DEBUG
941  if(DebugMode){
942  Logger::Get()->Write(
943  "Iterator: flag ends: ITERATORFLAG_SET_INSIDE_COMMENT");
944  }
945  #endif // _DEBUG
946  // can unset this //
947  CurrentFlags &= ~ITERATORFLAG_SET_INSIDE_COMMENT;
948  }
949  }
950 
951 
953  }
954 
955  template <typename T, typename R, typename ...Args>
956  R proxycall(T & obj, R(T::*mf)(Args...), Args &&... args) {
957  return (obj.*mf)(std::forward<Args>(args)...);
958  }
959 
963  template <typename... Params, typename... Args>
964  void StartIterating(int specialflagcopy,
965  ITERATORCALLBACK_RETURNTYPE(StringIterator::*mf)(Params...), Args&&... args)
966  {
967  #ifdef ITERATOR_ALLOW_DEBUG
968  if (DebugMode) {
969  Logger::Get()->Write("Iterator: begin ----------------------");
970  }
971  #endif // _DEBUG
972  // We want to skip multiple checks on same character
973  // so we skip checks on first character when starting except
974  // the beginning of the string
975  bool IsStartUpLoop = GetPosition() == 0 ? true : false;
976 
977  bool firstiter = true;
978  if (IsStartUpLoop)
979  firstiter = false;
980 
981  for (; DataIterator->IsPositionValid(); DataIterator->MoveToNextCharacter()) {
982 
983  // The GetCharacter call will cache the result
984  // but there might be iterators that don't want to get the current character
985  #ifdef ITERATOR_ALLOW_DEBUG
986  int chara = GetCharacter();
987 
988  if (DebugMode) {
989  // Convert to UTF8 //
990 
991  std::string datathing = "Iterator: iterating: " +
992  Convert::ToString(GetPosition()) + " (";
993 
994  // Encode the character //
995  datathing += Convert::CodePointToUtf8(chara) + ")";
996 
997  Logger::Get()->Write(datathing);
998  }
999 
1000  #endif // _DEBUG
1001 
1002  // First iteration call is the same as the last so skip it //
1003  if (!firstiter) {
1004 
1005  if (CheckActiveFlags() == ITERATORCALLBACK_RETURNTYPE_STOP)
1006  break;
1007 
1008  // check current character //
1009  if (HandleSpecialCharacters() == ITERATORCALLBACK_RETURNTYPE_STOP)
1010  break;
1011  }
1012 
1013  firstiter = false;
1014 
1015  // Check for special cases //
1016 
1017  // valid character/valid iteration call callback //
1018  ITERATORCALLBACK_RETURNTYPE retval = (this->*mf)(std::forward<Args>(args)...);
1019  if (retval == ITERATORCALLBACK_RETURNTYPE_STOP) {
1020 
1021  #ifdef ITERATOR_ALLOW_DEBUG
1022  if (DebugMode) {
1023  Logger::Get()->Write("Iterator: stop ----------------------");
1024  }
1025  #endif // _DEBUG
1026  break;
1027  }
1028 
1029  // Character changes after this //
1030  CurrentStored = false;
1031  }
1032  }
1033 
1034 
1035  // ------------------------------------ //
1037  bool HandlesDelete = false;
1038 
1039  #ifdef ITERATOR_ALLOW_DEBUG
1040  bool DebugMode = false;
1042  #endif
1043 
1045  StringDataIterator* DataIterator = nullptr;
1046 
1049  int CurrentFlags = 0;
1050 
1052  int CurrentCharacter = -1;
1053 
1055  bool CurrentStored = false;
1056 
1057  protected:
1058 
1059  // Iteration functions //
1060 
1062  IteratorPositionData* data, QUOTETYPE quotes, int specialflags)
1063  {
1064  bool TakeChar = true;
1065  bool End = false;
1066 
1067  if(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP && IsAtNewLine()){
1068  ITR_FUNCDEBUG("Stopping to new line");
1069 
1070  if(data->Positions.Start){
1071  // Set the last character to two before this
1072  // (skip the current and " and end there)
1073  int previouscheck = GetPreviousCharacter();
1074 
1075  // Check do we need to go back 2 characters or just one //
1076  if((quotes == QUOTETYPE_BOTH && (previouscheck == '"' ||
1077  previouscheck == '\'')) ||
1078  (quotes == QUOTETYPE_DOUBLEQUOTES && previouscheck == '"') ||
1079  (quotes == QUOTETYPE_SINGLEQUOTES && previouscheck == '\''))
1080  {
1081  ITR_FUNCDEBUG("Going back over an extra quote character");
1082  data->Positions.End = GetPosition()-2;
1083  } else {
1084  data->Positions.End = GetPosition()-1;
1085  }
1086 
1087  ITR_FUNCDEBUG("Ending to new line, end is now: "+
1089  }
1090 
1091  SkipLineEnd();
1093  }
1094 
1095  int currentcharacter = GetCharacter();
1096 
1097  switch(quotes){
1098  case QUOTETYPE_BOTH:
1099  {
1100  if(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING){
1101  // check if we are on the quotes, because we don't want those //
1102  if(currentcharacter == '"' || currentcharacter == '\''){
1103  // if we aren't ignoring special disallow //
1104  if(!(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)){
1105  TakeChar = false;
1106  ITR_FUNCDEBUG("Found quote character");
1107  }
1108  }
1109 
1110  } else {
1111  End = true;
1112  ITR_FUNCDEBUG("Outside quotes");
1113  }
1114  }
1115  break;
1117  {
1118  if(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING_SINGLE){
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  }
1133  break;
1135  {
1136  if(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING_DOUBLE){
1137  // check if we are on the quotes, because we don't want those //
1138  if(currentcharacter == '"'){
1139  // if we aren't ignoring special disallow //
1140  if(!(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)){
1141  TakeChar = false;
1142  ITR_FUNCDEBUG("Found quote character");
1143  }
1144  }
1145 
1146  } else {
1147  End = true;
1148  ITR_FUNCDEBUG("Outside quotes");
1149  }
1150  }
1151  break;
1152  }
1153 
1154  // If we have found a character this is on the ending quote //
1155  if(!TakeChar && data->Positions.Start){
1156 
1157  // Set the last character to the one before this (skip the " and end there) //
1158  data->Positions.End = GetPosition() - 1;
1159  ITR_FUNCDEBUG("On ending quote, end is now: "+
1161  }
1162 
1163  if(End){
1164  // if we have found at least a character we can end this here //
1165  if(data->Positions.Start){
1166  // Set the last character to two before this
1167  // (skip the current and " and end there)
1168  data->Positions.End = GetPosition() - 2;
1169  ITR_FUNCDEBUG("Ending outside quotes, end is now: "+
1170  Convert::ToString(data->Positions));
1172  }
1173  } else if(TakeChar){
1174  // check is this first quoted character //
1175  if(!data->Positions.Start){
1176  // first position! //
1177  data->Positions.Start = GetPosition();
1178  ITR_FUNCDEBUG("First character found: "+
1180 
1181  }
1182  }
1183 
1185  }
1186 
1188  IteratorPositionData* data, int stopflags, int specialflags)
1189  {
1190  bool IsValid = true;
1191 
1192  if(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP && IsAtNewLine()){
1193  ITR_FUNCDEBUG("Stopping to new line");
1194 
1195  if(data->Positions.Start){
1196  // ended //
1197  data->Positions.End = GetPosition() - 1;
1198  ITR_FUNCDEBUG("Ending to new line, end is now: "+
1200  }
1201 
1202  SkipLineEnd();
1204  }
1205 
1206  int currentcharacter = GetCharacter();
1207 
1208  // If set this is invalid inside comments //
1209  if((specialflags & SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING) &&
1210  (CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT))
1211  {
1212  IsValid = false;
1213  goto invalidcodelabelunnormalcharacter;
1214  }
1215 
1216  if((stopflags & UNNORMALCHARACTER_TYPE_LOWCODES ||
1218  && !(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING))
1219  {
1220  if(currentcharacter <= ' '){
1221  IsValid = false;
1222  goto invalidcodelabelunnormalcharacter;
1223  }
1224  }
1225 
1226  if(stopflags & UNNORMALCHARACTER_TYPE_NON_ASCII){
1227 
1228  if(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING || !(
1229  (currentcharacter >= '0' && currentcharacter <= '9') ||
1230  (currentcharacter >= 'A' && currentcharacter <= 'Z') ||
1231  (currentcharacter >= 'a' && currentcharacter <= 'z')))
1232  {
1233  IsValid = false;
1234  goto invalidcodelabelunnormalcharacter;
1235  }
1236  }
1237 
1239  !(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING)
1240  && !(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL))
1241  {
1242  if(((currentcharacter <= '/' && currentcharacter >= '!') ||
1243  (currentcharacter <= '@' && currentcharacter >= ':')
1244  || (currentcharacter <= '`' && currentcharacter >= '[') ||
1245  (currentcharacter <= '~' && currentcharacter >= '{'))
1246  && !(currentcharacter == '_' || currentcharacter == '-'))
1247  {
1248  IsValid = false;
1249  goto invalidcodelabelunnormalcharacter;
1250  }
1251  }
1252 
1253  if(IsValid){
1254  // check is this first character //
1255  if(!data->Positions.Start){
1256  // first position! //
1257  data->Positions.Start = GetPosition();
1258  ITR_FUNCDEBUG("Started: "+Convert::ToString(data->Positions.Start));
1259  }
1260 
1261  } else {
1262 
1263  invalidcodelabelunnormalcharacter:
1264 
1265 
1266  // check for end //
1267  if(data->Positions.Start){
1268  // ended //
1269  data->Positions.End = GetPosition() - 1;
1270  ITR_FUNCDEBUG("End now: "+Convert::ToString(data->Positions.End));
1272  }
1273  }
1274 
1276  }
1277 
1279  IteratorNumberFindData* data, DECIMALSEPARATORTYPE decimal, int specialflags)
1280  {
1281  // Check is the current element a part of a number //
1282 
1283  bool IsValid = false;
1284 
1285  if(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP && IsAtNewLine()){
1286  ITR_FUNCDEBUG("Stopping to new line");
1287 
1288  if(data->Positions.Start){
1289  // ended //
1290  data->Positions.End = GetPosition() - 1;
1291  ITR_FUNCDEBUG("Ending to new line, end is now: "+
1293  }
1294 
1295  SkipLineEnd();
1297  }
1298 
1299  // Comments might be skipped //
1300  if(!(specialflags & SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING) ||
1301  !(CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT))
1302  {
1303 
1304  int currentcharacter = GetCharacter();
1305 
1306  if((currentcharacter >= 48) && (currentcharacter <= 57)){
1307  // Is a plain old digit //
1308  IsValid = true;
1309 
1310  } else {
1311  // Check is it a decimal separator (1 allowed)
1312  // or a negativity sign in front
1313  if(currentcharacter == '+' || currentcharacter == '-'){
1314 
1315  if((data->DigitsFound < 1) && (!data->NegativeFound)){
1316  IsValid = true;
1317  }
1318  data->NegativeFound = true;
1319  } else if (((currentcharacter == '.') &&
1320  ((decimal == DECIMALSEPARATORTYPE_DOT) ||
1321  (decimal == DECIMALSEPARATORTYPE_BOTH))) ||
1322  ((currentcharacter == ',') && ((decimal == DECIMALSEPARATORTYPE_COMMA) ||
1323  (decimal == DECIMALSEPARATORTYPE_BOTH))))
1324  {
1325  if((!data->DecimalFound) && (data->DigitsFound > 0)){
1326  IsValid = true;
1327  data->DecimalFound = true;
1328  }
1329  }
1330  }
1331  } else {
1332  ITR_FUNCDEBUG("Ignoring inside a comment");
1333  }
1334 
1335  if(IsValid){
1336  // check is this first digit //
1337  data->DigitsFound++;
1338  if(!data->Positions.Start){
1339  // first position! //
1340 
1341  data->Positions.Start = GetPosition();
1342  ITR_FUNCDEBUG("Data started: "+Convert::ToString(data->Positions.Start));
1343  }
1344 
1345  } else {
1346  // check for end //
1347  if(data->Positions.Start){
1348  // ended //
1349  data->Positions.End = GetPosition() - 1;
1350  ITR_FUNCDEBUG("End now: "+Convert::ToString(data->Positions.End));
1352  }
1353 
1354  }
1356  }
1357 
1359  IteratorAssignmentData* data, EQUALITYCHARACTER equality, int specialflags)
1360  {
1361  // check is current element a valid element //
1362  bool IsValid = true;
1363  bool IsStop = false;
1364 
1365  if(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP && IsAtNewLine()){
1366  ITR_FUNCDEBUG("Stopping to new line");
1367 
1368  SkipLineEnd();
1370  }
1371 
1372  // Comments cannot be part of this //
1373  if((specialflags & SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING) &&
1374  (CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT))
1375  {
1376  // Not valid inside a comment //
1377  ITR_FUNCDEBUG("Comment skipped");
1378  IsValid = false;
1379 
1380  } else {
1381 
1382  int charvalue = GetCharacter();
1383 
1384  // Skip if this is a space //
1385  if(charvalue < 33){
1386  // Not allowed in a name //
1387  ITR_FUNCDEBUG("Whitespace skipped");
1388  IsValid = false;
1389  }
1390 
1391  if(equality == EQUALITYCHARACTER_TYPE_ALL){
1392  // check for all possible value separators //
1393  if(charvalue == '=' || charvalue == ':'){
1394 
1395  if(!(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)){
1396  // If ignored don't stop //
1397  ITR_FUNCDEBUG("Found = or :");
1398  IsStop = true;
1399  }
1400  }
1401  } else if(equality == EQUALITYCHARACTER_TYPE_EQUALITY){
1402  // Check for an equality sign //
1403  if(charvalue == '='){
1404  if(!(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)){
1405  ITR_FUNCDEBUG("Found =");
1406  IsStop = true;
1407  }
1408  }
1409  } else if (equality == EQUALITYCHARACTER_TYPE_DOUBLEDOTSTYLE){
1410  // Check does it match the characters //
1411  if(charvalue == ':'){
1412  if(!(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)){
1413  ITR_FUNCDEBUG("Found :");
1414  IsStop = true;
1415  }
1416  }
1417  }
1418  }
1419 
1420  if(!IsStop){
1421  // end if end already found //
1422  if(data->SeparatorFound){
1423  ITR_FUNCDEBUG("Found stop");
1425  }
1426  } else {
1427  data->SeparatorFound = true;
1428  IsValid = false;
1429  }
1430 
1431  if(IsValid){
1432  // Check is this the first character //
1433  if(!data->Positions.Start){
1434  // first position! //
1435  data->Positions.Start = GetPosition();
1436  ITR_FUNCDEBUG("Data started: "+Convert::ToString(data->Positions.Start));
1437 
1438  } else {
1439  // Set end to this valid character //
1440  data->Positions.End = GetPosition();
1441  ITR_FUNCDEBUG("End now: "+Convert::ToString(data->Positions.End));
1442  }
1443  }
1444 
1445 
1447  }
1448 
1450  IteratorCharacterData &data, const int additionalskip, const int specialflags)
1451  {
1452  if(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP && IsAtNewLine()){
1453  ITR_FUNCDEBUG("Stopping to new line");
1454 
1455  SkipLineEnd();
1457  }
1458 
1459  // We can probably always skip inside a comment //
1460  if((specialflags & SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING) &&
1461  (CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT))
1462  {
1463 
1465  }
1466 
1467  // We can just return if we are inside a string //
1468  if(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING){
1470  }
1471 
1472  // Check does the character match what is being skipped //
1473  int curchara = GetCharacter();
1474 
1475  if(additionalskip & UNNORMALCHARACTER_TYPE_LOWCODES){
1476  if(curchara <= 32)
1478  }
1479 
1480  if(curchara == data.CharacterToUse){
1481  // We want to skip it //
1483  }
1484 
1485  // didn't match to be skipped characters //
1487  }
1488 
1490  IteratorFindUntilData* data, int character, int specialflags)
1491  {
1492  // Can this character be added //
1493  bool ValidChar = true;
1494 
1495  if(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP && IsAtNewLine()){
1496  ITR_FUNCDEBUG("Stopping to new line");
1497 
1498  if(data->Positions.Start){
1499  // This should be fine to get here //
1500  data->Positions.End = GetPosition() - 1;
1501  ITR_FUNCDEBUG("Ending to new line, end is now: "+
1503  }
1504 
1505  // Make sure to not return until end of the whole string //
1506  data->NewLineBreak = true;
1507 
1508  SkipLineEnd();
1510  }
1511 
1512  int tmpchara = GetCharacter();
1513 
1514  // We can just continue if we are inside a string //
1515  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING) &&
1516  !((specialflags & SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING)
1517  && (CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT)))
1518  {
1519  // Check did we encounter stop character //
1520  #ifdef ALLOW_DEBUG
1521  if (DebugMode) {
1522 
1523  std::string value = "Trying to match: ";
1524  utf8::append(tmpchara, std::back_inserter(value));
1525  value += "==" + Convert::ToString(tmpchara);
1526 
1527  Logger::Get()->Write("Iterator: procfunc: " + value); \
1528  }
1529  #endif // ALLOW_DEBUG
1530 
1531  if(tmpchara == character){
1532  // Skip if ignoring special characters //
1533  if(!(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL)){
1534  // Not valid character //
1535  ValidChar = false;
1536  ITR_FUNCDEBUG("Found match");
1537  // We must have started to encounter the stop character //
1538  if(data->Positions.Start){
1539  // We encountered the stop character //
1540  data->FoundEnd = true;
1541  ITR_FUNCDEBUG("Encountered end");
1542  }
1543  }
1544  }
1545  } else {
1546  #ifdef ALLOW_DEBUG
1547  if((CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING)){
1548  ITR_FUNCDEBUG("Ignoring inside string");
1549  }
1550  if((specialflags & SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING) &&
1551  (CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT))
1552  {
1553  ITR_FUNCDEBUG("Ignoring inside comment");
1554  }
1555  #endif // _DEBUG
1556  }
1557 
1558  if(ValidChar){
1559  // valid character set start if not already set //
1560  if(!data->Positions.Start){
1561  data->Positions.Start = GetPosition();
1562  data->Positions.End = data->Positions.Start;
1563  ITR_FUNCDEBUG("Data started: "+Convert::ToString(data->Positions.Start));
1564  }
1566  }
1567  // let's stop if we have found something //
1568  if(data->Positions.Start){
1569  // This should be fine to get here //
1570  data->Positions.End = GetPosition() - 1;
1571  ITR_FUNCDEBUG("Ending here: "+Convert::ToString(data->Positions.End));
1573  }
1574 
1575  // haven't found anything, we'll need to find something //
1577  }
1578 
1580  IteratorFindUntilData* data)
1581  {
1582  // Continue if the current character is a new line character //
1583 
1584  // All line separator characters should be here //
1585  if(IsAtNewLine()){
1586 
1587  if(!data->FoundEnd){
1588  // Ignore the first new line //
1589  data->FoundEnd = true;
1590  ITR_FUNCDEBUG("Ignoring first newline character");
1591  goto positionisvalidlabelstringiteratorfindnewline;
1592  }
1593 
1594  // This is a new line character //
1595  ITR_FUNCDEBUG("Found newline character");
1596 
1597  // End before this character //
1598  data->Positions.End = GetPosition() - 1;
1599  ITR_FUNCDEBUG("Ending here: "+Convert::ToString(data->Positions));
1600 
1601  SkipLineEnd();
1603  }
1604 
1605  positionisvalidlabelstringiteratorfindnewline:
1606 
1607  // Set position //
1608  if(!data->Positions.Start){
1609 
1610  // End before this character //
1611  data->Positions.Start = GetPosition();
1612  data->FoundEnd = true;
1613  ITR_FUNCDEBUG("Data started: "+Convert::ToString(data->Positions));
1614  }
1615 
1617  }
1618 
1620  IteratorNestingLevelData* data, int left, int right, int specialflags)
1621  {
1622  // Ignore if ignoring special characters //
1623  if(!(CurrentFlags & ITERATORFLAG_SET_IGNORE_SPECIAL) &&
1624  !(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING))
1625  {
1626  if(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP && IsAtNewLine()){
1627 
1628  // Invalid, always //
1630  }
1631 
1632  int currentcharacter = GetCharacter();
1633 
1634  // Nesting level starts //
1635  if(currentcharacter == left){
1636 
1637  ++data->NestingLevel;
1638 
1639  if(data->NestingLevel > 1){
1640 
1641  // There where multiple lefts in a row, like "[[[...]]]"
1642  goto isinsidevalidleftrightpair;
1643  }
1644 
1646  }
1647 
1648  // One nesting level is ending //
1649  if(currentcharacter == right){
1650 
1651  --data->NestingLevel;
1652 
1653  if(data->NestingLevel == 0){
1654 
1655  data->Positions.End = GetPosition() - 1;
1657  }
1658  }
1659  }
1660 
1661  isinsidevalidleftrightpair:
1662 
1663  if(!data->Positions.Start && data->NestingLevel > 0){
1664 
1665  data->Positions.Start = GetPosition();
1666  }
1667 
1669  }
1670 
1671 
1672 
1673  template<class AcceptStr>
1675  IteratorUntilSequenceData<AcceptStr>* data, int specialflags)
1676  {
1677  // First check if this is a line end //
1678  int curcharacter = GetCharacter();
1679 
1680  if(specialflags & SPECIAL_ITERATOR_ONNEWLINE_STOP && IsAtNewLine()){
1681 
1682  // Set the end to one before this, if found any //
1683  if(data->Positions.Start){
1684 
1685  data->Positions.End = GetPosition() - 1;
1686  }
1687 
1688  SkipLineEnd();
1690  }
1691 
1692  // We may not be inside strings nor comments for checking //
1693  if(!(CurrentFlags & ITERATORFLAG_SET_INSIDE_STRING) &&
1694  (!(CurrentFlags & ITERATORFLAG_SET_INSIDE_COMMENT) ||
1695  !(specialflags & SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING)))
1696  {
1697  // Check do we match the current position //
1698  if(curcharacter == data->StringToMatch[data->CurMatchedIndex]){
1699 
1700  // Found a matching character //
1701 
1702  // Move to next match position and don't yet verify if this is a valid
1703  // character
1704  ++data->CurMatchedIndex;
1705 
1706  if(data->CurMatchedIndex >= data->StringToMatch.size()){
1707 
1708  // End found //
1710  }
1711 
1713 
1714  }
1715 
1716  }
1717 
1718  // Go back to beginning of matching //
1719  data->CurMatchedIndex = 0;
1720 
1721  // All is fine //
1722  if(!data->Positions.Start){
1723 
1724  data->Positions.Start = GetPosition();
1725  data->Positions.End = data->Positions.Start;
1726  } else {
1727 
1728  // This might be poisonous to performance, but this gets the job done //
1729  data->Positions.End = GetPosition();
1730  }
1731 
1733  }
1734 
1735 
1736  };
1737 
1738 }
1739 #undef ALLOW_DEBUG
1740 
1741 #ifdef LEAK_INTO_GLOBAL
1743 #endif
1744 
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)
Set when inside a /* comment.
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&#39;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:118
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, &#39;like this&#39;.
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