| [35] | 1 | Unit StringUtilsUnit;
 | 
|---|
 | 2 | 
 | 
|---|
 | 3 | // NewView - a new OS/2 Help Viewer
 | 
|---|
| [75] | 4 | // Copyright 2006-2007 Ronald Brill (rbri at rbri dot de)
 | 
|---|
 | 5 | // This software is released under the GNU Public License - see readme.txt
 | 
|---|
| [35] | 6 | 
 | 
|---|
| [110] | 7 | // Helper functions to work with String and AnsiString
 | 
|---|
| [35] | 8 | 
 | 
|---|
 | 9 | Interface
 | 
|---|
 | 10 | 
 | 
|---|
 | 11 | uses
 | 
|---|
| [110] | 12 |   Classes,
 | 
|---|
 | 13 |   CharUtilsUnit;
 | 
|---|
| [35] | 14 | 
 | 
|---|
| [43] | 15 | const
 | 
|---|
| [110] | 16 |   StrTAB = CharTAB;
 | 
|---|
 | 17 |   StrCR = CharCR;
 | 
|---|
 | 18 |   StrLF = CharLF;
 | 
|---|
| [43] | 19 |   StrCRLF = StrCR + StrLF;
 | 
|---|
| [139] | 20 |   StrSingleQuote = CharSingleQuote;
 | 
|---|
 | 21 |   StrDoubleQuote = CharDoubleQuote;
 | 
|---|
| [43] | 22 | 
 | 
|---|
 | 23 | 
 | 
|---|
 | 24 |   TYPE
 | 
|---|
| [35] | 25 |      TSerializableStringList = class
 | 
|---|
 | 26 |      private
 | 
|---|
 | 27 |        stringList : TStringList;
 | 
|---|
 | 28 | 
 | 
|---|
 | 29 |      public
 | 
|---|
 | 30 |        CONSTRUCTOR Create;
 | 
|---|
 | 31 |        DESTRUCTOR Destroy; override;
 | 
|---|
 | 32 |        FUNCTION getCount : LongInt;
 | 
|---|
 | 33 |        PROCEDURE add(const aString : String);
 | 
|---|
 | 34 |        FUNCTION get(const anIndex : LongInt) : String;
 | 
|---|
 | 35 |        FUNCTION getSerializedString : String;
 | 
|---|
 | 36 |        PROCEDURE readValuesFromSerializedString(const aSerializedString : String);
 | 
|---|
 | 37 |   end;
 | 
|---|
 | 38 | 
 | 
|---|
| [139] | 39 |   // prefixes all occurences of one of the chars in aStringWithChars with anEscape char
 | 
|---|
| [35] | 40 |   // if the escapeChar itself is found, then it is doubled
 | 
|---|
| [118] | 41 |   Function StrEscapeAllCharsBy(const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char): String;
 | 
|---|
| [35] | 42 | 
 | 
|---|
| [43] | 43 |   // Extract all fields in a String given a set of delimiter characters and
 | 
|---|
 | 44 |   // an optional escape character usable to escape field delimits.
 | 
|---|
 | 45 |   // Example:
 | 
|---|
| [102] | 46 |   //     StrExtractStrings('1x2x3\x4', 'x', '\') ->
 | 
|---|
 | 47 |   //     returns 4 strings: '1', '', '2' and '3x4'
 | 
|---|
| [123] | 48 |   Procedure StrExtractStrings(var aResult : TStrings; const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char);
 | 
|---|
| [43] | 49 | 
 | 
|---|
| [82] | 50 |   // same as StrExtractStrings but ignores empty strings
 | 
|---|
| [123] | 51 |   Procedure StrExtractStringsIgnoreEmpty(var aResult : TStrings; const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char);
 | 
|---|
| [82] | 52 | 
 | 
|---|
| [43] | 53 |   // removes all occurences of char from aSetOfChars from the beginning
 | 
|---|
| [82] | 54 |   // of a String.
 | 
|---|
 | 55 |   Function StrTrimLeftChars(const aReceiver: String; const aSetOfChars: TSetOfChars): String;
 | 
|---|
 | 56 | 
 | 
|---|
 | 57 |   // removes all occurences of char from aSetOfChars from the end
 | 
|---|
 | 58 |   // of a String.
 | 
|---|
 | 59 |   Function StrTrimRightChars(const aReceiver: String; const aSetOfChars: TSetOfChars): String;
 | 
|---|
 | 60 | 
 | 
|---|
 | 61 |   // removes all occurences of char from aSetOfChars from the beginning
 | 
|---|
| [43] | 62 |   // end the end of a String.
 | 
|---|
 | 63 |   Function StrTrimChars(const aReceiver: String; const aSetOfChars: TSetOfChars): String;
 | 
|---|
 | 64 | 
 | 
|---|
 | 65 |   // removes all blanks from beginning and end
 | 
|---|
 | 66 |   Function StrTrim(const aReceiver: String): String;
 | 
|---|
 | 67 | 
 | 
|---|
| [82] | 68 |   // Returns the aCount leftmost chars of aString
 | 
|---|
 | 69 |   Function StrLeft(const aString : String; const aCount : Integer) : String;
 | 
|---|
 | 70 | 
 | 
|---|
| [102] | 71 |   // Returns a copy of the string without aCount chars from right
 | 
|---|
 | 72 |   Function StrLeftWithout(const aString : String; const aCount : Integer) : String;
 | 
|---|
 | 73 | 
 | 
|---|
 | 74 |   // Returns a copy of the string including all characters until one from aSetOfChars found
 | 
|---|
 | 75 |   Function StrLeftUntil(const aReceiver: String; const aSetOfChars: TSetOfChars) : String;
 | 
|---|
 | 76 | 
 | 
|---|
| [118] | 77 |   // Returns a copy of the string starting at aPos
 | 
|---|
 | 78 |   Function StrSubstringFrom(const aReceiver: String; const aPos : Integer) : String;
 | 
|---|
 | 79 | 
 | 
|---|
| [105] | 80 |   // returns true if the String starts with the provided one
 | 
|---|
| [102] | 81 |   // this is case SENSITIVE
 | 
|---|
 | 82 |   Function StrStartsWith(const aReceiver: String; const aStartString: String): Boolean;
 | 
|---|
 | 83 | 
 | 
|---|
| [105] | 84 |   // returns true if the String starts with the provided one
 | 
|---|
| [102] | 85 |   // this is case INsensitive
 | 
|---|
 | 86 |   Function StrStartsWithIgnoringCase(const aReceiver: String; const aStartString: String): Boolean;
 | 
|---|
 | 87 | 
 | 
|---|
| [43] | 88 |   // returns true if the String ends with the provides one
 | 
|---|
 | 89 |   // this is case SENSITIVE
 | 
|---|
 | 90 |   Function StrEndsWith(const aReceiver: String; const anEndString: String): Boolean;
 | 
|---|
 | 91 | 
 | 
|---|
| [105] | 92 |   // returns true if the String ends with the provided one
 | 
|---|
| [43] | 93 |   // this is case INsensitive
 | 
|---|
| [102] | 94 |   Function StrEndsWithIgnoringCase(const aReceiver: String; const anEndString: String): Boolean;
 | 
|---|
| [43] | 95 | 
 | 
|---|
| [139] | 96 |   // Returns true if aReceiver is only spaces (or empty)
 | 
|---|
 | 97 |   Function StrIsEmptyOrSpaces(const aReceiver: String) : Boolean;
 | 
|---|
 | 98 | 
 | 
|---|
| [105] | 99 |   // returns true if the Strings are the same
 | 
|---|
 | 100 |   // this is case INsensitive
 | 
|---|
 | 101 |   Function StrEqualIgnoringCase(const aReceiver: String; const aSecondString: String): Boolean;
 | 
|---|
 | 102 | 
 | 
|---|
| [68] | 103 |   // the IntToStr generates wrong results
 | 
|---|
 | 104 |   // in normal cases IntToStr returns a negative value
 | 
|---|
 | 105 |   // and somtimes completly wrong values
 | 
|---|
 | 106 |   Function LongWordToStr(const aLongWord: LongWord) : String;
 | 
|---|
 | 107 | 
 | 
|---|
| [65] | 108 |   Function BoolToStr(const aBoolean : boolean ): string;
 | 
|---|
| [43] | 109 | 
 | 
|---|
| [139] | 110 |   // Returns aString enclosed in single quotes
 | 
|---|
 | 111 |   Function StrInSingleQuotes(const aString : String) : String;
 | 
|---|
 | 112 | 
 | 
