source: branches/2.19_branch/NewView/StringUtilsUnit.pas@ 324

Last change on this file since 324 was 139, checked in by RBRi, 18 years ago

more refactoring

  • Property svn:eol-style set to native
File size: 26.0 KB
Line 
1Unit StringUtilsUnit;
2
3// NewView - a new OS/2 Help Viewer
4// Copyright 2006-2007 Ronald Brill (rbri at rbri dot de)
5// This software is released under the GNU Public License - see readme.txt
6
7// Helper functions to work with String and AnsiString
8
9Interface
10
11uses
12 Classes,
13 CharUtilsUnit;
14
15const
16 StrTAB = CharTAB;
17 StrCR = CharCR;
18 StrLF = CharLF;
19 StrCRLF = StrCR + StrLF;
20 StrSingleQuote = CharSingleQuote;
21 StrDoubleQuote = CharDoubleQuote;
22
23
24 TYPE
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
39 // prefixes all occurences of one of the chars in aStringWithChars with anEscape char
40 // if the escapeChar itself is found, then it is doubled
41 Function StrEscapeAllCharsBy(const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char): String;
42
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:
46 // StrExtractStrings('1x2x3\x4', 'x', '\') ->
47 // returns 4 strings: '1', '', '2' and '3x4'
48 Procedure StrExtractStrings(var aResult : TStrings; const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char);
49
50 // same as StrExtractStrings but ignores empty strings
51 Procedure StrExtractStringsIgnoreEmpty(var aResult : TStrings; const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char);
52
53 // removes all occurences of char from aSetOfChars from the beginning
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
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
68 // Returns the aCount leftmost chars of aString
69 Function StrLeft(const aString : String; const aCount : Integer) : String;
70
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
77 // Returns a copy of the string starting at aPos
78 Function StrSubstringFrom(const aReceiver: String; const aPos : Integer) : String;
79
80 // returns true if the String starts with the provided one
81 // this is case SENSITIVE
82 Function StrStartsWith(const aReceiver: String; const aStartString: String): Boolean;
83
84 // returns true if the String starts with the provided one
85 // this is case INsensitive
86 Function StrStartsWithIgnoringCase(const aReceiver: String; const aStartString: String): Boolean;
87
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
92 // returns true if the String ends with the provided one
93 // this is case INsensitive
94 Function StrEndsWithIgnoringCase(const aReceiver: String; const anEndString: String): Boolean;
95
96 // Returns true if aReceiver is only spaces (or empty)
97 Function StrIsEmptyOrSpaces(const aReceiver: String) : Boolean;
98
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
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
108 Function BoolToStr(const aBoolean : boolean ): string;
109
110 // Returns aString enclosed in single quotes
111 Function StrInSingleQuotes(const aString : String) : String;
112
113 // Returns aString enclosed in double quotes
114 Function StrInDoubleQuotes(const aString : String) : String;
115
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 );
119
120
121 // returns the position of aPart in aString
122 // case insensitive
123 Function CaseInsensitivePos(const aPart: String; const aString: String ): longint;
124
125 // Finds the last position of aChar within aString. Returns zero if no match
126 Function LastPosOfChar(const aChar: char; const aString: String): longint;
127
128
129 // --------------------
130 // ---- AnsiString ----
131 // --------------------
132
133
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
150 // --------------------
151 // ---- Misc TODO ----
152 // --------------------
153
154 Procedure GetMemString(const aPointer : pointer; var aString: string; const aSize: byte);
155
156 Procedure FreePString(var aPString: PString );
157
158 Function NewPString(const aString : String) : PString;
159
160
161Implementation
162
163 uses
164 SysUtils,
165 DebugUnit,
166 ACLUtility; // TODO
167
168 constructor TSerializableStringList.Create;
169 begin
170 LogEvent(LogObjConstDest, 'TSerializableStringList createdestroy');
171
172 inherited Create;
173 stringList := TStringList.Create;
174 end;
175
176
177 destructor TSerializableStringList.Destroy;
178 begin
179 LogEvent(LogObjConstDest, 'TSerializableStringList destroy');
180 if Nil <> stringList then stringList.Destroy;
181
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 := '';
207 for i := 0 to stringList.count-1 do
208 begin
209 if (i > 0) then result := result + '&';
210 result := result + StrEscapeAllCharsBy(stringList[i], ['&'], '\');
211 end;
212 end;
213
214
215 PROCEDURE TSerializableStringList.readValuesFromSerializedString(const aSerializedString : String);
216 Begin
217 if (length(aSerializedString) < 1) then exit;
218
219 LogEvent(LogObjConstDest, 'readValuesFromSerializedString');
220 stringList.Destroy;
221 LogEvent(LogObjConstDest, 'readValuesFromSerializedString destroy done');
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;
231 Var
232 i : Integer;
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
249 Procedure PrivateStrExtractStrings( Var aResult: TStrings;
250 const aReceiver: String;
251 const aSetOfChars: TSetOfChars;
252 const anEscapeChar: char;
253 const anIgnoreEmptyFlag : boolean);
254 Var
255 i : Integer;
256 tmpChar,tmpNextChar : Char;
257 tmpPart: String;
258 Begin
259 if (length(aReceiver) < 1) then exit;
260
261 tmpPart := '';
262
263 i := 1;
264 while i <= length(aReceiver) do
265 begin
266 tmpChar := aReceiver[i];
267 if i < length(aReceiver) then
268 tmpNextChar := aReceiver[i+1]
269 else
270 tmpNextChar := #0;
271
272 if (tmpChar = anEscapeChar) and (tmpNextChar = anEscapeChar) then
273 begin
274 tmpPart := tmpPart + anEscapeChar;
275 i := i + 2;
276 end
277 else
278 if (tmpChar = anEscapeChar) and (tmpNextChar IN aSetOfChars) then
279 begin
280 tmpPart := tmpPart + tmpNextChar;
281 i := i + 2;
282 end
283 else
284 if (tmpChar IN aSetOfChars) then
285 begin
286 if (NOT anIgnoreEmptyFlag) OR ('' <> tmpPart) then
287 begin
288 aResult.add(tmpPart);
289 end;
290 tmpPart := '';
291 i := i + 1;
292 end
293 else
294 begin
295 tmpPart := tmpPart + tmpChar;
296 i := i + 1;
297 end;
298 end;
299
300 if (NOT anIgnoreEmptyFlag) OR ('' <> tmpPart) then
301 begin
302 aResult.add(tmpPart);
303 end;
304 end;
305
306
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
321 tmpLength : integer;
322 i : integer;
323 Begin
324 tmpLength := Length(aReceiver);
325
326 if 1 > tmpLength then
327 begin
328 result := aReceiver;
329 exit;
330 end;
331
332 i := 1;
333 // mem optimization
334 if aReceiver[i] in aSetOfChars then
335 begin
336 while i <= tmpLength do
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
354 i : integer;
355 Begin
356 i := Length(aReceiver);
357
358 if 1 > i then
359 begin
360 result := aReceiver;
361 exit;
362 end;
363
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
383 Function StrTrimChars(const aReceiver: String; const aSetOfChars: TSetOfChars): String;
384 Var
385 i,j : integer;
386 tmpNeedCopy : boolean;
387 Begin
388 j := Length(aReceiver);
389
390 if 1 > j then
391 begin
392 result := aReceiver;
393 exit;
394 end;
395
396 tmpNeedCopy := false;
397 i := 1;
398 while i < j do
399 begin
400 if aReceiver[i] in aSetOfChars then
401 begin
402 inc(i);
403 tmpNeedCopy := true;
404 end
405 else
406 begin
407 break;
408 end;
409 end;
410
411 while j >= i do
412 begin
413 if aReceiver[j] in aSetOfChars then
414 begin
415 dec(j);
416 tmpNeedCopy := true;
417 end
418 else
419 begin
420 break;
421 end;
422 end;
423
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;
432 end;
433
434
435 Function StrTrim(const aReceiver: String): String;
436 Begin
437 result := StrTrimChars(aReceiver, [' ']);
438 end;
439
440
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
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
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
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
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
548 begin
549 result := false;
550 exit;
551 end;
552 dec(tmpMatchPos);
553 dec(tmpStringPos);
554 end;
555
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
565 tmpStringPos := length(aReceiver);
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
576 if upcase(aReceiver[tmpStringPos]) <> upcase(anEndString[tmpMatchPos]) then
577 begin
578 result := false;
579 exit;
580 end;
581 dec(tmpMatchPos);
582 dec(tmpStringPos);
583 end;
584
585 result := true;
586 end;
587
588
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
620 Function StrEqualIgnoringCase(const aReceiver: String; const aSecondString: String): Boolean;
621 begin
622 Result := CompareText(aReceiver, aSecondString) = 0;
623 end;
624
625
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
661 Function BoolToStr(const aBoolean : boolean ): string;
662 begin
663 if aBoolean then
664 Result := 'True'
665 else
666 Result := 'False';
667 end;
668
669
670 Function StrInSingleQuotes(const aString : String) : String;
671 begin
672 Result := StrSingleQuote + aString + StrSingleQuote;
673 end;
674
675
676 Function StrInDoubleQuotes(const aString : String) : String;
677 begin
678 Result := StrDoubleQuote + aString + StrDoubleQuote;
679 end;
680
681
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;
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
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
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
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
1098END.
Note: See TracBrowser for help on using the repository browser.