|---|
| [102] | 113 |   // Returns aString enclosed in double quotes
 | 
|---|
 | 114 |   Function StrInDoubleQuotes(const aString : String) : String;
 | 
|---|
| [65] | 115 | 
 | 
|---|
| [106] | 116 |   // Extract all fields in a String delimited by whitespace (blank or tab).
 | 
|---|
 | 117 |   // use double quotes if you need blanks in the strings
 | 
|---|
 | 118 |   Procedure StrExtractStringsQuoted(Var aResult: TStrings; const aReceiver: String );
 | 
|---|
| [102] | 119 | 
 | 
|---|
| [110] | 120 | 
 | 
|---|
 | 121 |   // returns the position of aPart in aString
 | 
|---|
 | 122 |   // case insensitive
 | 
|---|
 | 123 |   Function CaseInsensitivePos(const aPart: String; const aString: String ): longint;
 | 
|---|
 | 124 | 
 | 
|---|
| [139] | 125 |   // Finds the last position of aChar within aString. Returns zero if no match
 | 
|---|
 | 126 |   Function LastPosOfChar(const aChar: char; const aString: String): longint;
 | 
|---|
| [118] | 127 | 
 | 
|---|
| [139] | 128 | 
 | 
|---|
| [110] | 129 |   // --------------------
 | 
|---|
 | 130 |   // ---- AnsiString ----
 | 
|---|
 | 131 |   // --------------------
 | 
|---|
 | 132 | 
 | 
|---|
| [139] | 133 | 
 | 
|---|
| [110] | 134 |   // removes all occurences of char from aSetOfChars from the beginning
 | 
|---|
 | 135 |   // of a String.
 | 
|---|
 | 136 |   Function AnsiStrTrimLeftChars(const aReceiver: AnsiString; const aSetOfChars: TSetOfChars): AnsiString;
 | 
|---|
 | 137 | 
 | 
|---|
 | 138 |   // removes all occurences of char from aSetOfChars from the end
 | 
|---|
 | 139 |   // of a String.
 | 
|---|
 | 140 |   Function AnsiStrTrimRightChars(const aReceiver: AnsiString; const aSetOfChars: TSetOfChars): AnsiString;
 | 
|---|
 | 141 | 
 | 
|---|
 | 142 |   // removes all occurences of char from aSetOfChars from the beginning
 | 
|---|
 | 143 |   // end the end of a String.
 | 
|---|
 | 144 |   Function AnsiStrTrimChars(const aReceiver: AnsiString; const aSetOfChars: TSetOfChars): AnsiString;
 | 
|---|
 | 145 | 
 | 
|---|
 | 146 |   // removes all blanks from beginning and end
 | 
|---|
 | 147 |   Function AnsiStrTrim(const aReceiver: AnsiString): AnsiString;
 | 
|---|
 | 148 | 
 | 
|---|
 | 149 | 
 | 
|---|
| [139] | 150 |   // --------------------
 | 
|---|
 | 151 |   // ---- Misc TODO  ----
 | 
|---|
 | 152 |   // --------------------
 | 
|---|
| [110] | 153 | 
 | 
|---|
| [139] | 154 |   Procedure GetMemString(const aPointer : pointer; var aString: string; const aSize: byte);
 | 
|---|
| [110] | 155 | 
 | 
|---|
| [139] | 156 |   Procedure FreePString(var aPString: PString );
 | 
|---|
 | 157 | 
 | 
|---|
 | 158 |   Function NewPString(const aString : String) : PString;
 | 
|---|
 | 159 | 
 | 
|---|
 | 160 | 
 | 
|---|
| [35] | 161 | Implementation
 | 
|---|
 | 162 | 
 | 
|---|
| [65] | 163 |   uses
 | 
|---|
| [105] | 164 |     SysUtils,
 | 
|---|
| [139] | 165 |     DebugUnit,
 | 
|---|
 | 166 |     ACLUtility;  // TODO
 | 
|---|
| [65] | 167 | 
 | 
|---|
| [35] | 168 |   constructor TSerializableStringList.Create;
 | 
|---|
 | 169 |   begin
 | 
|---|
| [65] | 170 |     LogEvent(LogObjConstDest, 'TSerializableStringList createdestroy');
 | 
|---|
 | 171 | 
 | 
|---|
| [35] | 172 |     inherited Create;
 | 
|---|
 | 173 |     stringList := TStringList.Create;
 | 
|---|
 | 174 |   end;
 | 
|---|
 | 175 | 
 | 
|---|
 | 176 | 
 | 
|---|
 | 177 |   destructor TSerializableStringList.Destroy;
 | 
|---|
 | 178 |   begin
 | 
|---|
| [65] | 179 |     LogEvent(LogObjConstDest, 'TSerializableStringList destroy');
 | 
|---|
 | 180 |     if Nil <> stringList then stringList.Destroy;
 | 
|---|
 | 181 | 
 | 
|---|
| [35] | 182 |     inherited Destroy;
 | 
|---|
 | 183 |   end;
 | 
|---|
 | 184 | 
 | 
|---|
 | 185 | 
 | 
|---|
 | 186 |   FUNCTION TSerializableStringList.getCount : LongInt;
 | 
|---|
 | 187 |   begin
 | 
|---|
 | 188 |     result := stringList.count;
 | 
|---|
 | 189 |   end;
 | 
|---|
 | 190 | 
 | 
|---|
 | 191 | 
 | 
|---|
 | 192 |   PROCEDURE TSerializableStringList.add(const aString : String);
 | 
|---|
 | 193 |   begin
 | 
|---|
 | 194 |     stringList.add(aString);
 | 
|---|
 | 195 |   end;
 | 
|---|
 | 196 | 
 | 
|---|
 | 197 |   FUNCTION TSerializableStringList.get(const anIndex : LongInt) : String;
 | 
|---|
 | 198 |   begin
 | 
|---|
 | 199 |     result := stringList[anIndex];
 | 
|---|
 | 200 |   end;
 | 
|---|
 | 201 | 
 | 
|---|
 | 202 |   FUNCTION TSerializableStringList.getSerializedString : String;
 | 
|---|
 | 203 |   Var
 | 
|---|
 | 204 |     i : Integer;
 | 
|---|
 | 205 |   begin
 | 
|---|
 | 206 |     result := '';
 | 
|---|
| [82] | 207 |     for i := 0 to stringList.count-1 do
 | 
|---|
| [35] | 208 |     begin
 | 
|---|
 | 209 |       if (i > 0) then result := result + '&';
 | 
|---|
| [43] | 210 |       result := result + StrEscapeAllCharsBy(stringList[i], ['&'], '\');
 | 
|---|
| [35] | 211 |     end;
 | 
|---|
 | 212 |   end;
 | 
|---|
 | 213 | 
 | 
|---|
 | 214 | 
 | 
|---|
 | 215 |   PROCEDURE TSerializableStringList.readValuesFromSerializedString(const aSerializedString : String);
 | 
|---|
| [43] | 216 |   Begin
 | 
|---|
 | 217 |     if (length(aSerializedString) < 1) then exit;
 | 
|---|
 | 218 | 
 | 
|---|
| [65] | 219 |     LogEvent(LogObjConstDest, 'readValuesFromSerializedString');
 | 
|---|
 | 220 |     stringList.Destroy;
 | 
|---|
 | 221 |     LogEvent(LogObjConstDest, 'readValuesFromSerializedString destroy done');
 | 
|---|
| [43] | 222 |     stringList := TStringList.Create;
 | 
|---|
 | 223 |     StrExtractStrings(stringList, aSerializedString, ['&'], '\');
 | 
|---|
 | 224 |   end;
 | 
|---|
 | 225 | 
 | 
|---|
 | 226 | 
 | 
|---|
 | 227 |   // ----------------------------------------------------------
 | 
|---|
 | 228 | 
 | 
|---|
 | 229 | 
 | 
|---|
 | 230 |   Function StrEscapeAllCharsBy(Const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char): String;
 | 
|---|
| [35] | 231 |   Var
 | 
|---|
 | 232 |     i : Integer;
 | 
|---|
| [43] | 233 |     tmpChar : Char;
 | 
|---|
 | 234 |   Begin
 | 
|---|
 | 235 |     Result := '';
 | 
|---|
 | 236 | 
 | 
|---|
 | 237 |     for i := 1 To length(aReceiver) do
 | 
|---|
 | 238 |     begin
 | 
|---|
 | 239 |       tmpChar := aReceiver[i];
 | 
|---|
 | 240 | 
 | 
|---|
 | 241 |       if (tmpChar = anEscapeChar) or (tmpChar IN aSetOfChars) then
 | 
|---|
 | 242 |         result := result + anEscapeChar + tmpChar
 | 
|---|
 | 243 |       else
 | 
|---|
 | 244 |         result := result + tmpChar;
 | 
|---|
 | 245 |     end;
 | 
|---|
 | 246 |   end;
 | 
|---|
 | 247 | 
 | 
|---|
 | 248 | 
 | 
|---|
| [82] | 249 |   Procedure PrivateStrExtractStrings(   Var aResult: TStrings;
 | 
|---|
 | 250 |                                         const aReceiver: String;
 | 
|---|
 | 251 |                                         const aSetOfChars: TSetOfChars;
 | 
|---|
 | 252 |                                         const anEscapeChar: char;
 | 
|---|
 | 253 |                                         const anIgnoreEmptyFlag : boolean);
 | 
|---|
| [43] | 254 |   Var
 | 
|---|
 | 255 |     i : Integer;
 | 
|---|
| [35] | 256 |     tmpChar,tmpNextChar : Char;
 | 
|---|
 | 257 |     tmpPart: String;
 | 
|---|
| [43] | 258 |   Begin
 | 
|---|
 | 259 |     if (length(aReceiver) < 1) then exit;
 | 
|---|
| [35] | 260 | 
 | 
|---|
 | 261 |     tmpPart := '';
 | 
|---|
 | 262 | 
 | 
|---|
 | 263 |     i := 1;
 | 
|---|
| [43] | 264 |     while i <= length(aReceiver) do
 | 
|---|
| [35] | 265 |     begin
 | 
|---|
| [43] | 266 |       tmpChar := aReceiver[i];
 | 
|---|
 | 267 |       if i < length(aReceiver) then
 | 
|---|
 | 268 |         tmpNextChar := aReceiver[i+1]
 | 
|---|
| [35] | 269 |       else
 | 
|---|
 | 270 |         tmpNextChar := #0;
 | 
|---|
 | 271 | 
 | 
|---|
| [43] | 272 |       if (tmpChar = anEscapeChar) and (tmpNextChar = anEscapeChar) then
 | 
|---|
| [35] | 273 |       begin
 | 
|---|
| [43] | 274 |         tmpPart := tmpPart + anEscapeChar;
 | 
|---|
| [35] | 275 |         i := i + 2;
 | 
|---|
 | 276 |       end
 | 
|---|
 | 277 |       else
 | 
|---|
| [43] | 278 |         if (tmpChar = anEscapeChar) and (tmpNextChar IN aSetOfChars) then
 | 
|---|
| [35] | 279 |         begin
 | 
|---|
| [43] | 280 |           tmpPart := tmpPart + tmpNextChar;
 | 
|---|
| [35] | 281 |           i := i + 2;
 | 
|---|
 | 282 |         end
 | 
|---|
 | 283 |         else
 | 
|---|
| [43] | 284 |           if (tmpChar IN aSetOfChars) then
 | 
|---|
| [35] | 285 |           begin
 | 
|---|
| [82] | 286 |             if (NOT anIgnoreEmptyFlag) OR ('' <> tmpPart) then
 | 
|---|
 | 287 |             begin
 | 
|---|
 | 288 |               aResult.add(tmpPart);
 | 
|---|
 | 289 |             end;
 | 
|---|
| [35] | 290 |             tmpPart := '';
 | 
|---|
 | 291 |             i := i + 1;
 | 
|---|
 | 292 |           end
 | 
|---|
 | 293 |           else
 | 
|---|
 | 294 |             begin
 | 
|---|
 | 295 |             tmpPart := tmpPart + tmpChar;
 | 
|---|
 | 296 |             i := i + 1;
 | 
|---|
 | 297 |           end;
 | 
|---|
 | 298 |     end;
 | 
|---|
| [82] | 299 | 
 | 
|---|
 | 300 |     if (NOT anIgnoreEmptyFlag) OR ('' <> tmpPart) then
 | 
|---|
 | 301 |     begin
 | 
|---|
 | 302 |       aResult.add(tmpPart);
 | 
|---|
 | 303 |     end;
 | 
|---|
| [35] | 304 |   end;
 | 
|---|
 | 305 | 
 | 
|---|
 | 306 | 
 | 
|---|
| [82] | 307 |   Procedure StrExtractStrings(Var aResult: TStrings; Const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char);
 | 
|---|
 | 308 |   Begin
 | 
|---|
 | 309 |     PrivateStrExtractStrings(aResult, aReceiver, aSetOfChars, anEscapeChar, false);
 | 
|---|
 | 310 |   end;
 | 
|---|
 | 311 | 
 | 
|---|
 | 312 | 
 | 
|---|
 | 313 |   Procedure StrExtractStringsIgnoreEmpty(Var aResult: TStrings; Const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char);
 | 
|---|
 | 314 |   Begin
 | 
|---|
 | 315 |     PrivateStrExtractStrings(aResult, aReceiver, aSetOfChars, anEscapeChar, true);
 | 
|---|
 | 316 |   end;
 | 
|---|
 | 317 | 
 | 
|---|
 | 318 | 
 | 
|---|
 | 319 |   Function StrTrimLeftChars(const aReceiver: String; const aSetOfChars: TSetOfChars): String;
 | 
|---|
 | 320 |   Var
 | 
|---|
| [110] | 321 |     tmpLength : integer;
 | 
|---|
 | 322 |     i : integer;
 | 
|---|
| [82] | 323 |   Begin
 | 
|---|
| [110] | 324 |     tmpLength := Length(aReceiver);
 | 
|---|
 | 325 | 
 | 
|---|
 | 326 |     if 1 > tmpLength then
 | 
|---|
 | 327 |     begin
 | 
|---|
 | 328 |       result := aReceiver;
 | 
|---|
 | 329 |       exit;
 | 
|---|
 | 330 |     end;
 | 
|---|
 | 331 | 
 | 
|---|
| [82] | 332 |     i := 1;
 | 
|---|
 | 333 |     // mem optimization
 | 
|---|
 | 334 |     if aReceiver[i] in aSetOfChars then
 | 
|---|
 | 335 |     begin
 | 
|---|
| [110] | 336 |       while i <= tmpLength do
 | 
|---|
| [82] | 337 |       begin
 | 
|---|
 | 338 |         if aReceiver[i] in aSetOfChars then
 | 
|---|
 | 339 |           inc(i)
 | 
|---|
 | 340 |         else
 | 
|---|
 | 341 |           break;
 | 
|---|
 | 342 |       end;
 | 
|---|
 | 343 |       result := Copy(aReceiver, i, Length(aReceiver)-i+1);
 | 
|---|
 | 344 |     end
 | 
|---|
 | 345 |     else
 | 
|---|
 | 346 |     begin
 | 
|---|
 | 347 |       result := aReceiver;
 | 
|---|
 | 348 |     end;
 | 
|---|
 | 349 |   end;
 | 
|---|
 | 350 | 
 | 
|---|
 | 351 | 
 | 
|---|
 | 352 |   Function StrTrimRightChars(const aReceiver: String; const aSetOfChars: TSetOfChars): String;
 | 
|---|
 | 353 |   Var
 | 
|---|
| [110] | 354 |     i : integer;
 | 
|---|
| [82] | 355 |   Begin
 | 
|---|
 | 356 |     i := Length(aReceiver);
 | 
|---|
 | 357 | 
 | 
|---|
| [110] | 358 |     if 1 > i then
 | 
|---|
 | 359 |     begin
 | 
|---|
 | 360 |       result := aReceiver;
 | 
|---|
 | 361 |       exit;
 | 
|---|
 | 362 |     end;
 | 
|---|
 | 363 | 
 | 
|---|
| [82] | 364 |     // mem optimization
 | 
|---|
 | 365 |     if aReceiver[i] in aSetOfChars then
 | 
|---|
 | 366 |     begin
 | 
|---|
 | 367 |       while i > 0 do
 | 
|---|
 | 368 |       begin
 | 
|---|
 | 369 |         if aReceiver[i] in aSetOfChars then
 | 
|---|
 | 370 |           dec(i)
 | 
|---|
 | 371 |         else
 | 
|---|
 | 372 |           break;
 | 
|---|
 | 373 |       end;
 | 
|---|
 | 374 |       result := Copy(aReceiver, 1, i);
 | 
|---|
 | 375 |     end
 | 
|---|
 | 376 |     else
 | 
|---|
 | 377 |     begin
 | 
|---|
 | 378 |       result := aReceiver;
 | 
|---|
 | 379 |     end;
 | 
|---|
 | 380 |   end;
 | 
|---|
 | 381 | 
 | 
|---|
 | 382 | 
 | 
|---|
| [43] | 383 |   Function StrTrimChars(const aReceiver: String; const aSetOfChars: TSetOfChars): String;
 | 
|---|
| [35] | 384 |   Var
 | 
|---|
| [110] | 385 |     i,j : integer;
 | 
|---|
| [82] | 386 |     tmpNeedCopy : boolean;
 | 
|---|
| [35] | 387 |   Begin
 | 
|---|
| [110] | 388 |     j := Length(aReceiver);
 | 
|---|
 | 389 | 
 | 
|---|
 | 390 |     if 1 > j then
 | 
|---|
 | 391 |     begin
 | 
|---|
 | 392 |       result := aReceiver;
 | 
|---|
 | 393 |       exit;
 | 
|---|
 | 394 |     end;
 | 
|---|
 | 395 | 
 | 
|---|
| [82] | 396 |     tmpNeedCopy := false;
 | 
|---|
| [43] | 397 |     i := 1;
 | 
|---|
| [110] | 398 |     while i < j do
 | 
|---|
| [43] | 399 |     begin
 | 
|---|
 | 400 |       if aReceiver[i] in aSetOfChars then
 | 
|---|
| [82] | 401 |       begin
 | 
|---|
 | 402 |         inc(i);
 | 
|---|
 | 403 |         tmpNeedCopy := true;
 | 
|---|
 | 404 |       end
 | 
|---|
 | 405 |       else
 | 
|---|
 | 406 |       begin
 | 
|---|
 | 407 |         break;
 | 
|---|
 | 408 |       end;
 | 
|---|
| [43] | 409 |     end;
 | 
|---|
| [35] | 410 | 
 | 
|---|
| [43] | 411 |     while j >= i do
 | 
|---|
| [35] | 412 |     begin
 | 
|---|
| [43] | 413 |       if aReceiver[j] in aSetOfChars then
 | 
|---|
| [82] | 414 |       begin
 | 
|---|
 | 415 |         dec(j);
 | 
|---|
 | 416 |         tmpNeedCopy := true;
 | 
|---|
 | 417 |       end
 | 
|---|
| [43] | 418 |       else
 | 
|---|
| [82] | 419 |       begin
 | 
|---|
| [43] | 420 |         break;
 | 
|---|
| [82] | 421 |       end;
 | 
|---|
| [43] | 422 |     end;
 | 
|---|
 | 423 | 
 | 
|---|
| [82] | 424 |     if tmpNeedCopy then
 | 
|---|
 | 425 |     begin
 | 
|---|
 | 426 |       result := Copy(aReceiver, i, j-i+1);
 | 
|---|
 | 427 |     end
 | 
|---|
 | 428 |     else
 | 
|---|
 | 429 |     begin
 | 
|---|
 | 430 |       result := aReceiver;
 | 
|---|
 | 431 |     end;
 | 
|---|
| [43] | 432 |   end;
 | 
|---|
 | 433 | 
 | 
|---|
 | 434 | 
 | 
|---|
 | 435 |   Function StrTrim(const aReceiver: String): String;
 | 
|---|
 | 436 |   Begin
 | 
|---|
 | 437 |     result := StrTrimChars(aReceiver, [' ']);
 | 
|---|
 | 438 |   end;
 | 
|---|
 | 439 | 
 | 
|---|
 | 440 | 
 | 
|---|
| [82] | 441 |   Function StrLeft(const aString : String; const aCount : Integer) : String;
 | 
|---|
 | 442 |   Begin
 | 
|---|
 | 443 |     if aCount >= Length(aString) then
 | 
|---|
 | 444 |       Result := aString
 | 
|---|
 | 445 |     else
 | 
|---|
 | 446 |       Result := copy(aString, 1, aCount);
 | 
|---|
 | 447 |   end;
 | 
|---|
 | 448 | 
 | 
|---|
 | 449 | 
 | 
|---|
| [102] | 450 |   Function StrLeftWithout(const aString : String; const aCount : Integer) : String;
 | 
|---|
 | 451 |   Begin
 | 
|---|
 | 452 |     Result:= copy(aString, 1, length(aString) - aCount );
 | 
|---|
 | 453 |   End;
 | 
|---|
 | 454 | 
 | 
|---|
 | 455 | 
 | 
|---|
 | 456 |   Function StrLeftUntil(const aReceiver: String; const aSetOfChars: TSetOfChars) : String;
 | 
|---|
 | 457 |   Var
 | 
|---|
 | 458 |     i : integer;
 | 
|---|
 | 459 |   Begin
 | 
|---|
 | 460 |     Result := aReceiver;
 | 
|---|
 | 461 | 
 | 
|---|
 | 462 |     for i := 1 To Length(aReceiver) do
 | 
|---|
 | 463 |     begin
 | 
|---|
 | 464 |       if aReceiver[i] in aSetOfChars then
 | 
|---|
 | 465 |       begin
 | 
|---|
 | 466 |         Result := Copy(aReceiver, 1, i-1 );
 | 
|---|
 | 467 |         break;
 | 
|---|
 | 468 |       end;
 | 
|---|
 | 469 |     end;
 | 
|---|
 | 470 |   end;
 | 
|---|
 | 471 | 
 | 
|---|
 | 472 | 
 | 
|---|
| [118] | 473 |   Function StrSubstringFrom(const aReceiver: String; const aPos : Integer) : String;
 | 
|---|
 | 474 |   Begin
 | 
|---|
 | 475 |     Result := copy(aReceiver, aPos, length(aReceiver) - aPos + 1);
 | 
|---|
 | 476 |   end;
 | 
|---|
 | 477 | 
 | 
|---|
 | 478 | 
 | 
|---|
| [102] | 479 |   Function StrStartsWith(const aReceiver: String; const aStartString: String) : Boolean;
 | 
|---|
 | 480 |   Var
 | 
|---|
 | 481 |     tmpStringPos : integer;
 | 
|---|
 | 482 |     tmpStartStringLength : integer;
 | 
|---|
 | 483 |   Begin
 | 
|---|
 | 484 |     tmpStartStringLength := Length(aStartString);
 | 
|---|
 | 485 | 
 | 
|---|
 | 486 |     if Length(aReceiver) < tmpStartStringLength then
 | 
|---|
 | 487 |     begin
 | 
|---|
 | 488 |       result := false;
 | 
|---|
 | 489 |       exit;
 | 
|---|
 | 490 |     end;
 | 
|---|
 | 491 | 
 | 
|---|
 | 492 |     for tmpStringPos := 1 to tmpStartStringLength do
 | 
|---|
 | 493 |     begin
 | 
|---|
 | 494 |       if aReceiver[tmpStringPos] <> aStartString[tmpStringPos] then
 | 
|---|
 | 495 |       begin
 | 
|---|
 | 496 |         result := false;
 | 
|---|
 | 497 |         exit;
 | 
|---|
 | 498 |       end;
 | 
|---|
 | 499 |     end;
 | 
|---|
 | 500 | 
 | 
|---|
 | 501 |     result := true;
 | 
|---|
 | 502 |   end;
 | 
|---|
 | 503 | 
 | 
|---|
 | 504 | 
 | 
|---|
 | 505 |   Function StrStartsWithIgnoringCase(const aReceiver: String; const aStartString: String) : Boolean;
 | 
|---|
 | 506 |   Var
 | 
|---|
 | 507 |     tmpStringPos : integer;
 | 
|---|
 | 508 |     tmpStartStringLength : integer;
 | 
|---|
 | 509 |   Begin
 | 
|---|
 | 510 |     tmpStartStringLength := Length(aStartString);
 | 
|---|
 | 511 | 
 | 
|---|
 | 512 |     if Length(aReceiver) < tmpStartStringLength then
 | 
|---|
 | 513 |     begin
 | 
|---|
 | 514 |       result := false;
 | 
|---|
 | 515 |       exit;
 | 
|---|
 | 516 |     end;
 | 
|---|
 | 517 | 
 | 
|---|
 | 518 |     for tmpStringPos := 1 to tmpStartStringLength do
 | 
|---|
 | 519 |     begin
 | 
|---|
 | 520 |       if UpCase(aReceiver[tmpStringPos]) <> UpCase(aStartString[tmpStringPos]) then
 | 
|---|
 | 521 |       begin
 | 
|---|
 | 522 |         result := false;
 | 
|---|
 | 523 |         exit;
 | 
|---|
 | 524 |       end;
 | 
|---|
 | 525 |     end;
 | 
|---|
 | 526 | 
 | 
|---|
 | 527 |     result := true;
 | 
|---|
 | 528 |   end;
 | 
|---|
 | 529 | 
 | 
|---|
 | 530 | 
 | 
|---|
| [43] | 531 |   Function StrEndsWith(const aReceiver: String; const anEndString: String): Boolean;
 | 
|---|
 | 532 |   Var
 | 
|---|
 | 533 |     tmpStringPos : Longint;
 | 
|---|
 | 534 |     tmpMatchPos : Longint;
 | 
|---|
 | 535 |   Begin
 | 
|---|
 | 536 |     tmpStringPos := length(aReceiver);
 | 
|---|
 | 537 |     tmpMatchPos := length(anEndString);
 | 
|---|
 | 538 | 
 | 
|---|
 | 539 |     if tmpMatchPos > tmpStringPos then
 | 
|---|
 | 540 |     begin
 | 
|---|
 | 541 |       result := false;
 | 
|---|
 | 542 |       exit;
 | 
|---|
 | 543 |     end;
 | 
|---|
 | 544 | 
 | 
|---|
 | 545 |     while tmpMatchPos > 0 do
 | 
|---|
 | 546 |     begin
 | 
|---|
 | 547 |       if aReceiver[tmpStringPos] <> anEndString[tmpMatchPos] then
 | 
|---|
| [35] | 548 |       begin
 | 
|---|
| [43] | 549 |         result := false;
 | 
|---|
 | 550 |         exit;
 | 
|---|
 | 551 |       end;
 | 
|---|
 | 552 |       dec(tmpMatchPos);
 | 
|---|
 | 553 |       dec(tmpStringPos);
 | 
|---|
 | 554 |     end;
 | 
|---|
| [35] | 555 | 
 | 
|---|
| [43] | 556 |     result := true;
 | 
|---|
 | 557 |   end;
 | 
|---|
 | 558 | 
 | 
|---|
 | 559 | 
 | 
|---|
 | 560 |   Function StrEndsWithIgnoringCase(const aReceiver: String; const anEndString: String): Boolean;
 | 
|---|
 | 561 |   Var
 | 
|---|
 | 562 |     tmpStringPos : Longint;
 | 
|---|
 | 563 |     tmpMatchPos : Longint;
 | 
|---|
 | 564 |   Begin
 | 
|---|
| [102] | 565 |     tmpStringPos := length(aReceiver);
 | 
|---|
| [43] | 566 |     tmpMatchPos := length(anEndString);
 | 
|---|
 | 567 | 
 | 
|---|
 | 568 |     if tmpMatchPos > tmpStringPos then
 | 
|---|
 | 569 |     begin
 | 
|---|
 | 570 |       result := false;
 | 
|---|
 | 571 |       exit;
 | 
|---|
 | 572 |     end;
 | 
|---|
 | 573 | 
 | 
|---|
 | 574 |     while tmpMatchPos > 0 do
 | 
|---|
 | 575 |     begin
 | 
|---|
| [102] | 576 |       if upcase(aReceiver[tmpStringPos]) <> upcase(anEndString[tmpMatchPos]) then
 | 
|---|
| [43] | 577 |       begin
 | 
|---|
 | 578 |         result := false;
 | 
|---|
 | 579 |         exit;
 | 
|---|
| [35] | 580 |       end;
 | 
|---|
| [43] | 581 |       dec(tmpMatchPos);
 | 
|---|
 | 582 |       dec(tmpStringPos);
 | 
|---|
| [35] | 583 |     end;
 | 
|---|
| [43] | 584 | 
 | 
|---|
 | 585 |     result := true;
 | 
|---|
| [35] | 586 |   end;
 | 
|---|
 | 587 | 
 | 
|---|
| [102] | 588 | 
 | 
|---|
| [139] | 589 |   Function StrIsEmptyOrSpaces(const aReceiver: String) : Boolean;
 | 
|---|
 | 590 |   Begin
 | 
|---|
 | 591 |     Asm
 | 
|---|
 | 592 |       MOV ESI, aReceiver   // get address of aReceiver into ESI
 | 
|---|
 | 593 |       MOV CL,[ESI]     // get length of s
 | 
|---|
 | 594 |       MOVZX ECX, CL      // widen CL
 | 
|---|
 | 595 |       INC ECX
 | 
|---|
 | 596 | 
 | 
|---|
 | 597 |     !IsSpacesLoop:
 | 
|---|
 | 598 |       INC ESI   // move to next char
 | 
|---|
 | 599 |       DEC ECX
 | 
|---|
 | 600 |       JE !IsSpacesTrue
 | 
|---|
 | 601 | 
 | 
|---|
 | 602 |       MOV AL,[ESI] // load character
 | 
|---|
 | 603 |       CMP AL,32  // is it a space?
 | 
|---|
 | 604 |       JE !IsSpacesLoop // yes, go to next
 | 
|---|
 | 605 | 
 | 
|---|
 | 606 |       // no, return false
 | 
|---|
 | 607 |       MOV EAX, 0
 | 
|---|
 | 608 |       JMP !IsSpacesDone
 | 
|---|
 | 609 | 
 | 
|---|
 | 610 |     !IsSpacesTrue:
 | 
|---|
 | 611 |       MOV EAX, 1
 | 
|---|
 | 612 | 
 | 
|---|
 | 613 |     !IsSpacesDone:
 | 
|---|
 | 614 |       LEAVE
 | 
|---|
 | 615 |       RETN32 4
 | 
|---|
 | 616 |     End;
 | 
|---|
 | 617 |   End;
 | 
|---|
 | 618 | 
 | 
|---|
 | 619 | 
 | 
|---|
| [105] | 620 |   Function StrEqualIgnoringCase(const aReceiver: String; const aSecondString: String): Boolean;
 | 
|---|
 | 621 |   begin
 | 
|---|
 | 622 |     Result := CompareText(aReceiver, aSecondString) = 0;
 | 
|---|
 | 623 |   end;
 | 
|---|
 | 624 | 
 | 
|---|
 | 625 | 
 | 
|---|
| [68] | 626 |   Function LongWordToStr(const aLongWord: LongWord) : String;
 | 
|---|
 | 627 |   Var
 | 
|---|
 | 628 |     l : LongWord;
 | 
|---|
 | 629 |     i : Integer;
 | 
|---|
 | 630 |   Begin
 | 
|---|
 | 631 |     Result := '';
 | 
|---|
 | 632 |     l := aLongWord;
 | 
|---|
 | 633 | 
 | 
|---|
 | 634 |     if l = 0 then
 | 
|---|
 | 635 |     begin
 | 
|---|
 | 636 |       result := '0';
 | 
|---|
 | 637 |       exit;
 | 
|---|
 | 638 |     end;
 | 
|---|
 | 639 | 
 | 
|---|
 | 640 |     while l > 0 do
 | 
|---|
 | 641 |     begin
 | 
|---|
 | 642 |       i := l mod 10;
 | 
|---|
 | 643 |       l := l div 10;
 | 
|---|
 | 644 |       Case i of
 | 
|---|
 | 645 |            0 : result := '0' + result;
 | 
|---|
 | 646 |            1 : result := '1' + result;
 | 
|---|
 | 647 |            2 : result := '2' + result;
 | 
|---|
 | 648 |            3 : result := '3' + result;
 | 
|---|
 | 649 |            4 : result := '4' + result;
 | 
|---|
 | 650 |            5 : result := '5' + result;
 | 
|---|
 | 651 |            6 : result := '6' + result;
 | 
|---|
 | 652 |            7 : result := '7' + result;
 | 
|---|
 | 653 |            8 : result := '8' + result;
 | 
|---|
 | 654 |            9 : result := '9' + result;
 | 
|---|
 | 655 |       end;
 | 
|---|
 | 656 |     end;
 | 
|---|
 | 657 | 
 | 
|---|
 | 658 |   end;
 | 
|---|
 | 659 | 
 | 
|---|
 | 660 | 
 | 
|---|
| [65] | 661 |   Function BoolToStr(const aBoolean : boolean ): string;
 | 
|---|
 | 662 |   begin
 | 
|---|
 | 663 |     if aBoolean then
 | 
|---|
 | 664 |       Result := 'True'
 | 
|---|
 | 665 |     else
 | 
|---|
 | 666 |       Result := 'False';
 | 
|---|
 | 667 |   end;
 | 
|---|
 | 668 | 
 | 
|---|
| [106] | 669 | 
 | 
|---|
| [139] | 670 |   Function StrInSingleQuotes(const aString : String) : String;
 | 
|---|
 | 671 |   begin
 | 
|---|
 | 672 |     Result := StrSingleQuote + aString + StrSingleQuote;
 | 
|---|
 | 673 |   end;
 | 
|---|
 | 674 | 
 | 
|---|
 | 675 | 
 | 
|---|
| [102] | 676 |   Function StrInDoubleQuotes(const aString : String) : String;
 | 
|---|
 | 677 |   begin
 | 
|---|
| [106] | 678 |     Result := StrDoubleQuote + aString + StrDoubleQuote;
 | 
|---|
| [102] | 679 |   end;
 | 
|---|
 | 680 | 
 | 
|---|
 | 681 | 
 | 
|---|
| [106] | 682 |   Procedure StrExtractStringsQuoted(Var aResult: TStrings; const aReceiver: String );
 | 
|---|
 | 683 |   Var
 | 
|---|
 | 684 |     tmpState : (WHITESPACE, INSIDE, START_QUOTE, INSIDE_QUOTED, INSIDE_QUOTED_START_QUOTE);
 | 
|---|
 | 685 |     tmpCurrentParsePosition : Integer;
 | 
|---|
 | 686 |     tmpCurrentChar : Char;
 | 
|---|
 | 687 |     tmpPart : String;
 | 
|---|
 | 688 | 
 | 
|---|
 | 689 |   Begin
 | 
|---|
 | 690 |     if (length(aReceiver) < 1) then exit;
 | 
|---|
 | 691 | 
 | 
|---|
 | 692 |     tmpState := WHITESPACE;
 | 
|---|
 | 693 |     tmpPart := '';
 | 
|---|
 | 694 | 
 | 
|---|
 | 695 |     tmpCurrentParsePosition := 1;
 | 
|---|
 | 696 | 
 | 
|---|
 | 697 |     for tmpCurrentParsePosition:=1 to length(aReceiver) do
 | 
|---|
 | 698 |     begin
 | 
|---|
 | 699 |       tmpCurrentChar := aReceiver[tmpCurrentParsePosition];
 | 
|---|
 | 700 | 
 | 
|---|
 | 701 |       Case tmpCurrentChar of
 | 
|---|
 | 702 |         ' ', StrTAB :
 | 
|---|
 | 703 |         begin
 | 
|---|
 | 704 | 
 | 
|---|
 | 705 |           Case tmpState of
 | 
|---|
 | 706 | 
 | 
|---|
 | 707 |             WHITESPACE :
 | 
|---|
 | 708 |             begin
 | 
|---|
 | 709 |               // nothing
 | 
|---|
 | 710 |             end;
 | 
|---|
 | 711 | 
 | 
|---|
 | 712 |             INSIDE :
 | 
|---|
 | 713 |             begin
 | 
|---|
 | 714 |               aResult.add(tmpPart);
 | 
|---|
 | 715 |               tmpPart := '';
 | 
|---|
 | 716 |               tmpState := WHITESPACE;
 | 
|---|
 | 717 |             end;
 | 
|---|
 | 718 | 
 | 
|---|
 | 719 |             INSIDE_QUOTED :
 | 
|---|
 | 720 |             begin
 | 
|---|
 | 721 |               tmpPart := tmpPart + tmpCurrentChar;
 | 
|---|
 | 722 |             end;
 | 
|---|
 | 723 | 
 | 
|---|
 | 724 |             START_QUOTE :
 | 
|---|
 | 725 |             begin
 | 
|---|
 | 726 |               tmpPart := tmpPart + tmpCurrentChar;
 | 
|---|
 | 727 |               tmpState := INSIDE_QUOTED;
 | 
|---|
 | 728 |             end;
 | 
|---|
 | 729 | 
 | 
|---|
 | 730 |             INSIDE_QUOTED_START_QUOTE :
 | 
|---|
 | 731 |             begin
 | 
|---|
 | 732 |               aResult.add(tmpPart);
 | 
|---|
 | 733 |               tmpPart := '';
 | 
|---|
 | 734 |               tmpState := WHITESPACE;
 | 
|---|
 | 735 |             end;
 | 
|---|
 | 736 |           end;
 | 
|---|
 | 737 |         end;
 | 
|---|
 | 738 | 
 | 
|---|
 | 739 |         StrDoubleQuote :
 | 
|---|
 | 740 |         begin
 | 
|---|
 | 741 | 
 | 
|---|
 | 742 |           Case tmpState of
 | 
|---|
 | 743 | 
 | 
|---|
 | 744 |             WHITESPACE :
 | 
|---|
 | 745 |             begin
 | 
|---|
 | 746 |               tmpState := START_QUOTE;
 | 
|---|
 | 747 |             end;
 | 
|---|
 | 748 | 
 | 
|---|
 | 749 |             INSIDE :
 | 
|---|
 | 750 |             begin
 | 
|---|
 | 751 |               aResult.add(tmpPart);
 | 
|---|
 | 752 |               tmpPart := '';
 | 
|---|
 | 753 |               tmpState := START_QUOTE;
 | 
|---|
 | 754 |             end;
 | 
|---|
 | 755 | 
 | 
|---|
 | 756 |             INSIDE_QUOTED :
 | 
|---|
 | 757 |             begin
 | 
|---|
 | 758 |               tmpState := INSIDE_QUOTED_START_QUOTE;
 | 
|---|
 | 759 |             end;
 | 
|---|
 | 760 | 
 | 
|---|
 | 761 |             START_QUOTE :
 | 
|---|
 | 762 |             begin
 | 
|---|
 | 763 |               tmpState := INSIDE_QUOTED_START_QUOTE;
 | 
|---|
 | 764 |             end;
 | 
|---|
 | 765 | 
 | 
|---|
 | 766 |             INSIDE_QUOTED_START_QUOTE :
 | 
|---|
 | 767 |             begin
 | 
|---|
 | 768 |               tmpPart := tmpPart + tmpCurrentChar;
 | 
|---|
 | 769 |               tmpState := INSIDE_QUOTED;
 | 
|---|
 | 770 |             end;
 | 
|---|
 | 771 |           end;
 | 
|---|
 | 772 |         end;
 | 
|---|
 | 773 | 
 | 
|---|
 | 774 |         else
 | 
|---|
 | 775 |         begin
 | 
|---|
 | 776 |           Case tmpState of
 | 
|---|
 | 777 | 
 | 
|---|
 | 778 |             WHITESPACE :
 | 
|---|
 | 779 |             begin
 | 
|---|
 | 780 |               tmpPart := tmpPart + tmpCurrentChar;
 | 
|---|
 | 781 |               tmpState := INSIDE;
 | 
|---|
 | 782 |             end;
 | 
|---|
 | 783 | 
 | 
|---|
 | 784 |             INSIDE, INSIDE_QUOTED :
 | 
|---|
 | 785 |             begin
 | 
|---|
 | 786 |               tmpPart := tmpPart + tmpCurrentChar;
 | 
|---|
 | 787 |             end;
 | 
|---|
 | 788 | 
 | 
|---|
 | 789 |             START_QUOTE :
 | 
|---|
 | 790 |             begin
 | 
|---|
 | 791 |               tmpPart := tmpPart + tmpCurrentChar;
 | 
|---|
 | 792 |               tmpState := INSIDE_QUOTED;
 | 
|---|
 | 793 |             end;
 | 
|---|
 | 794 | 
 | 
|---|
 | 795 |             INSIDE_QUOTED_START_QUOTE :
 | 
|---|
 | 796 |             begin
 | 
|---|
 | 797 |               aResult.add(tmpPart);
 | 
|---|
 | 798 |               tmpPart := tmpCurrentChar;
 | 
|---|
 | 799 |               tmpState := INSIDE;
 | 
|---|
 | 800 |             end;
 | 
|---|
 | 801 |           end;
 | 
|---|
 | 802 |         end;
 | 
|---|
 | 803 | 
 | 
|---|
 | 804 |       end;
 | 
|---|
 | 805 |     end;
 | 
|---|
 | 806 | 
 | 
|---|
 | 807 |     Case tmpState of
 | 
|---|
 | 808 |       WHITESPACE, START_QUOTE : {nothing to do};
 | 
|---|
 | 809 | 
 | 
|---|
 | 810 |       INSIDE, INSIDE_QUOTED, INSIDE_QUOTED_START_QUOTE :
 | 
|---|
 | 811 |       begin
 | 
|---|
 | 812 |         aResult.add(tmpPart);
 | 
|---|
 | 813 |       end;
 | 
|---|
 | 814 |     end;
 | 
|---|
 | 815 |   end;
 | 
|---|
| [110] | 816 | 
 | 
|---|
 | 817 | 
 | 
|---|
 | 818 |   Function CaseInsensitivePos(const aPart: String; const aString: String) : longint;
 | 
|---|
 | 819 |   Var
 | 
|---|
 | 820 |     EndOfPart: longword;
 | 
|---|
 | 821 |   Begin
 | 
|---|
 | 822 |     // Result := Pos(UpperCase(aPart), Uppercase(aString));
 | 
|---|
 | 823 | 
 | 
|---|
 | 824 |     // Aarons assembler version :-)
 | 
|---|
 | 825 |     Asm
 | 
|---|
 | 826 |     //Locals:
 | 
|---|
 | 827 |     //a at [EBP+12]
 | 
|---|
 | 828 |     //b at [EBP+8]
 | 
|---|
 | 829 | 
 | 
|---|
 | 830 |     // First get and check lengths
 | 
|---|
 | 831 |     MOV   ESI, aPart     // get address of aPart into ESI
 | 
|---|
 | 832 |     MOV   CL,  [ESI]     // get length of aPart
 | 
|---|
 | 833 |     CMP   CL, 0          // if aPart is empty then return null to simulate the behavior of POS
 | 
|---|
 | 834 |     JE    !CIP_NoMatch
 | 
|---|
 | 835 | 
 | 
|---|
 | 836 |     MOV   EDI, aString   // get address of aString into EDI
 | 
|---|
 | 837 |     MOV   DL,  [EDI]     // get length of aString
 | 
|---|
 | 838 |     CMP   CL,  DL
 | 
|---|
 | 839 |     JBE   !CIP_PartFitsInString
 | 
|---|
 | 840 | 
 | 
|---|
 | 841 |     // aParta longer than aString so aPart can't be in aString
 | 
|---|
 | 842 | 
 | 
|---|
 | 843 |     !CIP_NoMatch:
 | 
|---|
 | 844 |       MOV   EAX, 0
 | 
|---|
 | 845 |       LEAVE
 | 
|---|
 | 846 |       RETN32 8
 | 
|---|
 | 847 | 
 | 
|---|
 | 848 |     !CIP_PartFitsInString:
 | 
|---|
 | 849 |       INC   ESI            // skip length byte in aPart
 | 
|---|
 | 850 |       INC   EDI            // skip length byte of aString
 | 
|---|
 | 851 | 
 | 
|---|
 | 852 |     // get ending address of b into EDX
 | 
|---|
 | 853 |       MOVZX EDX, DL        // widen DL
 | 
|---|
 | 854 |       ADD   EDX, EDI       // add start of aString
 | 
|---|
 | 855 | 
 | 
|---|
 | 856 |     // get ending address of a into EndOfA
 | 
|---|
 | 857 |       MOVZX ECX, CL        // widen CL
 | 
|---|
 | 858 |       ADD   ECX, ESI       // add start of aPart
 | 
|---|
 | 859 |       MOV   EndOfPart, ECX    // store to EndOfPart
 | 
|---|
 | 860 | 
 | 
|---|
 | 861 |       MOV   ECX, EDI       // set start of current match to start of b
 | 
|---|
 | 862 | 
 | 
|---|
 | 863 |       // ESI: current search point in a
 | 
|---|
 | 864 |       // EDI: current search point in b
 | 
|---|
 | 865 |       // EDX: end of b
 | 
|---|
 | 866 |       // ECX: start of current match
 | 
|---|
 | 867 |       // available: eax, ebx
 | 
|---|
 | 868 | 
 | 
|---|
 | 869 |       JMP   !CIP_Loop
 | 
|---|
 | 870 | 
 | 
|---|
 | 871 |     !CIP_LoopStart:
 | 
|---|
 | 872 |       CMP   EDI, EDX
 | 
|---|
 | 873 |       JE    !CIP_NoMatch   // run out of b
 | 
|---|
 | 874 | 
 | 
|---|
 | 875 |       MOV   AL,  [ESI]     // get next char of a
 | 
|---|
 | 876 |       INC   ESI            // next in a
 | 
|---|
 | 877 | 
 | 
|---|
 | 878 |       MOV   BL,  [EDI]     // get next char of b
 | 
|---|
 | 879 |       INC   EDI            // next in b
 | 
|---|
 | 880 | 
 | 
|---|
 | 881 |     // Convert chars to uppercase
 | 
|---|
 | 882 |       CMP   AL,  97
 | 
|---|
 | 883 |       JB    !CIP_Upcase1
 | 
|---|
 | 884 |       CMP   AL,  122
 | 
|---|
 | 885 |       JA    !CIP_Upcase1
 | 
|---|
 | 886 |       SUB   AL,  32         // convert lower to upper
 | 
|---|
 | 887 |     !CIP_Upcase1:
 | 
|---|
 | 888 | 
 | 
|---|
 | 889 |       CMP   BL,97
 | 
|---|
 | 890 |       JB    !CIP_Upcase2
 | 
|---|
 | 891 |       CMP   BL,122
 | 
|---|
 | 892 |       JA    !CIP_Upcase2
 | 
|---|
 | 893 |       SUB   BL,32          // convert lower to upper
 | 
|---|
 | 894 |     !CIP_Upcase2:
 | 
|---|
 | 895 | 
 | 
|---|
 | 896 |     // Compare uppercased chars
 | 
|---|
 | 897 |       CMP   AL,BL
 | 
|---|
 | 898 |       JE    !CIP_Loop
 | 
|---|
 | 899 | 
 | 
|---|
 | 900 |     // different.
 | 
|---|
 | 901 | 
 | 
|---|
 | 902 |     // Back to start of match + 1
 | 
|---|
 | 903 |       INC   ECX            // inc start of match
 | 
|---|
 | 904 |       MOV   EDI, ECX       // back to start of match in b
 | 
|---|
 | 905 |       MOV   ESI, aPart     // back to start of aPart
 | 
|---|
 | 906 |       INC   ESI            // skip length
 | 
|---|
 | 907 |       JMP   !CIP_LoopStart
 | 
|---|
 | 908 | 
 | 
|---|
 | 909 |     !CIP_Loop:
 | 
|---|
 | 910 | 
 | 
|---|
 | 911 |     // same
 | 
|---|
 | 912 |       CMP   ESI, EndOfPart    // have we reached the end of a
 | 
|---|
 | 913 |       JB    !CIP_LoopStart
 | 
|---|
 | 914 | 
 | 
|---|
 | 915 |       // Match, return position
 | 
|---|
 | 916 |       SUB   ECX, [EBP+8]   // position = ( start of match ) - ( start of b ) + 1
 | 
|---|
 | 917 |       MOV   EAX, ECX
 | 
|---|
 | 918 |       LEAVE
 | 
|---|
 | 919 |       RETN32 8
 | 
|---|
 | 920 |     end;
 | 
|---|
 | 921 |   end;
 | 
|---|
 | 922 | 
 | 
|---|
 | 923 | 
 | 
|---|
| [139] | 924 |   Function LastPosOfChar(const aChar: char; const aString: String): longint;
 | 
|---|
 | 925 |   Var
 | 
|---|
 | 926 |     tmpPos : longint;
 | 
|---|
 | 927 |   begin
 | 
|---|
 | 928 |     tmpPos := Length(aString);
 | 
|---|
 | 929 |     while tmpPos > 0 do
 | 
|---|
 | 930 |     begin
 | 
|---|
 | 931 |       if aString[tmpPos] = aChar then
 | 
|---|
 | 932 |       begin
 | 
|---|
 | 933 |         Result := tmpPos;
 | 
|---|
 | 934 |         exit;
 | 
|---|
 | 935 |       end;
 | 
|---|
 | 936 |       dec(tmpPos);
 | 
|---|
 | 937 |     end;
 | 
|---|
 | 938 |     Result := 0;
 | 
|---|
 | 939 |   end;
 | 
|---|
 | 940 | 
 | 
|---|
| [110] | 941 |   // --------------------
 | 
|---|
 | 942 |   // ---- AnsiString ----
 | 
|---|
 | 943 |   // --------------------
 | 
|---|
 | 944 | 
 | 
|---|
 | 945 | 
 | 
|---|
 | 946 |   Function AnsiStrTrimLeftChars(const aReceiver: AnsiString; const aSetOfChars: TSetOfChars): AnsiString;
 | 
|---|
 | 947 |   Var
 | 
|---|
 | 948 |     tmpLength : integer;
 | 
|---|
 | 949 |     i : integer;
 | 
|---|
 | 950 |   Begin
 | 
|---|
 | 951 |     tmpLength := Length(aReceiver);
 | 
|---|
 | 952 | 
 | 
|---|
 | 953 |     if 1 > tmpLength then
 | 
|---|
 | 954 |     begin
 | 
|---|
 | 955 |       result := aReceiver;
 | 
|---|
 | 956 |       exit;
 | 
|---|
 | 957 |     end;
 | 
|---|
 | 958 | 
 | 
|---|
 | 959 |     i := 1;
 | 
|---|
 | 960 |     // mem optimization
 | 
|---|
 | 961 |     if aReceiver[i] in aSetOfChars then
 | 
|---|
 | 962 |     begin
 | 
|---|
 | 963 |       while i <= tmpLength do
 | 
|---|
 | 964 |       begin
 | 
|---|
 | 965 |         if aReceiver[i] in aSetOfChars then
 | 
|---|
 | 966 |           inc(i)
 | 
|---|
 | 967 |         else
 | 
|---|
 | 968 |           break;
 | 
|---|
 | 969 |       end;
 | 
|---|
 | 970 |       result := AnsiCopy(aReceiver, i, Length(aReceiver)-i+1);
 | 
|---|
 | 971 |     end
 | 
|---|
 | 972 |     else
 | 
|---|
 | 973 |     begin
 | 
|---|
 | 974 |       result := aReceiver;
 | 
|---|
 | 975 |     end;
 | 
|---|
 | 976 |   end;
 | 
|---|
 | 977 | 
 | 
|---|
 | 978 | 
 | 
|---|
 | 979 |   Function AnsiStrTrimRightChars(const aReceiver: AnsiString; const aSetOfChars: TSetOfChars): AnsiString;
 | 
|---|
 | 980 |   Var
 | 
|---|
 | 981 |     i : integer;
 | 
|---|
 | 982 |   Begin
 | 
|---|
 | 983 |     i := Length(aReceiver);
 | 
|---|
 | 984 | 
 | 
|---|
 | 985 |     if 1 > i then
 | 
|---|
 | 986 |     begin
 | 
|---|
 | 987 |       result := aReceiver;
 | 
|---|
 | 988 |       exit;
 | 
|---|
 | 989 |     end;
 | 
|---|
 | 990 | 
 | 
|---|
 | 991 |     // mem optimization
 | 
|---|
 | 992 |     if aReceiver[i] in aSetOfChars then
 | 
|---|
 | 993 |     begin
 | 
|---|
 | 994 |       while i > 0 do
 | 
|---|
 | 995 |       begin
 | 
|---|
 | 996 |         if aReceiver[i] in aSetOfChars then
 | 
|---|
 | 997 |           dec(i)
 | 
|---|
 | 998 |         else
 | 
|---|
 | 999 |           break;
 | 
|---|
 | 1000 |       end;
 | 
|---|
 | 1001 |       result := AnsiCopy(aReceiver, 1, i);
 | 
|---|
 | 1002 |     end
 | 
|---|
 | 1003 |     else
 | 
|---|
 | 1004 |     begin
 | 
|---|
 | 1005 |       result := aReceiver;
 | 
|---|
 | 1006 |     end;
 | 
|---|
 | 1007 |   end;
 | 
|---|
 | 1008 | 
 | 
|---|
 | 1009 | 
 | 
|---|
 | 1010 |   Function AnsiStrTrimChars(const aReceiver: AnsiString; const aSetOfChars: TSetOfChars): AnsiString;
 | 
|---|
 | 1011 |   Var
 | 
|---|
 | 1012 |     i,j : integer;
 | 
|---|
 | 1013 |     tmpNeedCopy : boolean;
 | 
|---|
 | 1014 |   Begin
 | 
|---|
 | 1015 |     tmpNeedCopy := false;
 | 
|---|
 | 1016 | 
 | 
|---|
 | 1017 |     j := Length(aReceiver);
 | 
|---|
 | 1018 | 
 | 
|---|
 | 1019 |     if 1 > j then
 | 
|---|
 | 1020 |     begin
 | 
|---|
 | 1021 |       result := aReceiver;
 | 
|---|
 | 1022 |       exit;
 | 
|---|
 | 1023 |     end;
 | 
|---|
 | 1024 | 
 | 
|---|
 | 1025 |     i := 1;
 | 
|---|
 | 1026 |     while i < j do
 | 
|---|
 | 1027 |     begin
 | 
|---|
 | 1028 |       if aReceiver[i] in aSetOfChars then
 | 
|---|
 | 1029 |       begin
 | 
|---|
 | 1030 |         inc(i);
 | 
|---|
 | 1031 |         tmpNeedCopy := true;
 | 
|---|
 | 1032 |       end
 | 
|---|
 | 1033 |       else
 | 
|---|
 | 1034 |       begin
 | 
|---|
 | 1035 |         break;
 | 
|---|
 | 1036 |       end;
 | 
|---|
 | 1037 |     end;
 | 
|---|
 | 1038 | 
 | 
|---|
 | 1039 |     while j >= i do
 | 
|---|
 | 1040 |     begin
 | 
|---|
 | 1041 |       if aReceiver[j] in aSetOfChars then
 | 
|---|
 | 1042 |       begin
 | 
|---|
 | 1043 |         dec(j);
 | 
|---|
 | 1044 |         tmpNeedCopy := true;
 | 
|---|
 | 1045 |       end
 | 
|---|
 | 1046 |       else
 | 
|---|
 | 1047 |       begin
 | 
|---|
 | 1048 |         break;
 | 
|---|
 | 1049 |       end;
 | 
|---|
 | 1050 |     end;
 | 
|---|
 | 1051 | 
 | 
|---|
 | 1052 |     if tmpNeedCopy then
 | 
|---|
 | 1053 |     begin
 | 
|---|
 | 1054 |       result := AnsiCopy(aReceiver, i, j-i+1);
 | 
|---|
 | 1055 |     end
 | 
|---|
 | 1056 |     else
 | 
|---|
 | 1057 |     begin
 | 
|---|
 | 1058 |       result := aReceiver;
 | 
|---|
 | 1059 |     end;
 | 
|---|
 | 1060 |   end;
 | 
|---|
 | 1061 | 
 | 
|---|
 | 1062 | 
 | 
|---|
 | 1063 |   Function AnsiStrTrim(const aReceiver: AnsiString): AnsiString;
 | 
|---|
 | 1064 |   Begin
 | 
|---|
 | 1065 |     result := AnsiStrTrimChars(aReceiver, [' ']);
 | 
|---|
 | 1066 |   end;
 | 
|---|
 | 1067 | 
 | 
|---|
 | 1068 | 
 | 
|---|
| [139] | 1069 |   // --------------------
 | 
|---|
 | 1070 |   // ---- Misc TODO  ----
 | 
|---|
 | 1071 |   // --------------------
 | 
|---|
 | 1072 | 
 | 
|---|
 | 1073 |   Procedure GetMemString(const aPointer : pointer; var aString: string; const aSize: byte);
 | 
|---|
 | 1074 |   begin
 | 
|---|
 | 1075 |     aString[0] := char(aSize);
 | 
|---|
 | 1076 |     MemCopy(aPointer, Addr(aString[1]), aSize);
 | 
|---|
 | 1077 |   end;
 | 
|---|
 | 1078 | 
 | 
|---|
 | 1079 | 
 | 
|---|
 | 1080 |   Procedure FreePString(var aPString : PString );
 | 
|---|
 | 1081 |   begin
 | 
|---|
 | 1082 |     if aPString = nil then
 | 
|---|
 | 1083 |     begin
 | 
|---|
 | 1084 |       exit;
 | 
|---|
 | 1085 |     end;
 | 
|---|
 | 1086 | 
 | 
|---|
 | 1087 |     FreeMem(aPString, Length(aPString^) + 1);
 | 
|---|
 | 1088 |     aPString := nil;
 | 
|---|
 | 1089 |   end;
 | 
|---|
 | 1090 | 
 | 
|---|
 | 1091 | 
 | 
|---|
 | 1092 |   Function NewPString(const aString : String) : PString;
 | 
|---|
 | 1093 |   begin
 | 
|---|
 | 1094 |     GetMem(Result, Length(aString) + 1);
 | 
|---|
 | 1095 |     Result^ := aString;
 | 
|---|
 | 1096 |   end;
 | 
|---|
 | 1097 | 
 | 
|---|
| [35] | 1098 | END.
 | 
|---|